[Date Prev][Date Next][Thread Prev][Thread Next] [Search] [Date Index] [Thread Index]

Re: Benchmarking (was: Re: [MacPerl] crazy hoops to do something that seems so simple?)



On Tue, Nov 14, 2000 at 09:46:06PM -0500, Scott R. Godin wrote:
> on 11/14/2000 03:20 PM, Ronald J Kimball at rjk@linguist.dartmouth.edu
> wrote:
> 
> > Here's an improved Benchmark.  I read <DATA> into @DATA first.  In each
> > iteration I copy the array to @tmp because otherwise the
> > substitutions/translations would affect @DATA.  (In this case, that
> > wouldn't really matter; every other iteration would just reverse the
> > change.)
> > 
> > 
> > Benchmark: timing 2048 iterations of Substitute, Trans...
> > Substitute: 13 wallclock secs (12.49 usr +  0.02 sys = 12.51 CPU)
> > Trans:       1 wallclock secs ( 0.57 usr +  0.00 sys =  0.57 CPU)
> > 
> > 
> > The difference between using s/// and tr/// is actually rather significant.
> 
> Is it possible to write the
> 
>     s/([a-z0-9])/$replace{$1}/g;
> 
> in a tr/// form? It's my understanding at this point (and I could be wrong)
> that you have to write it as an eval, but I don't know whether you can
> assign the result of that to a variable, using =~ .. anyone know?

Yup, you're right, you do need eval to use non-constant strings in tr///.
But fortunately, you only need the eval to be executed once.  For example:

my $reverse = reverse '0' .. '9', 'a'..'z';
my $trans = eval "sub { \$_[0] =~ tr/a-z0-9/$reverse/ }";
while (<DATA>) {
    $trans->($_);
    print;
}

That creates a reference to an anonymous subroutine that, when called,
performs the translate on the first argument.

Then, to avoid so many subroutine dereferences and calls, you can put the
loop inside the eval.  And if you're only going to execute the loop once,
you don't need the anonymous sub, of course; you can just eval the code
directly.  (See TransSub2 below for an example of that.)


And here's another benchmark, with various eval approaches:


Benchmark: timing 8192 iterations of Substitute, Trans, TransEval,
           TransSub1, TransSub2...
Substitute: 26 wallclock secs (24.58 usr +  0.04 sys = 24.62 CPU)
     Trans:  2 wallclock secs ( 1.30 usr +  0.01 sys =  1.31 CPU)
 TransEval:  4 wallclock secs ( 3.96 usr +  0.01 sys =  3.97 CPU)
 TransSub1:  2 wallclock secs ( 2.08 usr +  0.00 sys =  2.08 CPU)
 TransSub2:  2 wallclock secs ( 1.22 usr +  0.00 sys =  1.22 CPU)


#!perl -w
use strict;
use Benchmark;

my @DATA = <DATA>;
my @tmp;

my %replace;
  
@replace{'a' .. 'z'} = reverse 'a' .. 'z';
@replace{'0' .. '9'} = reverse '0' .. '9';

my $reverse = reverse '0' .. '9', 'a'..'z';
my $trans1 = eval "sub { \$_[0] =~ tr/a-z0-9/$reverse/ }";
my $trans2 = eval "sub { foreach (\@_) { tr/a-z0-9/$reverse/ } }";

timethese(1 << (shift || 0),
          {
           'Substitute' =>
           sub {
               for (@tmp = @DATA) {
                   s/([a-z0-9])/$replace{$1}/g;
               }
           },
           'Trans' =>
           sub {
               for (@tmp = @DATA) {
                   tr/abcdefghijklmnopqrstuvwxyz0123456789/zyxwvutsrqponmlkjihgfedcba9876543210/; # damn linewrapping :-|
               }
           },
           'TransEval' =>
           sub {
               eval "for (\@tmp = \@DATA) { \$_ =~ tr/a-z0-9/$reverse/ }";
           },
           'TransSub1' =>
           sub {
               for (@tmp = @DATA) {
                   $trans1->($_);
               }
           },
           'TransSub2' =>
           sub {
               $trans2->(@tmp = @DATA);
           },
          }
);

__END__
dm-)(dome.zip
dm-[dl]-bloodpool.zip
dm-[pcf]biohazard.zip
dm-[tech]labyrinth.zip
dm-[tech]labyrinthv2.zip
dm_lightray.zip
dm-007archives.zip
dm-007basement.zip
dm-007caves.zip
dm-007complex.zip
dm-007egyptian.zip
[snippage...]
dm-wz5-revolution.zip
dm-wzarena1.zip
dm-xenon][.zip
dm-xfiles.zip
dm-xisorspalace.zip
dm-xortion.zip
dm-xtrememeasures.zip
dm-yougan.zip
dm-youtoo.zip
dm-zahltag_ut_addon.zip
dm-zaxisfreestyle.zip
dm-zaxisvirtuality.zip
dm-zeitkind-pro-addon.zip
dm-zyklotron.zip


> Considering I have around 2,630 map names to deal with at present, I'm still
> not certain how much time it saves or not. the .cgi SEEMS to still run
> generally as fast as usual, only taking about 5 secs to iterate through the
> largest segment of the maplist (the UT Deathmatch maps; around 1600-1700 or
> so); the part that takes it the longest, is sending the actual HTML for this
> portion, which tops out around 500K+

In the Benchmark results above, each approach did tr/// on more than
200,000 lines.  Even though the Substitute method is an order of magnitude
slower, that's only half a second for 2,630 lines.  So, you're not looking
at a big time savings in that area.


Ronald

# ===== Want to unsubscribe from this list?
# ===== Send mail with body "unsubscribe" to macperl-request@macperl.org