Armin Ronacher | de478f6 | 2007-02-28 22:35:04 +0100 | [diff] [blame^] | 1 | # Template language benchmarks |
| 2 | # |
| 3 | # Objective: Generate a 1000x10 HTML table as fast as possible. |
| 4 | # adapted for jinja 1 |
| 5 | # |
| 6 | # Author: Jonas Borgström <jonas@edgewall.com> |
| 7 | # Author: Armin Ronacher <armin.ronacher@active-4.com> |
| 8 | |
| 9 | import cgi |
| 10 | import sys |
| 11 | import timeit |
| 12 | from StringIO import StringIO |
| 13 | |
| 14 | from genshi.builder import tag |
| 15 | from genshi.template import MarkupTemplate |
| 16 | |
| 17 | from jinja import Environment |
| 18 | |
| 19 | from django.conf import settings |
| 20 | settings.configure() |
| 21 | from django.template import Context as DjangoContext |
| 22 | from django.template import Template as DjangoTemplate |
| 23 | |
| 24 | from Cheetah.Template import Template as CheetahTemplate |
| 25 | |
| 26 | from mako.template import Template as MakoTemplate |
| 27 | |
| 28 | table = [dict(a='1',b='2',c='3',d='4',e='5',f='6',g='7',h='8',i='9',j='10') |
| 29 | for x in range(1000)] |
| 30 | |
| 31 | genshi_tmpl = MarkupTemplate(""" |
| 32 | <table xmlns:py="http://genshi.edgewall.org/"> |
| 33 | <tr py:for="row in table"> |
| 34 | <td py:for="c in row.values()" py:content="c"/> |
| 35 | </tr> |
| 36 | </table> |
| 37 | """) |
| 38 | |
| 39 | django_tmpl = DjangoTemplate(""" |
| 40 | <table> |
| 41 | {% for row in table %} |
| 42 | <tr>{% for col in row.values %}{{ col|escape }}{% endfor %}</tr> |
| 43 | {% endfor %} |
| 44 | </table> |
| 45 | """) |
| 46 | |
| 47 | jinja_tmpl = Environment().from_string(''' |
| 48 | <table> |
| 49 | {% for row in table %} |
| 50 | <tr>{% for col in row.values() %}{{ col|escape }}{% endfor %}</tr> |
| 51 | {% endfor %} |
| 52 | </table> |
| 53 | ''') |
| 54 | |
| 55 | cheetah_tmpl = CheetahTemplate(''' |
| 56 | # filter escape |
| 57 | <table> |
| 58 | #for $row in $table |
| 59 | <tr> |
| 60 | #for $col in $row.values() |
| 61 | $col |
| 62 | #end for |
| 63 | </tr> |
| 64 | #end for |
| 65 | </table> |
| 66 | ''', searchList=[{'table': table, 'escape': cgi.escape}]) |
| 67 | |
| 68 | mako_tmpl = MakoTemplate(''' |
| 69 | <table> |
| 70 | % for row in table: |
| 71 | <tr> |
| 72 | % for col in row.values(): |
| 73 | ${col|h} |
| 74 | % endfor |
| 75 | </tr> |
| 76 | % endfor |
| 77 | </table> |
| 78 | ''') |
| 79 | |
| 80 | def test_django(): |
| 81 | """Django Templates""" |
| 82 | context = DjangoContext({'table': table}) |
| 83 | django_tmpl.render(context) |
| 84 | |
| 85 | def test_jinja(): |
| 86 | """Jinja Templates""" |
| 87 | jinja_tmpl.render(table=table) |
| 88 | |
| 89 | def test_genshi(): |
| 90 | """Genshi Templates""" |
| 91 | stream = genshi_tmpl.generate(table=table) |
| 92 | stream.render('html', strip_whitespace=False) |
| 93 | |
| 94 | def test_cheetah(): |
| 95 | """Cheetah Templates""" |
| 96 | cheetah_tmpl.respond() |
| 97 | |
| 98 | def test_mako(): |
| 99 | """Mako Templates""" |
| 100 | mako_tmpl.render(table=table) |
| 101 | |
| 102 | |
| 103 | def run(which=None, number=10): |
| 104 | tests = ['test_django', 'test_jinja', 'test_genshi', 'test_cheetah', 'test_mako'] |
| 105 | |
| 106 | if which: |
| 107 | tests = filter(lambda n: n[5:] in which, tests) |
| 108 | |
| 109 | for test in [t for t in tests if hasattr(sys.modules[__name__], t)]: |
| 110 | t = timeit.Timer(setup='from __main__ import %s;' % test, |
| 111 | stmt='%s()' % test) |
| 112 | time = t.timeit(number=number) / number |
| 113 | |
| 114 | if time < 0.00001: |
| 115 | result = ' (not installed?)' |
| 116 | else: |
| 117 | result = '%16.2f ms' % (1000 * time) |
| 118 | print '%-35s %s' % (getattr(sys.modules[__name__], test).__doc__, result) |
| 119 | |
| 120 | |
| 121 | if __name__ == '__main__': |
| 122 | which = [arg for arg in sys.argv[1:] if arg[0] != '-'] |
| 123 | |
| 124 | if '-p' in sys.argv: |
| 125 | import hotshot, hotshot.stats |
| 126 | prof = hotshot.Profile("template.prof") |
| 127 | benchtime = prof.runcall(run, which, number=1) |
| 128 | stats = hotshot.stats.load("template.prof") |
| 129 | stats.strip_dirs() |
| 130 | stats.sort_stats('time', 'calls') |
| 131 | stats.print_stats() |
| 132 | else: |
| 133 | run(which) |