PDFLATEX := pdflatex
PDFLATEXFLAGS := -halt-on-error -file-line-error
+PLOTS := stw pause time mem ncol
+PROGS := bigarr conalloc concpu mcore rnddata sbtree split \
+ bh bisort em3d tsp voronoi dil
+
+STATS := ./stats.py
+TEMPLITE := ./templite.py
+
+EPSTOPDF := epstopdf
+GNUPLOT := gnuplot
+
+comma := ,
+
imgs := $O/img/mark-sweep-0.pdf \
$(patsubst %.dot,$O/%.pdf,$(wildcard img/mark-sweep-*.dot)) \
- $O/img/heap.pdf
+ $O/img/heap.pdf \
+ $(patsubst %,$O/img/norm-hist-%.pdf,$(PLOTS))
presentacion.pdf: $O/presentacion.tex $(imgs)
@echo "$(PDFLATEX) $< > $@"
@echo "$(AAFIG) $< > $@"
@$(AAFIG) $(AAFIGFLAGS) -t pdf -o $@ $<
+$O/img/norm-hist-%.csv: img/raw-hist-%.csv
+ @echo "norm $< > $@"
+ @awk -F, -v m=`cut -d, -f4 $< | $(STATS) '$$1' '%(max)s'` \
+ '{print $$1 "," $$2/m "," $$3/m "," $$4/m "," $$5/m}' \
+ $< > $@
+
+$O/img/norm-hist-%.eps: $(patsubst %,$O/img/norm-hist-\%-%.csv,$(PROGS))
+ @echo "plot $< > $@"
+ @$(TEMPLITE) "progs=($(patsubst %,'%'$(comma),$(PROGS))), " \
+ "files=($(patsubst %,'%'$(comma),$^))" \
+ < histogram-plot.tpl.gpi | $(GNUPLOT) > $@
+
+$O/img/norm-hist-%.pdf: $O/img/norm-hist-%.eps
+ @echo "$(EPSTOPDF) $< > $@"
+ @$(EPSTOPDF) --outfile=$@ $<
+
$O/img/%.pdf: img/%.pdf
@echo "cp $< > $@"
@cp $< $@
--- /dev/null
+#!/bin/bash
+
+res_root="../../cd/resultados"
+
+stats="../../dgcbench/stats.py"
+
+progs="bigarr conalloc concpu mcore rnddata sbtree split"
+progs="$progs bh bisort em3d tsp voronoi dil"
+
+cdgc_opts="cdgc-conservative=0:fork=1:early_collect=1:eager_alloc=1"
+
+declare -A opts=(
+ [basic]="cdgc-conservative=1:fork=0:early_collect=0:eager_alloc=0"
+ [cdgc]="$cdgc_opts"
+)
+
+declare -A time_opts=(
+ [basic]="basic"
+ [cdgc]="$cdgc_opts"
+)
+
+declare -A exps=(
+ [pause]='$2'
+ [stw]='$4'
+ [mem]='($5+$6+$7+$8)/1024/1024'
+ [ncol]=''
+)
+
+get_counts() {
+ exp="${exps[$1]}"
+ prog="$2"
+ opts="${opts[$3]}"
+ for f in "$res_root/raw-collect/collect-$prog-$opts-4cpu-"*.csv
+ do
+ sed 1d "$f" | wc -l
+ done
+}
+
+get_maxs() {
+ exp="${exps[$1]}"
+ prog="$2"
+ opts="${opts[$3]}"
+ for f in "$res_root/raw-collect/collect-$prog-$opts-4cpu-"*.csv
+ do
+ $stats "$exp" '%(max)s' < $f
+ done
+}
+
+declare -A funcs=(
+ [pause]=get_maxs
+ [stw]=get_maxs
+ [mem]=get_maxs
+ [ncol]=get_counts
+)
+
+for val in stw pause mem ncol
+do
+ for prog in $progs
+ do
+ dst="raw-hist-$val-$prog.csv"
+ echo $dst
+ rm -f $dst
+ for gc in basic cdgc
+ do
+ echo -n "$gc," >> $dst
+ ${funcs[$val]} $val $prog $gc | $stats >> $dst
+ done
+ done
+done
+
+# time
+for prog in $progs
+do
+ dst="raw-hist-time-$prog.csv"
+ echo $dst
+ rm -f $dst
+ for gc in basic cdgc
+ do
+ opts="${time_opts[$gc]}"
+ src="$res_root/raw-timemem/timemem-$prog-$opts-4cpu.csv"
+ echo -n "$gc," >> $dst
+ $stats < "$src" >> $dst
+ done
+done
+
--- /dev/null
+#!/usr/bin/gnuplot
+
+# Terminal
+set term postscript eps color size 16cm,9cm 16
+
+# Style macros
+set macros
+min = "lc rgb 'gray20'"
+std = "lc rgb 'gray50'"
+max = "lc rgb 'gray90'"
+
+# Style
+set style histogram rows title offset character 2, 0.25, 0
+set style fill solid 1.00 border rgb 'black'
+set style data histograms
+set boxwidth 0.8 absolute
+set xtics border in scale 1,0.5 nomirror rotate by -45 offset character 0,0.3,0
+set yrange [0:1.18]
+
+# Data format
+set datafile separator ','
+
+# Labels
+#set ylabel "$ {ylabel}$"
+#set xlabel font "/usr/share/fonts/truetype/msttcorefonts/arial.ttf,9"
+
+
+# Plot
+${
+def title(i, name):
+ emit('title "%s"' % name if i == 0 else 'notitle')
+def end(i):
+ emit(', \\' if i != len(progs)-1 else '')
+def at(i):
+ emit(i*4)
+}$
+no_neg(x)=(x < 0) ? 0 : x
+only_neg(x)=(x < 0) ? x : 0
+plot ${ for i, name in enumerate(progs): }$ \
+ newhistogram '${name}$' at ${at(i)}$, '${files[i]}$' \
+ using (no_neg($2+only_neg($3-$2-$5))) ${title(i, 'min')}$ lt 1 @min, \
+ '' using (no_neg($3-$2-$5)) notitle lt 1 @max, \
+ '' using ($5):xtic(1) ${title(i, 'media+/-dstd')}$ lt 1 @std, \
+ '' using ($5+only_neg($4-$3-$5)) notitle lt 1 @std, \
+ '' using (no_neg($4-$3-$5)) ${title(i, 'max')}$ lt 1 @max ${end(i)}$
+${:}$
+
--- /dev/null
+basic,2.07917,2.18310545,4.157879,0.464813462944
+cdgc,11.433216,11.433216,11.433216,5.46751098841e-15
--- /dev/null
+basic,11.433216,11.433216,11.433216,5.46751098841e-15
+cdgc,38.455475,38.55940565,40.534088,0.464791996691
--- /dev/null
+basic,30.141022,30.141022,30.141022,1.09350219768e-14
+cdgc,30.141022,30.141022,30.141022,1.09350219768e-14
--- /dev/null
+basic,12.789091,13.77643265,13.828398,0.232396110149
+cdgc,248.714491,612.7363295,866.070425,210.640857572
--- /dev/null
+basic,12.789091,13.6205366,13.828398,0.426522593268
+cdgc,233.124701,572.7225661,865.031118,181.60645256
--- /dev/null
+basic,192.323128,213.68236495,225.195165,11.577899837
+cdgc,280.140861,307.0036485,324.047602,12.9706109271
--- /dev/null
+basic,63.399216,63.399216,63.399216,7.29001465121e-15
+cdgc,63.399216,63.399216,63.399216,7.29001465121e-15
--- /dev/null
+basic,28.062313,35.3894916,43.652103,4.72650854508
+cdgc,29.10162,39.8065926,48.848637,5.59284100127
--- /dev/null
+basic,179.803017,179.803017,179.803017,5.83201172097e-14
+cdgc,88.342861,94.71795645,103.27893,2.86178337954
--- /dev/null
+basic,16.629845,16.629845,16.629845,3.64500732561e-15
+cdgc,16.629845,16.629845,16.629845,3.64500732561e-15
--- /dev/null
+basic,39.531034,39.531034,39.531034,7.29001465121e-15
+cdgc,39.510735,39.510735,39.510735,7.29001465121e-15
--- /dev/null
+basic,63.399216,63.399216,63.399216,7.29001465121e-15
+cdgc,63.399216,63.399216,63.399216,7.29001465121e-15
--- /dev/null
+basic,16.629845,16.629845,16.629845,3.64500732561e-15
+cdgc,30.141022,30.141022,30.141022,1.09350219768e-14
--- /dev/null
+basic,194.0,461.9,476.0,63.0571169655
+cdgc,136.0,146.45,153.0,6.80150912047
--- /dev/null
+basic,304.0,304.0,304.0,0.0
+cdgc,197.0,197.2,201.0,0.894427191
--- /dev/null
+basic,9.0,9.0,9.0,0.0
+cdgc,13.0,13.0,13.0,0.0
--- /dev/null
+basic,137.0,291.65,531.0,117.535784025
+cdgc,71.0,107.95,136.0,22.8484135117
--- /dev/null
+basic,131.0,337.85,842.0,190.429231226
+cdgc,61.0,108.65,138.0,21.8373774211
--- /dev/null
+basic,60.0,66.65,73.0,3.68888800817
+cdgc,56.0,60.45,69.0,3.44085362726
--- /dev/null
+basic,13.0,13.0,13.0,0.0
+cdgc,16.0,16.1,17.0,0.307793505626
--- /dev/null
+basic,20.0,26.0,32.0,3.41821744866
+cdgc,16.0,21.1,24.0,2.04939015319
--- /dev/null
+basic,26.0,26.0,26.0,0.0
+cdgc,27.0,30.2,34.0,1.47255595908
--- /dev/null
+basic,882.0,882.0,882.0,0.0
+cdgc,1599.0,1611.95,1625.0,11.5870844614
--- /dev/null
+basic,6.0,6.0,6.0,0.0
+cdgc,6.0,6.0,6.0,0.0
--- /dev/null
+basic,13.0,13.0,13.0,0.0
+cdgc,19.0,19.0,19.0,0.0
--- /dev/null
+basic,20.0,20.0,20.0,0.0
+cdgc,17.0,17.0,17.0,0.0
--- /dev/null
+basic,0.006341,0.0070548,0.011743,0.00118721073374
+cdgc,0.020404,0.02165885,0.023406,0.000843754221822
--- /dev/null
+basic,0.013362,0.01400835,0.015574,0.00057152964421
+cdgc,0.022026,0.0268808,0.034491,0.00366693087788
--- /dev/null
+basic,0.122755,0.1246257,0.129578,0.00151685346411
+cdgc,0.007484,0.0075112,0.007543,1.55211231281e-05
--- /dev/null
+basic,0.042979,0.07535985,0.134227,0.023178607547
+cdgc,0.021947,0.04329685,0.098636,0.0230773515225
--- /dev/null
+basic,0.192288,0.451174,0.836117,0.194322757006
+cdgc,0.026142,0.162402,0.537421,0.164214566828
--- /dev/null
+basic,1.595315,1.71880855,2.117081,0.108999370252
+cdgc,0.03875,0.0451756,0.068917,0.00710120491184
--- /dev/null
+basic,0.090642,0.09101215,0.091644,0.0002873076977
+cdgc,0.001516,0.00175475,0.003647,0.000609403753033
--- /dev/null
+basic,0.001075,0.0025355,0.007734,0.00172627385459
+cdgc,0.001624,0.002694,0.00442,0.000892104961962
--- /dev/null
+basic,0.482151,0.4841625,0.486271,0.00134280525296
+cdgc,0.003564,0.00382025,0.004365,0.000193515367267
--- /dev/null
+basic,0.047843,0.0487219,0.049951,0.000489057945119
+cdgc,0.031739,0.0328529,0.033435,0.000482458495624
--- /dev/null
+basic,0.027929,0.02840565,0.033432,0.00120746006908
+cdgc,0.001889,0.0020243,0.002595,0.000172639905127
--- /dev/null
+basic,0.170735,0.17245185,0.175821,0.00123120874604
+cdgc,0.009535,0.0095982,0.009822,7.71775806006e-05
--- /dev/null
+basic,0.088204,0.08969115,0.092197,0.00130518493447
+cdgc,0.025863,0.02688875,0.0299,0.00109041570417
--- /dev/null
+basic,0.003338,0.00372125,0.004419,0.000303491936076
+cdgc,0.000665,0.0007152,0.000824,4.97314895477e-05
--- /dev/null
+basic,0.011832,0.0119604,0.012157,8.92426614999e-05
+cdgc,0.001727,0.0019626,0.002702,0.000268126129
--- /dev/null
+basic,0.112923,0.11454635,0.117228,0.000976614305973
+cdgc,0.001251,0.0012971,0.001531,6.82116674693e-05
--- /dev/null
+basic,0.038047,0.07398005,0.130561,0.0238953876952
+cdgc,0.017973,0.0402028,0.096622,0.024038583949
--- /dev/null
+basic,0.133355,0.44688645,0.835915,0.199266115678
+cdgc,0.021121,0.15964875,0.53686,0.163611449594
--- /dev/null
+basic,1.545817,1.66497965,2.06463,0.10821270263
+cdgc,0.008421,0.010195,0.010774,0.000667461727663
--- /dev/null
+basic,0.08985,0.09021725,0.090844,0.000281627763845
+cdgc,0.001266,0.00147915,0.003145,0.000522728094258
--- /dev/null
+basic,0.000469,0.00075325,0.001444,0.000266041918937
+cdgc,0.001287,0.00212125,0.004034,0.000838577547178
--- /dev/null
+basic,0.481313,0.4833222,0.485427,0.00134525652416
+cdgc,0.003373,0.00361295,0.004183,0.000194769897977
--- /dev/null
+basic,0.043971,0.0448436,0.04604,0.000482406729463
+cdgc,0.000753,0.00088175,0.000956,6.41805635441e-05
--- /dev/null
+basic,0.027061,0.02753045,0.032559,0.00120309852049
+cdgc,0.001528,0.00164625,0.002133,0.000150209634213
--- /dev/null
+basic,0.159822,0.1614685,0.164834,0.00123199938055
+cdgc,0.002531,0.0029089,0.003554,0.000344218856329
--- /dev/null
+basic,0.081298,0.08261495,0.085106,0.00110376549164
+cdgc,0.001046,0.0011569,0.001533,0.000122656945648
--- /dev/null
+basic,4.69,4.9406,5.05,0.0508463070318
+cdgc,4.81,4.9106,5.81,0.147030609058
--- /dev/null
+basic,4.95,5.0068,5.12,0.0341329931956
+cdgc,5.13,5.335,5.69,0.0727940903634
--- /dev/null
+basic,3.14,3.1518,3.18,0.0118992368131
+cdgc,2.81,2.8288,2.85,0.0128793459081
--- /dev/null
+basic,1.61,2.8505,4.28,0.645008975866
+cdgc,1.83,1.998,2.28,0.112230964861
--- /dev/null
+basic,2.13,3.552,5.23,1.06569769585
+cdgc,1.85,2.0815,2.56,0.163812312371
--- /dev/null
+basic,48.36,55.4776,69.04,4.33202952861
+cdgc,20.27,20.5098,20.91,0.131109706361
--- /dev/null
+basic,5.09,5.1212,5.29,0.0352043596558
+cdgc,4.55,4.5684,4.6,0.0126748988645
--- /dev/null
+basic,5.22,5.6934,6.14,0.178252400734
+cdgc,2.65,3.0444,3.27,0.135136514499
--- /dev/null
+basic,5.28,5.3296,5.63,0.0511883277512
+cdgc,0.94,0.972,1.01,0.0239897937482
--- /dev/null
+basic,4.97,5.0006,5.06,0.0221691088624
+cdgc,6.46,6.5522,6.83,0.0553758954412
--- /dev/null
+basic,2.37,2.379,2.38,0.00303045763366
+cdgc,0.35,0.3574,0.36,0.00443087497693
--- /dev/null
+basic,2.62,2.7112,2.83,0.0774238269501
+cdgc,1.99,2.0786,2.71,0.113766857912
--- /dev/null
+basic,2.89,3.4748,6.67,0.599401878747
+cdgc,0.32,0.3234,0.33,0.00478518120698
Banco de Pruebas
--------------------------------------------------
-Diapositiva 1
+Generalidades
~~~~~~~~~~~~~
-Diapositiva 1
+* Múltiples corridas (20-50)
-Diapositiva 2
-~~~~~~~~~~~~~
-Diapositiva 2
+ * Minimizar error en la medición
+ * Resultados expresados en función de:
+ * Mínimo
+ * Media
+ * Máximo
+ * Desvío estándar
-Tiempo de Stop-The-World
---------------------------------------------------
+* Minimizar variación entre corridas
-Diapositiva 1
-~~~~~~~~~~~~~
-Diapositiva 1
+ * ``cpufreq-set(1)``
+ * ``nice(1)``
+ * ``ionice(1)``
-Diapositiva 2
-~~~~~~~~~~~~~
-Diapositiva 2
+Programas
+~~~~~~~~~
+* Triviales (7)
+ * Ejercitar aspectos puntuales
+ * No realizan una tarea útil
+ * Casos patológicos
-Tiempo de Pausa Real
---------------------------------------------------
+* Programas pequeños - *Olden Benchmark* (5)
-Diapositiva 1
-~~~~~~~~~~~~~
-Diapositiva 1
+ * Relativamente pequeños (400-1000 *SLOC*)
+ * Realizan una tarea útil
+ * Manipulan mucho listas y árboles asignando mucha memoria
+ * No son ideales para probar un *GC*
-Diapositiva 2
-~~~~~~~~~~~~~
-Diapositiva 2
+* Programas reales - **Dil** (1)
+ * Compilador de D escrito en D
+ * Grande y complejo (32K+ *SLOC*, 86 módulos, 300+ *clases*)
+ * Programado sin (limitaciones ni ventajas del) *GC* en mente
+ * Manipulación de *strings*, arreglos dinámicos y asociativos
+
+Métricas
+~~~~~~~~
+* Tiempo total de ejecución
+* Tiempo máximo de *stop-the-world*
+* Tiempo máximo de pausa real
+* Cantidad máxima de memoria utilizada
+* Cantidad total de recolecciones realizadas
-Tiempo de Ejecución
+
+Gráficos de Corridas
--------------------------------------------------
-Diapositiva 1
-~~~~~~~~~~~~~
-Diapositiva 1
+Tiempo Máximo de Stop-The-World
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. image:: img/norm-hist-stw.pdf
+ :width: 12.5cm
+
+Tiempo Máximo de Pausa Real
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. image:: img/norm-hist-pause.pdf
+ :width: 12.5cm
+
+
+Tiempo Total de Ejecución
+~~~~~~~~~~~~~~~~~~~~~~~~~
+.. image:: img/norm-hist-time.pdf
+ :width: 12.5cm
+
+Cantidad total de recolecciones realizadas
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. image:: img/norm-hist-ncol.pdf
+ :width: 12.5cm
+
+Cantidad máxima de memoria utilizada
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. image:: img/norm-hist-mem.pdf
+ :width: 12.5cm
-Diapositiva 2
-~~~~~~~~~~~~~
-Diapositiva 2
Conclusión
--- /dev/null
+#!/usr/bin/env python
+
+import re
+import sys
+import numpy.numarray.mlab as m
+
+exp = '$1'
+fmt = '%(min)s,%(mean)s,%(max)s,%(std)s'
+sep = ','
+
+try:
+ exp = sys.argv[1]
+ fmt = sys.argv[2]
+ sep = sys.argv[3]
+except:
+ pass
+
+vals = []
+for n, l in enumerate(sys.stdin):
+ l = l.strip()
+ if not l:
+ continue
+ try:
+ fields = dict([('$'+str(int(k)+1), float(v.strip()))
+ for k, v in enumerate(l.split(sep))])
+ v = float(eval(re.sub(r'(\$\d+)', r'%(\1)f', exp) % fields))
+ except:
+ if n == 0:
+ continue
+ raise
+ vals.append(v)
+vars = dict(min=min(vals), mean=m.mean(vals), max=max(vals), std=m.std(vals))
+print fmt % vars
+
--- /dev/null
+#!/usr/bin/env python
+#
+# Templite+
+# A light-weight, fully functional, general purpose templating engine
+#
+# Copyright (c) 2009 joonis new media
+# Author: Thimo Kraemer <thimo.kraemer@joonis.de>
+#
+# Based on Templite - Tomer Filiba
+# http://code.activestate.com/recipes/496702/
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+import sys, re
+
+class Templite(object):
+ auto_emit = re.compile('(^[\'\"])|(^[a-zA-Z0-9_\[\]\'\"]+$)')
+
+ def __init__(self, template, start='${', end='}$'):
+ if len(start) != 2 or len(end) != 2:
+ raise ValueError('each delimiter must be two characters long')
+ delimiter = re.compile('%s(.*?)%s' % (re.escape(start), re.escape(end)), re.DOTALL)
+ offset = 0
+ tokens = []
+ for i, part in enumerate(delimiter.split(template)):
+ part = part.replace('\\'.join(list(start)), start)
+ part = part.replace('\\'.join(list(end)), end)
+ if i % 2 == 0:
+ if not part: continue
+ part = part.replace('\\', '\\\\').replace('"', '\\"')
+ part = '\t' * offset + 'emit("""%s""")' % part
+ else:
+ part = part.rstrip()
+ if not part: continue
+ if part.lstrip().startswith(':'):
+ if not offset:
+ raise SyntaxError('no block statement to terminate: ${%s}$' % part)
+ offset -= 1
+ part = part.lstrip()[1:]
+ if not part.endswith(':'): continue
+ elif self.auto_emit.match(part.lstrip()):
+ part = 'emit(%s)' % part.lstrip()
+ lines = part.splitlines()
+ margin = min(len(l) - len(l.lstrip()) for l in lines if l.strip())
+ part = '\n'.join('\t' * offset + l[margin:] for l in lines)
+ if part.endswith(':'):
+ offset += 1
+ tokens.append(part)
+ if offset:
+ raise SyntaxError('%i block statement(s) not terminated' % offset)
+ self.__code = compile('\n'.join(tokens), '<templite %r>' % template[:20], 'exec')
+
+ def render(self, __namespace=None, **kw):
+ """
+ renders the template according to the given namespace.
+ __namespace - a dictionary serving as a namespace for evaluation
+ **kw - keyword arguments which are added to the namespace
+ """
+ namespace = {}
+ if __namespace: namespace.update(__namespace)
+ if kw: namespace.update(kw)
+ namespace['emit'] = self.write
+
+ __stdout = sys.stdout
+ sys.stdout = self
+ self.__output = []
+ eval(self.__code, namespace)
+ sys.stdout = __stdout
+ return ''.join(self.__output)
+
+ def write(self, *args):
+ for a in args:
+ self.__output.append(str(a))
+
+
+if __name__ == '__main__':
+
+ if '--demo' not in sys.argv:
+ vars = eval('dict(' + ' '.join(sys.argv[1:]) + ')')
+ sys.stdout.write(Templite(sys.stdin.read()).render(vars))
+ sys.exit(0)
+
+ template = r"""
+This we already know:
+<html>
+ <body>
+ ${
+ def say_hello(arg):
+ emit("hello ", arg, "<br>")
+ }$
+
+ <table>
+ ${
+ for i in range(10):
+ emit("<tr><td> ")
+ say_hello(i)
+ emit(" </tr></td>\n")
+ }$
+ </table>
+
+ ${emit("hi")}$
+
+ tralala ${if x > 7:
+ say_hello("big x")}$ lala
+
+ $\{this is escaped starting delimiter
+
+ ${emit("this }\$ is an escaped ending delimiter")}$
+
+ ${# this is a python comment }$
+
+ </body>
+</html>
+
+But this is completely new:
+${if x > 7:}$
+ x is ${emit('greater')}$ than ${print x-1}$ Well, the print statement produces a newline.
+${:else:}$
+ This terminates the previous code block and starts an else code block
+ Also this would work: $\{:end}\$$\{else:}\$, but not this: $\{:end}\$ $\{else:}\$
+${:this terminates the else-block
+only the starting colon is essential}$
+
+So far you had to write:
+${
+ if x > 3:
+ emit('''
+ After a condition you could not continue your template.
+ You had to write pure python code.
+ The only way was to use %%-based substitutions %s
+ ''' % x)
+}$
+
+${if x > 6:}$
+ Now you do not need to break your template ${print x}$
+${:elif x > 3:}$
+ This is great
+${:endif}$
+
+${for i in range(x-1):}$ Of course you can use any type of block statement ${i}$ ${"fmt: %s" % (i*2)}$
+${:else:}$
+Single variables and expressions starting with quotes are substituted automatically.
+Instead $\{emit(x)}\$ you can write $\{x}\$ or $\{'%s' % x}\$ or $\{"", x}\$
+Therefore standalone statements like break, continue or pass
+must be enlosed by a semicolon: $\{continue;}\$
+The end
+${:end-for}$
+"""
+
+ t = Templite(template)
+ print t.render(x=8)
+
+
+ # Output is:
+ """
+This we already know:
+<html>
+ <body>
+
+
+ <table>
+ <tr><td> hello 0<br> </tr></td>
+<tr><td> hello 1<br> </tr></td>
+<tr><td> hello 2<br> </tr></td>
+<tr><td> hello 3<br> </tr></td>
+<tr><td> hello 4<br> </tr></td>
+<tr><td> hello 5<br> </tr></td>
+<tr><td> hello 6<br> </tr></td>
+<tr><td> hello 7<br> </tr></td>
+<tr><td> hello 8<br> </tr></td>
+<tr><td> hello 9<br> </tr></td>
+
+ </table>
+
+ hi
+
+ tralala hello big x<br> lala
+
+ ${this is escaped starting delimiter
+
+ this }$ is an escaped ending delimiter
+
+
+
+ </body>
+</html>
+
+But this is completely new:
+
+ x is greater than 7
+ Well, the print statement produces a newline.
+
+
+So far you had to write:
+
+ After a condition you could not continue your template.
+ You had to write pure python code.
+ The only way was to use %-based substitutions 8
+
+
+
+ Now you do not need to break your template 8
+
+
+
+ Of course you can use any type of block statement 0 fmt: 0
+ Of course you can use any type of block statement 1 fmt: 2
+ Of course you can use any type of block statement 2 fmt: 4
+ Of course you can use any type of block statement 3 fmt: 6
+ Of course you can use any type of block statement 4 fmt: 8
+ Of course you can use any type of block statement 5 fmt: 10
+ Of course you can use any type of block statement 6 fmt: 12
+
+Single variables and expressions starting with quotes are substituted automatically.
+Instead ${emit(x)}$ you can write ${x}$ or ${'%s' % x}$ or ${"", x}$
+Therefore standalone statements like break, continue or pass
+must be enlosed by a semicolon: ${continue;}$
+The end
+"""
+