From c2bc80fcf24d8102d6230aa478380402bd166b41 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 25 Feb 2012 12:06:40 +0000 Subject: [PATCH] Added timings --- pep-XXXX.rst | 34 +++++++++++++++++++++ timing.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 timing.py diff --git a/pep-XXXX.rst b/pep-XXXX.rst index a366458..9a0f49a 100644 --- a/pep-XXXX.rst +++ b/pep-XXXX.rst @@ -197,6 +197,40 @@ reintroducing redundant syntax. On the other hand, Python already has multiple literals for strings with mostly the same behavior (single 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 ========== diff --git a/timing.py b/timing.py new file mode 100644 index 0000000..7190583 --- /dev/null +++ b/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()