in reply to Benchmarking for loops?

Looking at the output of B::Concise, there are two extra opcodes in the block version. Compare:

$ perl -MO=Concise -e 'my $total = 0; $total += $_ for(1..1e6);'

to:

$ perl -MO=Concise -e 'my $total = 0; for(1..1e6){$total += $_;}'

At first glance, it looks like the opcodes manage entering and exiting the block scope.

Replies are listed 'Best First'.
Re^2: Benchmarking for loops?
by Fletch (Bishop) on Jul 13, 2004 at 00:10 UTC

    Yup, and similar things will happen with grep EXPR, LIST vs grep BLOCK LIST (as well as the corresponding maps). If you're really looking to eke out those last few cycles and can do without a full block (maybe you can get by with wrapping the grep or map in a block and reusing a lexical scoped to that in the EXPR) this can shave a bit off.

Re^2: Benchmarking for loops?
by ysth (Canon) on Jul 13, 2004 at 00:33 UTC
    What do you see? I see only one opcode difference (an extra nextstate). Which perl version?

      Here's a diff. This is a vanilla 5.8.3 on Linux PPC.

      --- postfix 2004-07-12 22:45:53.000000000 -0700 +++ block 2004-07-12 22:45:44.000000000 -0700 @@ -3,23 +3,23 @@ 2 <;> nextstate(main 1 -e:1) v ->3 5 <2> sassign vKS/2 ->6 3 <$> const(IV 0) s ->4 -4 <0> padsv[$total:1,2] sRM*/LVINTRO ->5 -6 <;> nextstate(main 2 -e:1) v ->7 -7 <;> nextstate(main 2 -e:1) v ->8 +4 <0> padsv[$total:1,4] sRM*/LVINTRO ->5 +6 <;> nextstate(main 3 -e:1) v ->7 j <2> leaveloop vK/2 ->k -c <{> enteriter(next->g last->j redo->d) lKS ->h -- <0> ex-pushmark s ->8 -- <1> ex-list lK ->b -8 <0> pushmark s ->9 -9 <$> const(IV 1) s ->a -a <$> const(NV 1000000) s ->b -b <$> gv(*_) s ->c +b <{> enteriter(next->g last->j redo->c) lKS ->h +- <0> ex-pushmark s ->7 +- <1> ex-list lK ->a +7 <0> pushmark s ->8 +8 <$> const(IV 1) s ->9 +9 <$> const(NV 1000000) s ->a +a <$> gv(*_) s ->b - <1> null vK/1 ->j -i <|> and(other->d) vK/1 ->j +i <|> and(other->c) vK/1 ->j h <0> iter s ->i - <@> lineseq vK ->- -f <2> add[t2] vKS/2 ->g -d <0> padsv[$total:1,2] sRM ->e +c <;> nextstate(main 2 -e:1) v ->d +f <2> add[t4] vKS/2 ->g +d <0> padsv[$total:1,4] sRM ->e - <1> ex-rv2sv sK/1 ->f e <$> gvsv(*_) s ->f g <0> unstack v ->h
        Thanks, somehow I missed that first nextstate. It's still there in bleadperl, and seems totally unnecessary to me.

      I believe (but do not know for absolutely sure) that nextstate is the opcode that sets things up to enter a block or maybe it is exit the block, I can't remember for sure (something is making me think that the op-tree is traversed/processed in post-order rather than pre-order and that might make the difference). If you are really interested you might want to check out Simon Cozens Perl 5 Internals paper, in particular the end part talks about some of the output of the B modules, and how to read/understand them.

      The (overly simplistic) reason why entering an exiting a block has a performance penalty is that perl is lexically scoped. So when entering each block a new lexical scratchpad needs to be set up, and then upon exiting the block all variables need to be restored.

      -stvn
        nextstate preps things between statements. It sets a pointer used to give warn and die messages a line number, clears the tainted-expression flag, resets the stack pointer, and frees any temporary variables generated by the previous statement.

        scoping is done mostly by scope (for a scope containing a single statement), or enter* & leave (for a scope containing multiple statements).