[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