[html-formfu] Performance
Carl Franks
fireartist at gmail.com
Thu Jun 28 15:18:40 GMT 2007
On 25/06/07, Tobias Kremer <list at funkreich.de> wrote:
> (widget) timethis 1000: 7 wallclock secs ( 7.26 usr + 0.35 sys =
> 7.61 CPU) @ 131.41/s (n=1000)
> (formfu) timethis 1000: 63 wallclock secs (59.00 usr + 2.99 sys =
> 61.99 CPU) @ 16.13/s (n=1000)
Okay, I've done some testing, and here's the results so far - and I
believe I have some good news!
I used 2 different benchmark files, both compare equivalent forms
built using HTML::FormFu, CGI::FormBuilder and HTML::Widget.
The first, "benchmark-basic.pl" has 10 text fields (each with the
'size' attribute set), and a submit button.
The second, "benchmark.pl", is similar, but has a select field
containing 101 items, and also the 'label' and 'value' set for all the
fields.
INITIAL BENCHMARKS
benchmark-basic.pl
* FormBuilder was 3x faster than FormFu
* html-widget was 15x faster than FormFu
benchmark.pl
* FormBuilder was 3.2x faster than FormFu
* html-widget was 7x faster than FormFu
This shows...
* html-widget is significantly faster than formfu
* html-widget has the biggest slowdown for the test using a large select field
(see below for benchmark output and files).
INLINED TEMPLATES BENCHMARK
I then experimented with inlining the FormFu TT templates, removing
all uses of WRAPPER, and as many uses of INCLUDE as possible.
In the end the only remaining includes were for block elements - so
the form used a single include for the fieldset, then the fieldset had
an include for each field. (so that's a total of 12 includes for
benchmark-basic.pl, and 13 includes for benchmark.pl)
benchmark-basic.pl
* FormBuilder was 2.3x faster than FormFu
* html-widget was 11.5x faster than FormFu
benchmark.pl
* FormBuilder was 2.2x faster than FormFu
* html-widget was 4.7x faster than FormFu
This shows...
* significant speed-up
* still a lot slower than html-widget
However there is a significant loss in functionality (losing a lot of
the granularity from the templates).
Template::Alloy BENCHMARK
I then reverted these changes and swapped from using TT to
Template::Alloy which supports the TT syntax and claims to be faster.
I only came across 1 incompatibility when running the FormFu test
suite - I was able to work around the problem with a minor change to
the templates, and I've logged a bug report with RT about it.
benchmark-basic.pl
* FormBuilder was 1.6x faster than FormFu
* html-widget was 8.2x faster than FormFu
benchmark.pl
* FormBuilder was 2.1x faster than FormFu
* html-widget was 4.5x faster than FormFu
This shows...
* massive speed difference simply switching to from TT to Template::Alloy
* still a noticeable slow-down when using a large select field - this
is likely due to the template include for every option in the select
field
Template::Alloy + INLINED SELECT OPTION BENCHMARK
I then also inlined the select option template - this was only in a
separate template for code-reuse reasons, not for user-customisation -
so I don't mind removing it.
benchmark-basic.pl
* FormBuilder was 1.5x faster than FormFu
* html-widget was 8x faster than FormFu
benchmark.pl
* FormBuilder was 1.6x faster than FormFu
* html-widget was 3.5x faster than FormFu
This shows...
* another significant speed-up when using a large select field
CONCLUSIONS
I plan to check-in the inlining of the select option template (and the
same change for radiogroup items) to remove the hit when rendering
large select fields.
I plan to make FormFu configurable, so you can easily choose
(preferably in your config file) to use Template::Alloy instead of TT.
The Template::Alloy TT incompatibility mentioned above was specific to
the select/radiogroup template which I propose removing - so it isn't
even an issue for use any more.
It would be good to have benchmark scripts in the repository which
compare several real-world templates, and possibly another which
intensively uses all the standard form fields.
DETAILED RESULTS
#####
# benchmark 1
$ benchmark-basic.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 17.0/s -- -67% -94%
CGI::FormBuilder 51.1/s 200% -- -81%
HTML::Widget 263/s 1447% 415% --
$ benchmark.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 8.44/s -- -69% -86%
CGI::FormBuilder 27.2/s 222% -- -54%
HTML::Widget 59.0/s 600% 117% --
#####
# benchmark 2
# inlined templates
$ benchmark-basic.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 22.7/s -- -56% -91%
CGI::FormBuilder 51.3/s 125% -- -80%
HTML::Widget 262/s 1051% 410% --
$ benchmark.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 12.3/s -- -55% -79%
CGI::FormBuilder 27.0/s 120% -- -53%
HTML::Widget 57.6/s 370% 114% --
#####
# benchmark 3
# Template::Alloy
$ benchmark-basic.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 31.5/s -- -36% -88%
CGI::FormBuilder 49.1/s 56% -- -81%
HTML::Widget 259/s 723% 427% --
$ benchmark.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 13.0/s -- -52% -78%
CGI::FormBuilder 27.2/s 110% -- -53%
HTML::Widget 58.1/s 348% 113% --
#####
# benchmark 4
# Template::Alloy + inlined select option template
$ benchmark-basic.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 32.0/s -- -36% -88%
CGI::FormBuilder 50.2/s 57% -- -80%
HTML::Widget 256/s 701% 411% --
$ benchmark.pl
Rate HTML::FormFu CGI::FormBuilder HTML::Widget
HTML::FormFu 16.6/s -- -39% -71%
CGI::FormBuilder 27.2/s 64% -- -53%
HTML::Widget 58.2/s 250% 114% --
#####
# benchmark-basic.pl
#!/usr/bin/perl
use strict;
use warnings;
use lib 'lib';
use HTML::FormFu;
use HTML::Widget;
use CGI::FormBuilder;
use Benchmark qw( cmpthese );
my $formfu = formfu();
my $widget = widget();
my $builder = builder();
# make sure TT has loaded/cached everything
my $output = "$formfu";
cmpthese(
1000,
{
'HTML::FormFu' => sub {
$output = "$formfu";
},
'HTML::Widget' => sub {
$output = $widget->process->as_xml;
},
'CGI::FormBuilder' => sub {
$output = $builder->render;
},
}
);
sub formfu {
my $form = HTML::FormFu->new;
$form->auto_fieldset(1);
for (1..10) {
$form->element({
name => "text$_",
size => 10
});
}
$form->element({
type => "submit",
name => "submit",
});
return $form;
}
sub widget {
my $form = HTML::Widget->new;
for (1..10) {
$form->element( "Textfield", "text$_" )->size(10);
}
$form->element( "Submit", "submit" );
return $form;
}
sub builder {
my $form = CGI::FormBuilder->new;
for (1..10) {
$form->field( name => "text$_", size => 10 );
}
return $form;
}
#####
# benchmark.pl
#!/usr/bin/perl
use strict;
use warnings;
use lib 'lib';
use HTML::FormFu;
use HTML::Widget;
use CGI::FormBuilder;
use Benchmark qw( cmpthese );
my $formfu = formfu();
my $widget = widget();
my $builder = builder();
# make sure TT has loaded/cached everything
my $output = "$formfu";
cmpthese(
500,
{
'HTML::FormFu' => sub {
$output = "$formfu";
},
'HTML::Widget' => sub {
$output = $widget->process->as_xml;
},
'CGI::FormBuilder' => sub {
$output = $builder->render;
},
}
);
sub formfu {
my $form = HTML::FormFu->new;
$form->auto_fieldset(1);
for (1..10) {
$form->element({
name => "text$_",
size => 10,
label => "text & $_",
});
}
$form->element({
name => "select",
type => "select",
label => "select",
values => [ 1907 .. 2007 ],
default => 2007,
});
$form->element({
type => "submit",
name => "submit",
});
return $form;
}
sub widget {
my $form = HTML::Widget->new;
for (1..10) {
$form->element( "Textfield", "text$_" )->label("text & $_")->size(10);
}
$form->element( "Select", "select" )->label("select")->options(
map { $_, $_ } 1907 .. 2007 )->selected(2007);
$form->element( "Submit", "submit" );
return $form;
}
sub builder {
my $form = CGI::FormBuilder->new;
for (1..10) {
$form->field(
name => "text$_",
size => 10,
label => "text & $_",
);
}
$form->field(
name => "select",
options => [ 1907 .. 2007 ],
value => 2007,
);
return $form;
}
More information about the HTML-FormFu
mailing list