]> Dogcows Code - chaz/p5-CGI-Ex/blob - samples/benchmark/bench_various_templaters.pl
CGI::Ex 2.13
[chaz/p5-CGI-Ex] / samples / benchmark / bench_various_templaters.pl
1 #!/usr/bin/perl -w
2
3 =head1 NAME
4
5 bench_various_templaters.pl - test the relative performance of several different types of template engines.
6
7 =cut
8
9 use strict;
10 use Benchmark qw(timethese cmpthese);
11
12 use Template;
13 use Template::Stash;
14 use Template::Stash::XS;
15 use Template::Parser::CET;
16 use Text::Template;
17 use HTML::Template;
18 use HTML::Template::Expr;
19 use HTML::Template::JIT;
20 use CGI::Ex::Dump qw(debug);
21 use CGI::Ex::Template;
22 use CGI::Ex::Template::XS;
23 use POSIX qw(tmpnam);
24 use File::Path qw(mkpath rmtree);
25
26 ###----------------------------------------------------------------###
27
28 my $names = {
29 CET => 'CGI::Ex::Template using TT interface',
30 CETX => 'CGI::Ex::Template::XS using TT interface',
31 CETH => 'CGI::Ex::Template using HTML::Template interface',
32 CETXH => 'CGI::Ex::Template::XS using HTML::Template interface',
33 HT => 'HTML::Template',
34 HTE => 'HTML::Template::Expr',
35 HTJ => 'HTML::Template::JIT - Compiled to C template',
36 TextTemplate => 'Text::Template - Perl code eval based',
37 TT => 'Template::Toolkit',
38 TTX => 'Template::Toolkit with Stash::XS',
39 TTXCET => 'Template::Toolkit with Stash::XS and Template::Parser::CET',
40
41 mem => 'Compiled in memory',
42 file => 'Loaded from file',
43 str => 'From string ref',
44 };
45
46 ###----------------------------------------------------------------###
47 ### get cache and compile dirs ready
48
49 my $dir = tmpnam;
50 my $dir2 = "$dir.cache";
51 mkpath($dir);
52 mkpath($dir2);
53 END {rmtree $dir; rmtree $dir2};
54 my @dirs = ($dir);
55
56 ###----------------------------------------------------------------###
57
58 my $form = {
59 foo => 'bar',
60 pass_in_something => 'what ever you want',
61 };
62
63 my $filler = ((" foo" x 10)."\n") x 10;
64
65 my $stash_t = {
66 shell_header => "This is a header",
67 shell_footer => "This is a footer",
68 shell_start => "<html>",
69 shell_end => "<end>",
70 a_stuff => [qw(one two three four)],
71 };
72
73 my $stash_ht = {
74 shell_header => "This is a header",
75 shell_footer => "This is a footer",
76 shell_start => "<html>",
77 shell_end => "<end>",
78 a_stuff => [map {{name => $_}} qw(one two three four)],
79 };
80
81 $FOO::shell_header = $FOO::shell_footer = $FOO::shell_start = $FOO::shell_end = $FOO::a_stuff;
82 $FOO::shell_header = "This is a header";
83 $FOO::shell_footer = "This is a footer";
84 $FOO::shell_start = "<html>";
85 $FOO::shell_end = "<end>";
86 $FOO::a_stuff = [qw(one two three four)];
87
88
89 ###----------------------------------------------------------------###
90 ### TT style template
91
92 my $content_tt = <<"DOC";
93 [% shell_header %]
94 [% shell_start %]
95 $filler
96
97 [% IF foo %]
98 This is some text.
99 [% END %]
100
101 [% FOREACH i IN a_stuff %][% i %][% END %]
102 [% pass_in_something %]
103
104 $filler
105 [% shell_end %]
106 [% shell_footer %]
107 DOC
108
109 if (open (my $fh, ">$dir/foo.tt")) {
110 print $fh $content_tt;
111 close $fh;
112 }
113
114 ###----------------------------------------------------------------###
115 ### HTML::Template style
116
117 my $content_ht = <<"DOC";
118 <TMPL_VAR NAME=shell_header>
119 <TMPL_VAR NAME=shell_start>
120 $filler
121
122 <TMPL_IF NAME=foo>
123 This is some text.
124 </TMPL_IF>
125
126 <TMPL_LOOP NAME=a_stuff><TMPL_VAR NAME=name></TMPL_LOOP>
127 <TMPL_VAR NAME=pass_in_something>
128
129 $filler
130 <TMPL_VAR NAME=shell_end>
131 <TMPL_VAR NAME=shell_footer>
132 DOC
133
134 if (open (my $fh, ">$dir/foo.ht")) {
135 print $fh $content_ht;
136 close $fh;
137 }
138
139 ###----------------------------------------------------------------###
140 ### Text::Template style template
141
142 my $content_p = <<"DOC";
143 {\$shell_header}
144 {\$shell_start}
145 $filler
146
147 { if (\$foo) {
148 \$OUT .= "
149 This is some text.
150 ";
151 }
152 }
153
154 { \$OUT .= \$_ foreach \@\$a_stuff; }
155 {\$pass_in_something}
156
157 $filler
158 {\$shell_end}
159 {\$shell_footer}
160 DOC
161
162 ###----------------------------------------------------------------###
163 ### The TT interface allows for a single object to be cached and reused.
164
165 my $tt = Template->new( INCLUDE_PATH => \@dirs, STASH => Template::Stash->new($stash_t));
166 my $ttx = Template->new( INCLUDE_PATH => \@dirs, STASH => Template::Stash::XS->new($stash_t));
167 my $ct = CGI::Ex::Template->new( INCLUDE_PATH => \@dirs, VARIABLES => $stash_t);
168 my $ctx = CGI::Ex::Template::XS->new(INCLUDE_PATH => \@dirs, VARIABLES => $stash_t);
169
170 ###----------------------------------------------------------------###
171
172 my $tests = {
173
174 ###----------------------------------------------------------------###
175 ### compile means item was compiled to optree or perlcode and stored on disk
176
177 TT_file => sub {
178 my $tt = Template->new(INCLUDE_PATH => \@dirs, STASH => Template::Stash->new($stash_t), COMPILE_DIR => $dir2);
179 my $out = ""; $tt->process('foo.tt', $form, \$out); $out;
180 },
181 TTX_file => sub {
182 my $tt = Template->new(INCLUDE_PATH => \@dirs, STASH => Template::Stash::XS->new($stash_t), COMPILE_DIR => $dir2);
183 my $out = ""; $tt->process('foo.tt', $form, \$out); $out;
184 },
185 CET_file => sub {
186 my $t = CGI::Ex::Template->new(INCLUDE_PATH => \@dirs, VARIABLES => $stash_t, COMPILE_DIR => $dir2);
187 my $out = ''; $t->process('foo.tt', $form, \$out); $out;
188 },
189 CETX_file => sub {
190 my $t = CGI::Ex::Template::XS->new(INCLUDE_PATH => \@dirs, VARIABLES => $stash_t, COMPILE_DIR => $dir2);
191 my $out = ''; $t->process('foo.tt', $form, \$out); $out;
192 },
193
194 CETH_file => sub {
195 my $ht = CGI::Ex::Template->new(type => 'filename', source => "foo.ht", file_cache => 1, path => \@dirs, file_cache_dir => $dir2);
196 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
197 },
198 CETXH_file => sub {
199 my $ht = CGI::Ex::Template::XS->new(type => 'filename', source => "foo.ht", file_cache => 1, path => \@dirs, file_cache_dir => $dir2);
200 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
201 },
202 HT_file => sub {
203 my $ht = HTML::Template->new(type => 'filename', source => "foo.ht", file_cache => 1, path => \@dirs, file_cache_dir => $dir2);
204 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
205 },
206
207 ###----------------------------------------------------------------###
208 ### str infers that we are pulling from a string reference
209
210 TextTemplate_str => sub {
211 my $pt = Text::Template->new(
212 TYPE => 'STRING',
213 SOURCE => $content_p,
214 HASH => $form);
215 my $out = $pt->fill_in(PACKAGE => 'FOO', HASH => $form);
216 },
217
218 TT_str => sub {
219 my $t = Template->new(STASH => Template::Stash->new($stash_t));
220 my $out = ""; $t->process(\$content_tt, $form, \$out); $out;
221 },
222 TTX_str => sub {
223 my $t = Template->new(STASH => Template::Stash::XS->new($stash_t));
224 my $out = ""; $t->process(\$content_tt, $form, \$out); $out;
225 },
226 TTXCET_str => sub {
227 my $t = Template->new(STASH => Template::Stash::XS->new($stash_t), PARSER => Template::Parser::CET->new);
228 my $out = ""; $t->process(\$content_tt, $form, \$out); $out;
229 },
230 CET_str => sub {
231 my $t = CGI::Ex::Template->new(VARIABLES => $stash_t);
232 my $out = ""; $t->process(\$content_tt, $form, \$out); $out;
233 },
234 CETX_str => sub {
235 my $t = CGI::Ex::Template::XS->new(VARIABLES => $stash_t);
236 my $out = ""; $t->process(\$content_tt, $form, \$out); $out;
237 },
238
239 CETH_str => sub {
240 my $ht = CGI::Ex::Template->new( type => 'scalarref', source => \$content_ht);
241 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
242 },
243 CETXH_str => sub {
244 my $ht = CGI::Ex::Template::XS->new(type => 'scalarref', source => \$content_ht);
245 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
246 },
247 HT_str => sub {
248 my $ht = HTML::Template->new( type => 'scalarref', source => \$content_ht);
249 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
250 },
251 HTE_str => sub {
252 my $ht = HTML::Template::Expr->new( type => 'scalarref', source => \$content_ht);
253 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
254 },
255
256 ###----------------------------------------------------------------###
257 ### mem indicates that the compiled form is stored in memory
258
259 TT_mem => sub { my $out = ""; $tt->process( 'foo.tt', $form, \$out); $out },
260 TTX_mem => sub { my $out = ""; $ttx->process('foo.tt', $form, \$out); $out },
261 CET_mem => sub { my $out = ""; $ct->process( 'foo.tt', $form, \$out); $out },
262 CETX_mem => sub { my $out = ""; $ctx->process('foo.tt', $form, \$out); $out },
263
264 CETH_mem => sub {
265 my $ht = CGI::Ex::Template->new( filename => "foo.ht", path => \@dirs, cache => 1);
266 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
267 },
268 CETXH_mem => sub {
269 my $ht = CGI::Ex::Template::XS->new(filename => "foo.ht", path => \@dirs, cache => 1);
270 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
271 },
272 HT_mem => sub {
273 my $ht = HTML::Template->new( filename => "foo.ht", path => \@dirs, cache => 1);
274 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
275 },
276 HTE_mem => sub {
277 my $ht = HTML::Template::Expr->new( filename => "foo.ht", path => \@dirs, cache => 1);
278 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
279 },
280 HTJ_mem => sub { # this is interesting - it is compiled - but it is pulled into memory just once
281 my $ht = HTML::Template::JIT->new( filename => "foo.ht", path => \@dirs, jit_path => $dir2);
282 $ht->param($stash_ht); $ht->param($form); my $out = $ht->output;
283 },
284 };
285
286 my $test = $tests->{'TT_str'}->();
287 foreach my $name (sort keys %$tests) {
288 if ($test ne $tests->{$name}->()) {
289 die "$name did not match TT_str output\n";
290 }
291 $name =~ /(\w+)_(\w+)/;
292 print "$name - $names->{$1} - ($names->{$2})\n";
293 }
294
295 ###----------------------------------------------------------------###
296 ### and now - the tests - grouped by common capability
297
298 my %mem_tests = map {($_ => $tests->{$_})} grep {/_mem$/} keys %$tests;
299 my %cpl_tests = map {($_ => $tests->{$_})} grep {/_file$/} keys %$tests;
300 my %str_tests = map {($_ => $tests->{$_})} grep {/_str$/} keys %$tests;
301
302 print "------------------------------------------------------------------------\n";
303 print "From a string or scalarref tests\n";
304 cmpthese timethese (-2, \%str_tests);
305
306 print "------------------------------------------------------------------------\n";
307 print "Compiled and cached on the file system tests\n";
308 cmpthese timethese (-2, \%cpl_tests);
309
310 print "------------------------------------------------------------------------\n";
311 print "Cached in memory tests\n";
312 cmpthese timethese (-2, \%mem_tests);
313
314 #print "------------------------------------------------------------------------\n";
315 #print "All variants together\n";
316 #cmpthese timethese (-2, $tests);
317
318 ###----------------------------------------------------------------###
319
320 __END__
321
322 =head1 SAMPLE OUTPUT v2.13
323
324 CETH_file - CGI::Ex::Template using HTML::Template interface - (Loaded from file)
325 CETH_mem - CGI::Ex::Template using HTML::Template interface - (Compiled in memory)
326 CETH_str - CGI::Ex::Template using HTML::Template interface - (From string ref)
327 CETXH_file - CGI::Ex::Template::XS using HTML::Template interface - (Loaded from file)
328 CETXH_mem - CGI::Ex::Template::XS using HTML::Template interface - (Compiled in memory)
329 CETXH_str - CGI::Ex::Template::XS using HTML::Template interface - (From string ref)
330 CETX_file - CGI::Ex::Template::XS using TT interface - (Loaded from file)
331 CETX_mem - CGI::Ex::Template::XS using TT interface - (Compiled in memory)
332 CETX_str - CGI::Ex::Template::XS using TT interface - (From string ref)
333 CET_file - CGI::Ex::Template using TT interface - (Loaded from file)
334 CET_mem - CGI::Ex::Template using TT interface - (Compiled in memory)
335 CET_str - CGI::Ex::Template using TT interface - (From string ref)
336 HTE_mem - HTML::Template::Expr - (Compiled in memory)
337 HTE_str - HTML::Template::Expr - (From string ref)
338 HTJ_mem - HTML::Template::JIT - Compiled to C template - (Compiled in memory)
339 HT_file - HTML::Template - (Loaded from file)
340 HT_mem - HTML::Template - (Compiled in memory)
341 HT_str - HTML::Template - (From string ref)
342 TTXCET_str - Template::Toolkit with Stash::XS and Template::Parser::CET - (From string ref)
343 TTX_file - Template::Toolkit with Stash::XS - (Loaded from file)
344 TTX_mem - Template::Toolkit with Stash::XS - (Compiled in memory)
345 TTX_str - Template::Toolkit with Stash::XS - (From string ref)
346 TT_file - Template::Toolkit - (Loaded from file)
347 TT_mem - Template::Toolkit - (Compiled in memory)
348 TT_str - Template::Toolkit - (From string ref)
349 TextTemplate_str - Text::Template - Perl code eval based - (From string ref)
350 ------------------------------------------------------------------------
351 From a string or scalarref tests
352 Benchmark: running CETH_str, CETXH_str, CETX_str, CET_str, HTE_str, HT_str, TTXCET_str, TTX_str, TT_str, TextTemplate_str for at least 2 CPU seconds...
353 CETH_str: 2 wallclock secs ( 2.18 usr + 0.00 sys = 2.18 CPU) @ 1449.08/s (n=3159)
354 CETXH_str: 2 wallclock secs ( 2.00 usr + 0.01 sys = 2.01 CPU) @ 1700.00/s (n=3417)
355 CETX_str: 2 wallclock secs ( 2.22 usr + 0.00 sys = 2.22 CPU) @ 1584.23/s (n=3517)
356 CET_str: 2 wallclock secs ( 2.14 usr + 0.00 sys = 2.14 CPU) @ 1333.18/s (n=2853)
357 HTE_str: 2 wallclock secs ( 2.07 usr + 0.00 sys = 2.07 CPU) @ 922.71/s (n=1910)
358 HT_str: 2 wallclock secs ( 2.13 usr + 0.00 sys = 2.13 CPU) @ 1221.13/s (n=2601)
359 TTXCET_str: 2 wallclock secs ( 2.01 usr + 0.01 sys = 2.02 CPU) @ 534.16/s (n=1079)
360 TTX_str: 2 wallclock secs ( 2.14 usr + 0.00 sys = 2.14 CPU) @ 312.62/s (n=669)
361 TT_str: 3 wallclock secs ( 2.12 usr + 0.01 sys = 2.13 CPU) @ 300.47/s (n=640)
362 TextTemplate_str: 2 wallclock secs ( 2.13 usr + 0.02 sys = 2.15 CPU) @ 1189.77/s (n=2558)
363 Rate TT_str TTX_str TTXCET_str HTE_str TextTemplate_str HT_str CET_str CETH_str CETX_str CETXH_str
364 TT_str 300/s -- -4% -44% -67% -75% -75% -77% -79% -81% -82%
365 TTX_str 313/s 4% -- -41% -66% -74% -74% -77% -78% -80% -82%
366 TTXCET_str 534/s 78% 71% -- -42% -55% -56% -60% -63% -66% -69%
367 HTE_str 923/s 207% 195% 73% -- -22% -24% -31% -36% -42% -46%
368 TextTemplate_str 1190/s 296% 281% 123% 29% -- -3% -11% -18% -25% -30%
369 HT_str 1221/s 306% 291% 129% 32% 3% -- -8% -16% -23% -28%
370 CET_str 1333/s 344% 326% 150% 44% 12% 9% -- -8% -16% -22%
371 CETH_str 1449/s 382% 364% 171% 57% 22% 19% 9% -- -9% -15%
372 CETX_str 1584/s 427% 407% 197% 72% 33% 30% 19% 9% -- -7%
373 CETXH_str 1700/s 466% 444% 218% 84% 43% 39% 28% 17% 7% --
374 ------------------------------------------------------------------------
375 Compiled and cached on the file system tests
376 Benchmark: running CETH_file, CETXH_file, CETX_file, CET_file, HT_file, TTX_file, TT_file for at least 2 CPU seconds...
377 CETH_file: 3 wallclock secs ( 2.14 usr + 0.02 sys = 2.16 CPU) @ 3106.02/s (n=6709)
378 CETXH_file: 2 wallclock secs ( 2.01 usr + 0.04 sys = 2.05 CPU) @ 4447.80/s (n=9118)
379 CETX_file: 3 wallclock secs ( 2.02 usr + 0.09 sys = 2.11 CPU) @ 3586.26/s (n=7567)
380 CET_file: 3 wallclock secs ( 2.16 usr + 0.05 sys = 2.21 CPU) @ 2432.13/s (n=5375)
381 HT_file: 2 wallclock secs ( 2.18 usr + 0.03 sys = 2.21 CPU) @ 1868.33/s (n=4129)
382 TTX_file: 2 wallclock secs ( 2.14 usr + 0.04 sys = 2.18 CPU) @ 820.64/s (n=1789)
383 TT_file: 2 wallclock secs ( 2.11 usr + 0.04 sys = 2.15 CPU) @ 733.02/s (n=1576)
384 Rate TT_file TTX_file HT_file CET_file CETH_file CETX_file CETXH_file
385 TT_file 733/s -- -11% -61% -70% -76% -80% -84%
386 TTX_file 821/s 12% -- -56% -66% -74% -77% -82%
387 HT_file 1868/s 155% 128% -- -23% -40% -48% -58%
388 CET_file 2432/s 232% 196% 30% -- -22% -32% -45%
389 CETH_file 3106/s 324% 278% 66% 28% -- -13% -30%
390 CETX_file 3586/s 389% 337% 92% 47% 15% -- -19%
391 CETXH_file 4448/s 507% 442% 138% 83% 43% 24% --
392 ------------------------------------------------------------------------
393 Cached in memory tests
394 Benchmark: running CETH_mem, CETXH_mem, CETX_mem, CET_mem, HTE_mem, HTJ_mem, HT_mem, TTX_mem, TT_mem for at least 2 CPU seconds...
395 CETH_mem: 2 wallclock secs ( 2.11 usr + 0.03 sys = 2.14 CPU) @ 3193.46/s (n=6834)
396 CETXH_mem: 2 wallclock secs ( 2.18 usr + 0.04 sys = 2.22 CPU) @ 4622.07/s (n=10261)
397 CETX_mem: 2 wallclock secs ( 2.02 usr + 0.10 sys = 2.12 CPU) @ 6334.43/s (n=13429)
398 CET_mem: 2 wallclock secs ( 2.16 usr + 0.04 sys = 2.20 CPU) @ 3946.82/s (n=8683)
399 HTE_mem: 2 wallclock secs ( 2.20 usr + 0.01 sys = 2.21 CPU) @ 1515.38/s (n=3349)
400 HTJ_mem: 2 wallclock secs ( 2.05 usr + 0.06 sys = 2.11 CPU) @ 5990.05/s (n=12639)
401 HT_mem: 2 wallclock secs ( 1.98 usr + 0.03 sys = 2.01 CPU) @ 2588.56/s (n=5203)
402 TTX_mem: 2 wallclock secs ( 2.07 usr + 0.03 sys = 2.10 CPU) @ 3254.29/s (n=6834)
403 TT_mem: 2 wallclock secs ( 2.18 usr + 0.02 sys = 2.20 CPU) @ 2217.73/s (n=4879)
404 Rate HTE_mem TT_mem HT_mem CETH_mem TTX_mem CET_mem CETXH_mem HTJ_mem CETX_mem
405 HTE_mem 1515/s -- -32% -41% -53% -53% -62% -67% -75% -76%
406 TT_mem 2218/s 46% -- -14% -31% -32% -44% -52% -63% -65%
407 HT_mem 2589/s 71% 17% -- -19% -20% -34% -44% -57% -59%
408 CETH_mem 3193/s 111% 44% 23% -- -2% -19% -31% -47% -50%
409 TTX_mem 3254/s 115% 47% 26% 2% -- -18% -30% -46% -49%
410 CET_mem 3947/s 160% 78% 52% 24% 21% -- -15% -34% -38%
411 CETXH_mem 4622/s 205% 108% 79% 45% 42% 17% -- -23% -27%
412 HTJ_mem 5990/s 295% 170% 131% 88% 84% 52% 30% -- -5%
413 CETX_mem 6334/s 318% 186% 145% 98% 95% 60% 37% 6% --
414
415 =cut
This page took 0.069099 seconds and 4 git commands to generate.