Skip Menu |

This queue is for tickets about the Params-Check CPAN distribution.

Report information
The Basics
Id: 27161
Status: open
Priority: 0/
Queue: Params-Check

People
Owner: Nobody in particular
Requestors: DAMS [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Enhancement proposal
Hi, I've worked on a reimplementation of this module for use in my company. Here is the version I ended with, that is backward compatible, contains the existing features, add 1 new feature, has the same code size, but is (sometimes really) faster. Attached are : - My implementation (file Check.pm) - The patch agains 0.26 version (file faster_reimpl.patch) - A benchmark file (file benchmark.pl) - The benchmark result, that I have commented (file result.txt) The new feature is that if you ask the template to store the value into a reference on a hash or array, then it's stored directyl in the array or hash. Thus you can write : my @array; check({ foo => { default => [], store => \@array} }, { foo => [ 42 ] } # @array is ( 42 ); Enjoy ! :) dams
Subject: result.txt
*** store2 Rate orig new orig 28169/s -- -18% new 34483/s 22% -- *** subs1 Rate orig new orig 25316/s -- -37% new 40000/s 58% -- # no difference, same code is run *** no_override Rate orig new orig 16129/s -- -8% new 17544/s 9% -- # first run is valid arg, second is broken arg # new code is optimized for valid args *** strict2 Rate orig new orig 27397/s -- -40% new 45455/s 66% -- Rate orig new orig 19231/s -- -13% new 21978/s 14% -- *** edge_case Rate orig new orig 37975/s -- -35% new 58824/s 55% -- *** preserver_case2 Rate orig new orig 15385/s -- -11% new 17241/s 12% -- # first run is valid arg, second is broken arg # new code is optimized for valid args *** required Rate orig new orig 29851/s -- -40% new 50000/s 67% -- Rate orig new orig 21739/s -- -4% new 22727/s 5% -- # first run is valid arg, second is broken arg # new code is optimized for valid args *** strict1 Rate orig new orig 26316/s -- -38% new 42553/s 62% -- Rate orig new orig 19048/s -- -12% new 21739/s 14% -- *** subs3 Rate orig new orig 25641/s -- -40% new 42553/s 66% -- *** unknown1 Rate orig new orig 18018/s -- -19% new 22222/s 23% -- *** r1 Rate orig new orig 6061/s -- -36% new 9434/s 56% -- *** real_life2 Rate orig new orig 5848/s -- -37% new 9259/s 58% -- # first run is valid arg, second is broken arg # new code is optimized for valid args *** define1 Rate orig new orig 27778/s -- -39% new 45455/s 64% -- Rate orig new orig 21053/s -- -14% new 24390/s 16% -- *** real_life Rate orig new orig 6993/s -- -14% new 8130/s 16% -- *** invalid_store Rate orig new orig 43103/s -- -34% new 64935/s 51% -- # they are all failing test, so not that much diff *** invalid_key_tests Rate orig new orig 14493/s -- -16% new 17241/s 19% -- Rate orig new orig 14493/s -- -12% new 16393/s 13% -- Rate orig new orig 14085/s -- -13% new 16129/s 15% -- Rate orig new orig 13699/s -- -12% new 15625/s 14% -- # last case is broken arg # new code is optimized for valid args *** default Rate orig new orig 38961/s -- -36% new 61224/s 57% -- Rate orig new orig 29412/s -- -40% new 49180/s 67% -- Rate orig new orig 28302/s -- -24% new 37037/s 31% -- Rate orig new orig 15873/s -- -14% new 18519/s 17% -- *** big_template Rate orig new orig 5348/s -- -22% new 6897/s 29% -- # Huge gain here, with ALLOW_UNKNOWN = 1 *** unknown2 Rate orig new orig 35088/s -- -47% new 66667/s 90% -- *** store1 Rate orig new orig 28571/s -- -11% new 32258/s 13% -- *** simple Rate orig new orig 30612/s -- -38% new 49180/s 61% -- *** r2 Rate orig new orig 5814/s -- -38% new 9346/s 61% -- *** preserver_case1 Rate orig new orig 32258/s -- -31% new 46512/s 44% -- # first run is valid arg, second is broken arg # new code is optimized for valid args *** define2 Rate orig new orig 28571/s -- -39% new 46512/s 63% -- Rate orig new orig 21739/s -- -14% new 25316/s 16% -- *** subs2 Rate orig new orig 25316/s -- -38% new 40816/s 61% --
Subject: benchmark.pl
#!/usr/bin/perl use strict; use warnings; use Benchmark qw(cmpthese); use lib qw(/home/dams/scratchpad/Params-Check-0.26/lib); use Params::Check; use Params::Check2; my %tests = ( real_life => { count => 10000, code_in_func => 'my $foo1; my $foo2; my $foo3', template => q({ arg1 => { defined => 1, strict_type => 1, default => '' }, arg2 => { default => 'bar', store => \$foo1 }, arg3 => { default => 'mod', store => \$foo2 }, arg4 => { defined => 1, strict_type => 1, default => [], store => \$foo3 }, arg5 => { default => {}, strict_type => 1 }, arg6 => { default => 'a', allow => [ qw(b a c d) ], strict_type => 1}, }), params => [q({ arg1 => 'foo', arg2 => 'moz', arg4 => [ 'answer', 42 ], arg5 => { answer => 42 }, arg6 => 'c', })], }, real_life2 => { count => 10000, code => '$Params::Check::PRESERVE_CASE= 0; $Params::Check::ALLOW_UNKNOWN = 1; $Params::Check::SANITY_CHECK_TEMPLATE = 0; ', template => q({ arg1 => { defined => 1, strict_type => 1, default => ''}, arg2 => { default => 'bar'}, arg3 => { default => 'mod'}, arg4 => { defined => 1, strict_type => 1, default => ''}, arg5 => { default => 'bar'}, arg6 => { default => 'mod'}, arg7 => { defined => 1, strict_type => 1, default => ''}, arg8 => { default => 'bar'}, arg9 => { default => 'mod'}, }), params => [q({ arg1 => 'foo', arg2 => 'moz', arg3 => 'answer', arg4 => 'foo', arg5 => 'moz', arg6 => 'answer', arg7 => 'foo', arg8 => 'moz', arg9 => 'answer', })], }, r1 => { count => 10000, template => q({ arg1 => { defined => 1, strict_type => 1, default => ''}, arg2 => { default => 'bar'}, arg3 => { default => 'mod'}, arg4 => { defined => 1, strict_type => 1, default => ''}, arg5 => { default => 'bar'}, arg6 => { default => 'mod'}, arg7 => { defined => 1, strict_type => 1, default => ''}, arg8 => { default => 'bar'}, arg9 => { default => 'mod'}, }), params => [q({ arg1 => 'foo', arg2 => 'moz', arg3 => 'answer', arg4 => 'foo', arg5 => 'moz', arg6 => 'answer', arg7 => 'foo', arg8 => 'moz', arg9 => 'answer', })], }, r2 => { count => 10000, code => '$Params::Check::SANITY_CHECK_TEMPLATE = 0; ', template => q({ arg1 => { defined => 1, strict_type => 1, default => ''}, arg2 => { default => 'bar'}, arg3 => { default => 'mod'}, arg4 => { defined => 1, strict_type => 1, default => ''}, arg5 => { default => 'bar'}, arg6 => { default => 'mod'}, arg7 => { defined => 1, strict_type => 1, default => ''}, arg8 => { default => 'bar'}, arg9 => { default => 'mod'}, }), params => [q({ arg1 => 'foo', arg2 => 'moz', arg3 => 'answer', arg4 => 'foo', arg5 => 'moz', arg6 => 'answer', arg7 => 'foo', arg8 => 'moz', arg9 => 'answer', })], }, simple => { count => 30000, template => '{ arg1 => {}, }', params => ['{ arg1 => 1, }'], }, default => { count => 30000, template => '{ foo => { default => 1 } }', params => [ '{}', '{ foo => 2}', '{ FOO => 2}', '{ -foo => 2}', ], }, no_override => { count => 10000, template => '{ foo => { no_override => 1, default => 42 } }', params => [ '{ foo => 13 }', ], }, required => { count => 20000, template => '{ foo => { required => 1 } }', params => [ '{ foo => 42 }', '{ }', ], }, invalid_key_tests => { count => 10000, template => '{ foo => { allow => sub { 0 } } }', params => [ '{ foo => 1 }', '{ foo => "foo" }', '{ foo => [] }', '{ foo => bless({},__PACKAGE__) }', ], }, invalid_store => { count => 50000, template => q({ foo => { store => '' } }), params => [ '{ }', ], }, edge_case => { count => 30000, template => q({ foo => { default => '' } }), params => [ '{ }', ], }, big_template => { count => 10000, template => q({ firstname => { required => 1, defined => 1 }, lastname => { required => 1, store => \$lastname }, gender => { required => 1, allow => [qr/M/i, qr/F/i], }, married => { allow => [0,1] }, age => { default => 21, allow => qr/^\d+$/, }, id_list => { default => [], strict_type => 1 }, phone => { allow => sub { 1 if +shift } }, bureau => { default => 'NSA', no_override => 1 }, }), params => [ q({ firstname => 'joe', lastname => 'jackson', gender => 'M', married => 1, age => 21, id_list => [1..3], phone => '555-8844', }), ], }, preserver_case1 => { count => 20000, code => '$Params::Check::PRESERVE_CASE = 1', template => q({ Foo => { default => 1 } }), params => [ '{ Foo => 42 }', ], }, preserver_case2 => { count => 20000, code => '$Params::Check::PRESERVE_CASE = 0', template => q({ Foo => { default => 1 } }), params => [ '{ Foo => 42 }', ], }, unknown1 => { count => 20000, template => q({ }), params => [ '{ foo => 42 }', ], }, unknown2 => { count => 20000, code => '$Params::Check::ALLOW_UNKNOWN = 1', template => q({ }), params => [ '{ foo => 42 }', ], }, store1 => { count => 20000, code => '$Params::Check::NO_DUPLICATES = 1; my $foo;', template => q({ foo => { store => \$foo } }), params => [ '{ foo => 42 }', ], }, store2 => { count => 20000, code => '$Params::Check::NO_DUPLICATES = 0; my $foo;', template => q({ foo => { store => \$foo } }), params => [ '{ foo => 42 }', ], }, strict1 => { count => 20000, code => '$Params::Check::STRICT_TYPE = 0', template => q({ foo => { strict_type => 1, default => [] } }), params => [ '{ foo => [] }', '{ foo => {} }', ], }, strict2 => { count => 20000, code => '$Params::Check::STRICT_TYPE = 1', template => q({ foo => { default => [] } }), params => [ '{ foo => [] }', '{ foo => {} }', ], }, define1 => { count => 20000, code => '$Params::Check::ONLY_ALLOW_DEFINED = 0', template => q({ foo => { defined => 1, default => 1 } }), params => [ '{ foo => 42 }', '{ foo => undef }', ], }, define2 => { count => 20000, code => '$Params::Check::ONLY_ALLOW_DEFINED = 1', template => q({ foo => { default => 1 } }), params => [ '{ foo => 42 }', '{ foo => undef }', ], }, subs1 => { count => 20000, template => q({ foo => { allow => sub { [] } } }), params => [ '{ foo => [] }', ], }, subs2 => { count => 20000, template => q({ foo => { allow => sub { {} } } }), params => [ '{ foo => {} }', ], }, subs3 => { count => 20000, template => q({ foo => { allow => sub { 1 } } }), params => [ '{ foo => 1 }', ], }, ); #my @keep = qw(store1 store2); #my @keep = qw(r1 r2); #my @keep = qw(real_life real_life2); #if (@keep) { # my %f; # @f{@keep} = @tests{@keep}; # %tests = %f; #} while (my ($name, $data) = each(%tests)) { my ($count, $template, $params, $code, $code_in_func) = @{$data}{qw(count template params code code_in_func)}; local $Params::Check::VERBOSE; local $Params::Check::NO_DUPLICATES; local $Params::Check::STRIP_LEADING_DASHES; local $Params::Check::STRICT_TYPE; local $Params::Check::ALLOW_UNKNOWN; local $Params::Check::PRESERVE_CASE; local $Params::Check::ONLY_ALLOW_DEFINED; local $Params::Check::SANITY_CHECK_TEMPLATE; local $Params::Check::WARNINGS_FATAL; local $Params::Check::CALLER_DEPTH; local $Params::Check2::VERBOSE; local $Params::Check2::NO_DUPLICATES; local $Params::Check2::STRIP_LEADING_DASHES; local $Params::Check2::STRICT_TYPE; local $Params::Check2::ALLOW_UNKNOWN; local $Params::Check2::PRESERVE_CASE; local $Params::Check2::ONLY_ALLOW_DEFINED; local $Params::Check2::SANITY_CHECK_TEMPLATE; local $Params::Check2::WARNINGS_FATAL; local $Params::Check2::CALLER_DEPTH; $code_in_func ||= ''; $code ||= ''; my $code_original = $code; my $code_new = $code; my $code_new3 = $code; $code_new =~ s/Check/Check2/g; $code_new3 =~ s/Check/Check3/g; print "*** $name\n"; my $i = 0; foreach (@$params) { local $SIG{__WARN__} = sub {}; cmpthese($count, { orig => qq( $code_original; foo($_); sub foo { $code_in_func; Params::Check::check($template, \$_[0]) } ), new => qq( $code_new; foo($_); sub foo { $code_in_func; Params::Check2::check($template, \$_[0]) } ), }); } print "\n"; }
Subject: faster_reimpl.patch

Message body is not shown because it is too large.

Subject: Check.pm

Message body is not shown because it is too large.

On Wed May 16 15:22:21 2007, DAMS wrote: Show quoted text
> Hi, > > I've worked on a reimplementation of this module for use in my company. > Here is the version I ended with, that is backward compatible, contains > the existing features, add 1 new feature, has the same code size, but is > (sometimes really) faster.
Thanks for the patch -- allow me some time to take a look at it and i'll get back to you. Cheers, Jos