# HG changeset patch # User cmlenz # Date 1153482961 0 # Node ID ff19219485cc9c7eede2206f505750c0b073129a # Parent fa08aef181a2100ef9057fb4ab1623d8af2212ff Add benchmark that builds a large HTML table using different templating techniques (provided by Jonas). diff --git a/examples/bench/basic.py b/examples/bench/basic.py new file mode 100644 --- /dev/null +++ b/examples/bench/basic.py @@ -0,0 +1,160 @@ +from cgi import escape +import os +from StringIO import StringIO +import sys +import timeit + +__all__ = ['clearsilver', 'django', 'kid', 'markup', 'simpletal'] + +def markup(dirname, verbose=False): + from markup.template import Context, TemplateLoader + loader = TemplateLoader([dirname], auto_reload=False) + template = loader.load('template.html') + def render(): + ctxt = Context(title='Just a test', user='joe', + items=['Number %d' % num for num in range(1, 15)]) + return template.generate(ctxt).render('html') + + if verbose: + print render() + return render + +def cheetah(dirname, verbose=False): + # FIXME: infinite recursion somewhere... WTF? + from Cheetah.Template import Template + class MyTemplate(Template): + def serverSidePath(self, path): return os.path.join(dirname, path) + filename = os.path.join(dirname, 'template.tmpl') + template = MyTemplate(file=filename) + + def render(): + template = MyTemplate(file=filename, + searchList=[{'title': 'Just a test', 'user': 'joe', + 'items': [u'Number %d' % num for num in range(1, 15)]}]) + return template.respond() + + if verbose: + print render() + return render + +def clearsilver(dirname, verbose=False): + import neo_cgi + neo_cgi.update() + import neo_util + import neo_cs + def render(): + hdf = neo_util.HDF() + hdf.setValue('hdf.loadpaths.0', dirname) + hdf.setValue('title', escape('Just a test')) + hdf.setValue('user', escape('joe')) + for num in range(1, 15): + hdf.setValue('items.%d' % (num - 1), escape('Number %d' % num)) + cs = neo_cs.CS(hdf) + cs.parseFile('template.cs') + return cs.render() + + if verbose: + print render() + return render + +def django(dirname, verbose=False): + from django.conf import settings + settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')]) + from django import template, templatetags + from django.template import loader + templatetags.__path__.append(os.path.join(dirname, 'templatetags')) + tmpl = loader.get_template('template.html') + + def render(): + data = {'title': 'Just a test', 'user': 'joe', + 'items': ['Number %d' % num for num in range(1, 15)]} + return tmpl.render(template.Context(data)) + + if verbose: + print render() + return render + +def kid(dirname, verbose=False): + import kid + kid.path = kid.TemplatePath([dirname]) + template = kid.Template(file='template.kid') + def render(): + template = kid.Template(file='template.kid', + title='Just a test', user='joe', + items=['Number %d' % num for num in range(1, 15)]) + return template.serialize(output='xhtml') + + if verbose: + print render() + return render + +def nevow(dirname, verbose=False): + # FIXME: can't figure out the API + from nevow.loaders import xmlfile + template = xmlfile('template.xml', templateDir=dirname).load() + def render(): + print template + + if verbose: + print render() + return render + +def simpletal(dirname, verbose=False): + from simpletal import simpleTAL, simpleTALES + fileobj = open(os.path.join(dirname, 'base.html')) + base = simpleTAL.compileHTMLTemplate(fileobj) + fileobj.close() + fileobj = open(os.path.join(dirname, 'template.html')) + template = simpleTAL.compileHTMLTemplate(fileobj) + fileobj.close() + def render(): + ctxt = simpleTALES.Context() + ctxt.addGlobal('base', base) + ctxt.addGlobal('title', 'Just a test') + ctxt.addGlobal('user', 'joe') + ctxt.addGlobal('items', ['Number %d' % num for num in range(1, 15)]) + buf = StringIO() + template.expand(ctxt, buf) + return buf.getvalue() + + if verbose: + print render() + return render + +def run(engines, verbose=False): + basepath = os.path.abspath(os.path.dirname(__file__)) + for engine in engines: + dirname = os.path.join(basepath, engine) + if verbose: + print '%s:' % engine.capitalize() + print '--------------------------------------------------------' + else: + print '%s:' % engine.capitalize(), + t = timeit.Timer(setup='from __main__ import %s; render = %s("%s", %s)' + % (engine, engine, dirname, verbose), + stmt='render()') + time = t.timeit(number=2000) / 2000 + if verbose: + print '--------------------------------------------------------' + print '%.2f ms' % (1000 * time) + if verbose: + print '--------------------------------------------------------' + + +if __name__ == '__main__': + engines = [arg for arg in sys.argv[1:] if arg[0] != '-'] + if not engines: + engines = __all__ + + verbose = '-v' in sys.argv + + if '-p' in sys.argv: + import hotshot, hotshot.stats + prof = hotshot.Profile("template.prof") + benchtime = prof.runcall(run, engines, verbose=verbose) + stats = hotshot.stats.load("template.prof") + stats.strip_dirs() + stats.sort_stats('time', 'calls') + stats.print_stats() + else: + run(engines, verbose=verbose) diff --git a/examples/bench/bigtable.py b/examples/bench/bigtable.py new file mode 100644 --- /dev/null +++ b/examples/bench/bigtable.py @@ -0,0 +1,152 @@ +# -*- encoding: utf-8 -*- +# Template language benchmarks +# +# Objective: Generate a 1000x10 HTML table as fast as possible. +# +# Author: Jonas Borgström + +import sys +import timeit + +import cElementTree as cet +from elementtree import ElementTree as et +import kid +from markup.builder import tag +from markup.template import Context, Template +import neo_cgi +import neo_cs +import neo_util + +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)] + +markup_tmpl = Template(""" + + + +
+
+""") + +markup_tmpl2 = Template(""" +$table
+""") + +kid_tmpl = kid.Template(""" + + + +
+
+""") + +kid_tmpl2 = kid.Template(""" +$table +""") + + +def test_markup(): + """Markup template""" + ctxt = Context(table=table) + stream = markup_tmpl.generate(ctxt) + stream.render('html') + +def test_markup_builder(): + """Markup template + tag builder""" + stream = tag.TABLE([ + tag.tr([tag.td(c) for c in row.values()]) + for row in table + ]).generate() + ctxt = Context(table=stream) + stream = markup_tmpl2.generate(ctxt) + stream.render('html') + +def test_builder(): + """Markup tag builder""" + stream = tag.TABLE([ + tag.tr([ + tag.td(c) for c in row.values() + ]) + for row in table + ]).generate() + stream.render('html') + +def test_kid(): + """Kid template""" + kid_tmpl.table = table + kid_tmpl.serialize(output='html') + +def test_kid_et(): + """Kid template + cElementTree""" + _table = cet.Element('table') + for row in table: + td = cet.SubElement(_table, 'tr') + for c in row.values(): + cet.SubElement(td, 'td').text=str(c) + kid_tmpl2.table = _table + kid_tmpl2.serialize(output='html') + +def test_et(): + """ElementTree""" + _table = et.Element('table') + for row in table: + tr = et.SubElement(_table, 'tr') + for c in row.values(): + et.SubElement(tr, 'td').text=str(c) + et.tostring(_table) + +def test_cet(): + """cElementTree""" + _table = cet.Element('table') + for row in table: + tr = cet.SubElement(_table, 'tr') + for c in row.values(): + cet.SubElement(tr, 'td').text=str(c) + cet.tostring(_table) + +def test_clearsilver(): + """ClearSilver""" + hdf = neo_util.HDF() + for i, row in enumerate(table): + for j, c in enumerate(row.values()): + hdf.setValue("rows.%d.cell.%d" % (i, j), str(c)) + + cs = neo_cs.CS(hdf) + cs.parseStr(""" + +
""") + cs.render() + + +def run(which=None, number=10): + tests = ['test_builder', 'test_markup', 'test_markup_builder', 'test_kid', + 'test_kid_et', 'test_et', 'test_cet', 'test_clearsilver'] + if which: + tests = filter(lambda n: n[5:] in which, tests) + + for test in tests: + t = timeit.Timer(setup='from __main__ import %s;' % test, + stmt='%s()' % test) + time = t.timeit(number=number) / number + + print '%-35s %8.2f ms' % (getattr(sys.modules[__name__], test).__doc__, + 1000 * time) + + +if __name__ == '__main__': + which = [arg for arg in sys.argv[1:] if arg[0] != '-'] + + if '-p' in sys.argv: + import hotshot, hotshot.stats + prof = hotshot.Profile("template.prof") + benchtime = prof.runcall(run, which, number=1) + stats = hotshot.stats.load("template.prof") + stats.strip_dirs() + stats.sort_stats('time', 'calls') + stats.print_stats() + else: + run(which) diff --git a/examples/bench/run.py b/examples/bench/run.py deleted file mode 100644 --- a/examples/bench/run.py +++ /dev/null @@ -1,160 +0,0 @@ -from cgi import escape -import os -from StringIO import StringIO -import sys -import timeit - -__all__ = ['clearsilver', 'django', 'kid', 'markup', 'simpletal'] - -def markup(dirname, verbose=False): - from markup.template import Context, TemplateLoader - loader = TemplateLoader([dirname], auto_reload=False) - template = loader.load('template.html') - def render(): - ctxt = Context(title='Just a test', user='joe', - items=['Number %d' % num for num in range(1, 15)]) - return template.generate(ctxt).render('html') - - if verbose: - print render() - return render - -def cheetah(dirname, verbose=False): - # FIXME: infinite recursion somewhere... WTF? - from Cheetah.Template import Template - class MyTemplate(Template): - def serverSidePath(self, path): return os.path.join(dirname, path) - filename = os.path.join(dirname, 'template.tmpl') - template = MyTemplate(file=filename) - - def render(): - template = MyTemplate(file=filename, - searchList=[{'title': 'Just a test', 'user': 'joe', - 'items': [u'Number %d' % num for num in range(1, 15)]}]) - return template.respond() - - if verbose: - print render() - return render - -def clearsilver(dirname, verbose=False): - import neo_cgi - neo_cgi.update() - import neo_util - import neo_cs - def render(): - hdf = neo_util.HDF() - hdf.setValue('hdf.loadpaths.0', dirname) - hdf.setValue('title', escape('Just a test')) - hdf.setValue('user', escape('joe')) - for num in range(1, 15): - hdf.setValue('items.%d' % (num - 1), escape('Number %d' % num)) - cs = neo_cs.CS(hdf) - cs.parseFile('template.cs') - return cs.render() - - if verbose: - print render() - return render - -def django(dirname, verbose=False): - from django.conf import settings - settings.configure(TEMPLATE_DIRS=[os.path.join(dirname, 'templates')]) - from django import template, templatetags - from django.template import loader - templatetags.__path__.append(os.path.join(dirname, 'templatetags')) - tmpl = loader.get_template('template.html') - - def render(): - data = {'title': 'Just a test', 'user': 'joe', - 'items': ['Number %d' % num for num in range(1, 15)]} - return tmpl.render(template.Context(data)) - - if verbose: - print render() - return render - -def kid(dirname, verbose=False): - import kid - kid.path = kid.TemplatePath([dirname]) - template = kid.Template(file='template.kid') - def render(): - template = kid.Template(file='template.kid', - title='Just a test', user='joe', - items=['Number %d' % num for num in range(1, 15)]) - return template.serialize(output='xhtml') - - if verbose: - print render() - return render - -def nevow(dirname, verbose=False): - # FIXME: can't figure out the API - from nevow.loaders import xmlfile - template = xmlfile('template.xml', templateDir=dirname).load() - def render(): - print template - - if verbose: - print render() - return render - -def simpletal(dirname, verbose=False): - from simpletal import simpleTAL, simpleTALES - fileobj = open(os.path.join(dirname, 'base.html')) - base = simpleTAL.compileHTMLTemplate(fileobj) - fileobj.close() - fileobj = open(os.path.join(dirname, 'template.html')) - template = simpleTAL.compileHTMLTemplate(fileobj) - fileobj.close() - def render(): - ctxt = simpleTALES.Context() - ctxt.addGlobal('base', base) - ctxt.addGlobal('title', 'Just a test') - ctxt.addGlobal('user', 'joe') - ctxt.addGlobal('items', ['Number %d' % num for num in range(1, 15)]) - buf = StringIO() - template.expand(ctxt, buf) - return buf.getvalue() - - if verbose: - print render() - return render - -def run(engines, verbose=False): - basepath = os.path.abspath(os.path.dirname(__file__)) - for engine in engines: - dirname = os.path.join(basepath, engine) - if verbose: - print '%s:' % engine.capitalize() - print '--------------------------------------------------------' - else: - print '%s:' % engine.capitalize(), - t = timeit.Timer(setup='from __main__ import %s; render = %s("%s", %s)' - % (engine, engine, dirname, verbose), - stmt='render()') - time = t.timeit(number=2000) / 2000 - if verbose: - print '--------------------------------------------------------' - print '%.2f ms' % (1000 * time) - if verbose: - print '--------------------------------------------------------' - - -if __name__ == '__main__': - engines = [arg for arg in sys.argv[1:] if arg[0] != '-'] - if not engines: - engines = __all__ - - verbose = '-v' in sys.argv - - if '-p' in sys.argv: - import hotshot, hotshot.stats - prof = hotshot.Profile("template.prof") - benchtime = prof.runcall(run, engines, verbose=verbose) - stats = hotshot.stats.load("template.prof") - stats.strip_dirs() - stats.sort_stats('time', 'calls') - stats.print_stats() - else: - run(engines, verbose=verbose)