Skip to content

Commit

Permalink
Added timings
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Feb 25, 2012
1 parent ed3d936 commit c2bc80f
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 0 deletions.
34 changes: 34 additions & 0 deletions pep-XXXX.rst
Expand Up @@ -197,6 +197,40 @@ reintroducing redundant syntax. On the other hand, Python already has
multiple literals for strings with mostly the same behavior (single multiple literals for strings with mostly the same behavior (single
quoted, double quoted, single triple quoted, double triple quoted). quoted, double quoted, single triple quoted, double triple quoted).


Runtime Overhead of Wrappers
============================

I did some basic timings on the performance of a ``u()`` wrapper function
as used by the `six` library. The implementation of ``u()`` is as
follows::

if sys.version_info >= (3, 0):
def u(value):
return value
else:
def u(value):
return unicode(value, 'unicode-escape')

The intention is that ``u'foo'`` can be turned to ``u('foo')`` and that on
Python 2.x an implicit decoding happens. In this case the wrapper will
have a decoding overhead for Python 2.x. I did some basic timings to see
how bad the performance loss would be. The following examples measure the
execution time over 10000 iterations::

u'\N{SNOWMAN}barbaz' 1000 loops, best of 3: 295 usec per loop
u('\N{SNOWMAN}barbaz') 10 loops, best of 3: 18.5 msec per loop
u'foobarbaz_%d' % x 100 loops, best of 3: 8.32 msec per loop
u('foobarbaz_%d') % x 10 loops, best of 3: 25.6 msec per loop
u'fööbarbaz' 1000 loops, best of 3: 289 usec per loop
u('fööbarbaz') 100 loops, best of 3: 15.1 msec per loop
u'foobarbaz' 1000 loops, best of 3: 294 usec per loop
u('foobarbaz') 100 loops, best of 3: 14.3 msec per loop

The overhead of the wrapper function in Python 3 is the price of a
function call since the function only has to return the argument
unchanged.


References References
========== ==========


Expand Down
86 changes: 86 additions & 0 deletions timing.py
@@ -0,0 +1,86 @@
# coding: utf-8
import sys
from subprocess import Popen


ITERATIONS = 10000


def u(value):
return unicode(value, 'unicode-escape')


def bench_format_literal():
"""u'foobarbaz_%d' % x"""
for x in xrange(ITERATIONS):
y = u'foobarbaz_%d' % x


def bench_format_wrapped():
"""u('foobarbaz_%d') % x"""
for x in xrange(ITERATIONS):
y = u('foobarbaz_%d') % x


def bench_simple_literal():
"""u'foobarbaz'"""
for x in xrange(ITERATIONS):
y = u'foobarbaz'


def bench_simple_wrapped():
"""u('foobarbaz')"""
for x in xrange(ITERATIONS):
y = u('foobarbaz')


def bench_non_ascii_literal():
"""u'fööbarbaz'"""
for x in xrange(ITERATIONS):
y = u'fööbarbaz'


def bench_non_ascii_wrapped():
"""u('fööbarbaz')"""
for x in xrange(ITERATIONS):
y = u('fööbarbaz')


def bench_escaped_literal():
"""u'\N{SNOWMAN}barbaz'"""
for x in xrange(ITERATIONS):
y = u'\N{SNOWMAN}barbaz'


def bench_escaped_wrapped():
"""u('\N{SNOWMAN}barbaz')"""
for x in xrange(ITERATIONS):
y = u('\N{SNOWMAN}barbaz')


def list_benchmarks():
for name in sorted(globals().keys()):
if name.startswith('bench_'):
yield name[6:]


def run_bench(name):
text = globals()['bench_' + name].__doc__.strip().decode('utf-8')
sys.stdout.write((u'%-32s' % text).encode('utf-8'))
sys.stdout.flush()
Popen([sys.executable, '-mtimeit', '-s',
'from timing import bench_%s as run' % name,
'run()']).wait()


def main():
print '=' * 80
print 'Running benchmarks'
print '-' * 80
for bench in list_benchmarks():
run_bench(bench)
print '-' * 80


if __name__ == '__main__':
main()

0 comments on commit c2bc80f

Please sign in to comment.