Benchmarks to Text::ClearSilver

Text::ClearSilver(CS)のベンチマークをとってみた。
比較はTemplate-Toolkit(TT), HTML::Template::Pro(HT), Text::MicroTemplate(MT)、およびMobaSiF::Template(MST)と行った。

ベンチマークスクリプトid:tokuhirom のものをベースに少し複雑にした。
結果:

$ perl benchmark/cs_tt_mt_ht.pl 100 # テンプレートの大きさを指定できる
5.10.1 on i686-linux
Template: 2.22
Text::MicroTemplate: 0.11
HTML::Template::Pro: 0.94
Text::ClearSilver: 0.10.5.1
MobaSiF::Template: 0.02
       Rate     TT     CS     MT     HT    MST
TT   55.1/s     --   -99%   -99%  -100%  -100%
CS   5023/s  9010%     --   -34%   -61%   -62%
MT   7657/s 13787%    52%     --   -40%   -42%
HT  12780/s 23077%   154%    67%     --    -3%
MST 13128/s 23709%   161%    71%     3%     --

結果、HTとMSTはテンプレートが巨大になるほどに際立ってくる。この中で唯一のPure PerlモジュールであるMTはかなり善戦するようだ。CSはTTと比較すると100倍ほど速いものの、MST,HT,MTと比較するとやや劣る。
特性としては、MSTは高速だがモジュールのインターフェイスは最低限のものしかなく、テンプレートの機能も低い。HTはHTMLエスケープをしてからエンジンに渡さなければならないためアトリビュートとしてescape="html"としなければならないため、ミスが生じやすい。MTとCSはモジュールのインターフェイスも充実しており、HTMLエスケープも簡単にできる*1ため使いやすい。
この中では、CSかMTが速度も機能も十分であり安全性も高いため、使いやすいように思う。

スクリプト

#!perl
use strict;
use warnings;
use Text::ClearSilver;
use Template;
use Text::MicroTemplate 'build_mt';
use HTML::Template::Pro;
use Benchmark ':all';

my $cs = Text::ClearSilver->new(VarEscapeMode => 'html');

my $n = shift(@ARGV) || 10;

my $tt_tmpl  = q{ [% foo  %] }            x $n;
my $mst_tmpl = q{ $= h:foo $ }            x $n;
my $cs_tmpl  = q{ <?cs var:foo ?> }       x $n;
my $mt_tmpl  = q{ <?=  $_[0]->{foo} ?> }  x $n;
my $ht_tmpl  = q{ <tmpl_var name="foo"> } x $n;

my $mt = build_mt($mt_tmpl);
my $ht = HTML::Template::Pro->new(
    scalarref => \$ht_tmpl,
);
my $tt = Template->new();

my $has_mst = eval { require MobaSiF::Template };

my %vars = (foo => 'bar');

printf "%vd %s\n", $^V, $^O;
foreach my $mod(qw(Template Text::MicroTemplate
    HTML::Template::Pro Text::ClearSilver),
    $has_mst ? 'MobaSiF::Template' : ()) {
    print $mod, ": ", $mod->VERSION, "\n";
}

my $mst_bin = 'mst.bin';
if($has_mst) {
    MobaSiF::Template::Compiler::compile(\$mst_tmpl, $mst_bin);
    eval q{ END{ unlink $mst_bin } };
}

if(0){
    warn _cs();
    warn _tt();
    warn _mt();
    warn _ht();
    warn _mst();
    exit;
}

cmpthese( -1, => {
        'CS'  => \&_cs,
        'TT'  => \&_tt,
        'MT'  => \&_mt,
        'HT'  => \&_ht,
        $has_mst ? ('MST' => \&_mst) : (),
    },
);

sub _cs {
    $cs->process(\$cs_tmpl, \%vars, \my $out );
    $out;
}
sub _tt {
    $tt->process(\$tt_tmpl, \%vars, \my $out) or die;
    $out;
}
sub _mt {
    $mt->(\%vars);
}
sub _ht {
    $ht->param(%vars);
    my $out = $ht->output();
}
sub _mst {
    MobaSiF::Template::insert($mst_bin, \%vars);
}
__END__

*1:MTはデフォルトでエスケープを行い、CSはnewにVarEscapeMode => 'html' を渡すと自動的にエスケープする。MSTもエスケープは簡単なのでミスの危険性は少ない。