Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 434 lines (409 sloc) 10.922 kb
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
1 """\
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
2 This benchmark compares some python templating engines with Jinja 2 so
3 that we get a picture of how fast Jinja 2 is for a semi real world
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
4 template. If a template engine is not installed the test is skipped.\
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
5 """
de6bf71 @mitsuhiko some performance improvements
authored
6 import sys
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
7 import cgi
00d5d21 @mitsuhiko some more stuff for jinja2
authored
8 from timeit import Timer
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
9 from jinja2 import Environment as JinjaEnvironment
00d5d21 @mitsuhiko some more stuff for jinja2
authored
10
de6bf71 @mitsuhiko some performance improvements
authored
11 context = {
12 'page_title': 'mitsuhiko\'s benchmark',
13 'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
14 }
00d5d21 @mitsuhiko some more stuff for jinja2
authored
15
16 jinja_template = JinjaEnvironment(
17 line_statement_prefix='%',
18 variable_start_string="${",
19 variable_end_string="}"
20 ).from_string("""\
21 <!doctype html>
22 <html>
23 <head>
de6bf71 @mitsuhiko some performance improvements
authored
24 <title>${page_title|e}</title>
00d5d21 @mitsuhiko some more stuff for jinja2
authored
25 </head>
26 <body>
27 <div class="header">
28 <h1>${page_title|e}</h1>
29 </div>
30 <ul class="navigation">
31 % for href, caption in [
32 ('index.html', 'Index'),
33 ('downloads.html', 'Downloads'),
34 ('products.html', 'Products')
35 ]
36 <li><a href="${href|e}">${caption|e}</a></li>
37 % endfor
38 </ul>
39 <div class="table">
40 <table>
41 % for row in table
42 <tr>
43 % for cell in row
44 <td>${cell}</td>
45 % endfor
46 </tr>
47 % endfor
48 </table>
49 </div>
50 </body>
51 </html>\
52 """)
53
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
54 def test_jinja():
55 jinja_template.render(context)
56
57 try:
b4da9be @mitsuhiko Added tornado templates to benchmark.
authored
58 from tornado.template import Template
59 except ImportError:
60 test_tornado = None
61 else:
62 tornado_template = Template("""\
63 <!doctype html>
64 <html>
65 <head>
66 <title>{{ page_title }}</title>
67 </head>
68 <body>
69 <div class="header">
70 <h1>{{ page_title }}</h1>
71 </div>
72 <ul class="navigation">
73 {% for href, caption in [ \
74 ('index.html', 'Index'), \
75 ('downloads.html', 'Downloads'), \
76 ('products.html', 'Products') \
77 ] %}
78 <li><a href="{{ href }}">{{ caption }}</a></li>
79 {% end %}
80 </ul>
81 <div class="table">
82 <table>
83 {% for row in table %}
84 <tr>
85 {% for cell in row %}
86 <td>{{ cell }}</td>
87 {% end %}
88 </tr>
89 {% end %}
90 </table>
91 </div>
92 </body>
93 </html>\
94 """)
95
96 def test_tornado():
97 tornado_template.generate(**context)
98
99 try:
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
100 from django.conf import settings
101 settings.configure()
102 from django.template import Template as DjangoTemplate, Context as DjangoContext
103 except ImportError:
104 test_django = None
105 else:
f60232d @mitsuhiko Updated examples to use Django cached.
authored
106 django_template = DjangoTemplate("""\
00d5d21 @mitsuhiko some more stuff for jinja2
authored
107 <!doctype html>
108 <html>
109 <head>
de6bf71 @mitsuhiko some performance improvements
authored
110 <title>{{ page_title }}</title>
00d5d21 @mitsuhiko some more stuff for jinja2
authored
111 </head>
112 <body>
113 <div class="header">
114 <h1>{{ page_title }}</h1>
115 </div>
116 <ul class="navigation">
117 {% for href, caption in navigation %}
118 <li><a href="{{ href }}">{{ caption }}</a></li>
119 {% endfor %}
120 </ul>
121 <div class="table">
122 <table>
123 {% for row in table %}
124 <tr>
125 {% for cell in row %}
126 <td>{{ cell }}</td>
127 {% endfor %}
128 </tr>
129 {% endfor %}
130 </table>
131 </div>
132 </body>
133 </html>\
f60232d @mitsuhiko Updated examples to use Django cached.
authored
134 """)
00d5d21 @mitsuhiko some more stuff for jinja2
authored
135
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
136 def test_django():
137 c = DjangoContext(context)
138 c['navigation'] = [('index.html', 'Index'), ('downloads.html', 'Downloads'),
139 ('products.html', 'Products')]
f60232d @mitsuhiko Updated examples to use Django cached.
authored
140 django_template.render(c)
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
141
142 try:
143 from mako.template import Template as MakoTemplate
144 except ImportError:
145 test_mako = None
146 else:
147 mako_template = MakoTemplate("""\
00d5d21 @mitsuhiko some more stuff for jinja2
authored
148 <!doctype html>
149 <html>
150 <head>
de6bf71 @mitsuhiko some performance improvements
authored
151 <title>${page_title|h}</title>
00d5d21 @mitsuhiko some more stuff for jinja2
authored
152 </head>
153 <body>
154 <div class="header">
155 <h1>${page_title|h}</h1>
156 </div>
157 <ul class="navigation">
158 % for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
159 <li><a href="${href|h}">${caption|h}</a></li>
160 % endfor
161 </ul>
162 <div class="table">
163 <table>
164 % for row in table:
165 <tr>
166 % for cell in row:
167 <td>${cell}</td>
168 % endfor
169 </tr>
170 % endfor
171 </table>
172 </div>
173 </body>
174 </html>\
449167d @mitsuhiko fixed a bug in the compiler
authored
175 """)
00d5d21 @mitsuhiko some more stuff for jinja2
authored
176
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
177 def test_mako():
178 mako_template.render(**context)
179
180 try:
181 from genshi.template import MarkupTemplate as GenshiTemplate
182 except ImportError:
183 test_genshi = None
184 else:
185 genshi_template = GenshiTemplate("""\
de6bf71 @mitsuhiko some performance improvements
authored
186 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
187 <head>
188 <title>${page_title}</title>
189 </head>
190 <body>
191 <div class="header">
192 <h1>${page_title}</h1>
193 </div>
194 <ul class="navigation">
195 <li py:for="href, caption in [
196 ('index.html', 'Index'),
197 ('downloads.html', 'Downloads'),
198 ('products.html', 'Products')]"><a href="${href}">${caption}</a></li>
199 </ul>
200 <div class="table">
201 <table>
202 <tr py:for="row in table">
203 <td py:for="cell in row">${cell}</td>
204 </tr>
205 </table>
206 </div>
207 </body>
208 </html>\
209 """)
210
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
211 def test_genshi():
212 genshi_template.generate(**context).render('html', strip_whitespace=False)
213
214 try:
215 from Cheetah.Template import Template as CheetahTemplate
216 except ImportError:
217 test_cheetah = None
218 else:
219 cheetah_template = CheetahTemplate("""\
de6bf71 @mitsuhiko some performance improvements
authored
220 #import cgi
221 <!doctype html>
222 <html>
223 <head>
224 <title>$cgi.escape($page_title)</title>
225 </head>
226 <body>
227 <div class="header">
228 <h1>$cgi.escape($page_title)</h1>
229 </div>
230 <ul class="navigation">
231 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
232 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
233 #end for
234 </ul>
235 <div class="table">
236 <table>
237 #for $row in $table:
238 <tr>
239 #for $cell in $row:
240 <td>$cell</td>
241 #end for
242 </tr>
243 #end for
244 </table>
245 </div>
246 </body>
247 </html>\
248 """, searchList=[dict(context)])
00d5d21 @mitsuhiko some more stuff for jinja2
authored
249
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
250 def test_cheetah():
251 unicode(cheetah_template)
00d5d21 @mitsuhiko some more stuff for jinja2
authored
252
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
253 try:
254 import tenjin
255 except ImportError:
256 test_tenjin = None
257 else:
258 tenjin_template = tenjin.Template()
259 tenjin_template.convert("""\
260 <!doctype html>
261 <html>
262 <head>
263 <title>${page_title}</title>
264 </head>
265 <body>
266 <div class="header">
267 <h1>${page_title}</h1>
268 </div>
269 <ul class="navigation">
270 <?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
271 <li><a href="${href}">${caption}</a></li>
272 <?py #end ?>
273 </ul>
274 <div class="table">
275 <table>
276 <?py for row in table: ?>
277 <tr>
278 <?py for cell in row: ?>
279 <td>#{cell}</td>
280 <?py #end ?>
281 </tr>
282 <?py #end ?>
283 </table>
284 </div>
285 </body>
286 </html>\
287 """)
de6bf71 @mitsuhiko some performance improvements
authored
288
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
289 def test_tenjin():
290 from tenjin.helpers import escape, to_str
291 tenjin_template.render(context, locals())
00d5d21 @mitsuhiko some more stuff for jinja2
authored
292
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
293 try:
294 from spitfire.compiler import util as SpitfireTemplate
295 from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
296 except ImportError:
297 test_spitfire = None
298 else:
299 spitfire_template = SpitfireTemplate.load_template("""\
300 <!doctype html>
301 <html>
302 <head>
303 <title>$cgi.escape($page_title)</title>
304 </head>
305 <body>
306 <div class="header">
307 <h1>$cgi.escape($page_title)</h1>
308 </div>
309 <ul class="navigation">
310 #for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
311 <li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
312 #end for
313 </ul>
314 <div class="table">
315 <table>
316 #for $row in $table
317 <tr>
318 #for $cell in $row
319 <td>$cell</td>
320 #end for
321 </tr>
322 #end for
323 </table>
324 </div>
325 </body>
326 </html>\
327 """, 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
328 spitfire_context = dict(context, **{'cgi': cgi})
329
330 def test_spitfire():
331 spitfire_template(search_list=[spitfire_context]).main()
332
6cc2b23 @moraes Added benchmark for chameleon/chameleon-genshi.
moraes authored
333
334 try:
335 from chameleon.zpt.template import PageTemplate
336 except ImportError:
337 test_chameleon = None
338 else:
339 chameleon_template = PageTemplate("""\
340 <html xmlns:tal="http://xml.zope.org/namespaces/tal">
341 <head>
342 <title tal:content="page_title">Page Title</title>
343 </head>
344 <body>
345 <div class="header">
346 <h1 tal:content="page_title">Page Title</h1>
347 </div>
348 <ul class="navigation">
349 <li tal:repeat="item sections"><a tal:attributes="href item[0]" tal:content="item[1]">caption</a></li>
350 </ul>
351 <div class="table">
352 <table>
353 <tr tal:repeat="row table">
354 <td tal:repeat="cell row" tal:content="row[cell]">cell</td>
355 </tr>
356 </table>
357 </div>
358 </body>
359 </html>\
360 """)
361 chameleon_context = dict(context)
362 chameleon_context['sections'] = [
363 ('index.html', 'Index'),
364 ('downloads.html', 'Downloads'),
365 ('products.html', 'Products')
366 ]
367 def test_chameleon():
368 chameleon_template.render(**chameleon_context)
369
370 try:
371 from chameleon.zpt.template import PageTemplate
372 from chameleon.genshi import language
373 except ImportError:
374 test_chameleon_genshi = None
375 else:
376 chameleon_genshi_template = PageTemplate("""\
377 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
378 <head>
379 <title>${page_title}</title>
380 </head>
381 <body>
382 <div class="header">
383 <h1>${page_title}</h1>
384 </div>
385 <ul class="navigation">
386 <li py:for="info in sections"><a href="${info[0]}">${info[1]}</a></li>
387 </ul>
388 <div class="table">
389 <table>
390 <tr py:for="row in table">
391 <td py:for="cell in row">${row[cell]}</td>
392 </tr>
393 </table>
394 </div>
395 </body>
396 </html>\
397 """, parser=language.Parser())
398 chameleon_genshi_context = dict(context)
399 chameleon_genshi_context['sections'] = [
400 ('index.html', 'Index'),
401 ('downloads.html', 'Downloads'),
402 ('products.html', 'Products')
403 ]
404 def test_chameleon_genshi():
405 chameleon_genshi_template.render(**chameleon_genshi_context)
406
407
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
408 sys.stdout.write('\r' + '\n'.join((
de6bf71 @mitsuhiko some performance improvements
authored
409 '=' * 80,
410 'Template Engine BigTable Benchmark'.center(80),
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
411 '=' * 80,
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
412 __doc__,
de6bf71 @mitsuhiko some performance improvements
authored
413 '-' * 80
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
414 )) + '\n')
c9705c2 @mitsuhiko all unittests pass, the special and dependency lookups have their own vi...
authored
415
416
6cc2b23 @moraes Added benchmark for chameleon/chameleon-genshi.
moraes authored
417 for test in 'jinja', 'mako', 'tornado', 'tenjin', 'spitfire', 'django', 'genshi', 'cheetah', 'chameleon', 'chameleon_genshi':
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
418 if locals()['test_' + test] is None:
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
419 sys.stdout.write(' %-20s*not installed*\n' % test)
2feed1d @mitsuhiko there is now a workaround in the compiler that makes sure it's possible ...
authored
420 continue
00d5d21 @mitsuhiko some more stuff for jinja2
authored
421 t = Timer(setup='from __main__ import test_%s as bench' % test,
422 stmt='bench()')
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
423 sys.stdout.write(' >> %-20s<running>' % test)
de6bf71 @mitsuhiko some performance improvements
authored
424 sys.stdout.flush()
19cf9c2 @mitsuhiko small performance improvements
authored
425 sys.stdout.write('\r %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
32a910f @mitsuhiko added spitfire to bench and did some more refactoring
authored
426 sys.stdout.write('-' * 80 + '\n')
427 sys.stdout.write('''\
428 WARNING: The results of this benchmark are useless to compare the
429 performance of template engines and should not be taken seriously in any
430 way. It's testing the performance of simple loops and has no real-world
431 usefulnes. It only used to check if changes on the Jinja code affect
432 performance in a good or bad way and how it roughly compares to others.
433 ''' + '=' * 80 + '\n')
Something went wrong with that request. Please try again.