[comp.lang.perl] next if C VS if

tchrist@convex.com (Tom Christiansen) (05/22/91)

Wondering how badly people who code like C instead of BASIC-PLUS fair
in the timing arena, I wrote a mini-benchmark:

VERSION 1: 
    for ($i = 0; $i < 100000; $i++) {
	if ($i) { next; }
    } 

VERSION 2: 
    for ($i = 0; $i < 100000; $i++) {
	next if $i;
    } 

Consistently I got this kind of timing behavior.

    % time perl ptest.1
    10.670u 9.105s 0:22.58 87.5% 0+0k 0+1io 36pf+0w

    % time perl ptest.2
    5.690u 0.071s 0:06.54 88.0% 0+0k 1+0io 36pf+0w

What the devil is going on here to incur two orders 
of magnitude more system time, not to mention double 
the user time???  Some kind of longjmp foo you don't 
see in the BASIC-PLUS style?  Larry, if you're out
there, what gives?


--tom
--
Tom Christiansen		tchrist@convex.com	convex!tchrist
		"So much mail, so little time." 

ejk@ux2.cso.uiuc.edu (Ed Kubaitis - CSO ) (05/22/91)

You're probably after a detailed explanation, but "Programming Perl" (p 362)
advises:

  o Use modifiers and equivalent && and ||, instead of full-blown conditionals.

    Statement modifiers avoid the overhead of entering and leaving a
    block.... The logical operators are translated internally to the
    equivalent statement modifiers whenever possible.

----------------------------------
Ed Kubaitis (ejk@ux2.cso.uiuc.edu)
Computing Services Office - University of Illinois, Urbana

tchrist@convex.COM (Tom Christiansen) (05/22/91)

From the keyboard of ejk@ux2.cso.uiuc.edu (Ed Kubaitis - CSO ):
:You're probably after a detailed explanation, but "Programming Perl" (p 362)
:advises:

Right -- I'm pretty familiar with the book. :-)  I'm looking for Larry
(or anyone else who's read the code enough) to explain the gory details.

--tom
--
Tom Christiansen		tchrist@convex.com	convex!tchrist
		"So much mail, so little time." 

eay@psych.psy.uq.oz.au (Eric Young) (05/23/91)

In article <1991May22.021106.13838@convex.com>, tchrist@convex.com (Tom Christiansen) writes:
>VERSION 1: 
>    for ($i = 0; $i < 100000; $i++) {
>	if ($i) { next; }
>    } 
>VERSION 2: 
>    for ($i = 0; $i < 100000; $i++) {
>	next if $i;
>    } 
On a sun4/75 - sunOS 4.1.1 - perl v 4.0.1.1 pl 3 with a trace perlscript
I get 10000 'sigcleanup () = 0' system calls when I run VERSION 1
I did not get all these system calls with VERSION 2.
I assume the problem is with next out of the { }.

trace -c version1
  100000 sigcleanup
       8 close
       7 mmap
       5 open
       ...

trace -c version2
       8 close
       7 mmap
       5 open
       ...

eric
---
Eric Young | Systems programmer - Psychology Dept. Queensland Uni.
ARNnet     | eay@psych.psy.uq.oz.au.

lwall@jpl-devvax.jpl.nasa.gov (Larry Wall) (05/23/91)

In article <1991May22.021106.13838@convex.com> tchrist@convex.com (Tom Christiansen) writes:
: Wondering how badly people who code like C instead of BASIC-PLUS fair
: in the timing arena, I wrote a mini-benchmark:
: 
: VERSION 1: 
:     for ($i = 0; $i < 100000; $i++) {
: 	if ($i) { next; }
:     } 
: 
: VERSION 2: 
:     for ($i = 0; $i < 100000; $i++) {
: 	next if $i;
:     } 
: 
: Consistently I got this kind of timing behavior.
: 
:     % time perl ptest.1
:     10.670u 9.105s 0:22.58 87.5% 0+0k 0+1io 36pf+0w
: 
:     % time perl ptest.2
:     5.690u 0.071s 0:06.54 88.0% 0+0k 1+0io 36pf+0w
: 
: What the devil is going on here to incur two orders 
: of magnitude more system time, not to mention double 
: the user time???  Some kind of longjmp foo you don't 
: see in the BASIC-PLUS style?  Larry, if you're out
: there, what gives?

What gives is probably your setjmp/longjmp doing sigblocks while unwinding
the stack.  That would explain the system time.  You also have the overhead
of building and tearing down the block context, including any management of
the setjmp/longjmp.

One thing that's going on here is that "while" loops are optimized:

	while (COND) {
	    ...
	}

turns into, more or less,

	if (COND) {
	    while (1) {
		last unless COND;
	    }
	}

The final statement of the loop is linked back to the first statement
so that we don't have to exit the loop block and restart it each time
through the loop.  The "next if" construct is particularly fast because
it's linked directly to the implied "last" command.  The "if (C) { next; }"
construct actually has to bust out of two blocks, and restart the loop
block from the outside, where the setjmp for the loop is established.

Note that "C && next;" is the exact equivalent of "next if C;" internally.
So you aren't forced to write your conditional last to be fast.

At the expense of a bit of safety, you could probably link in _setjmp/_longjmp
and find a considerable speedup.  You might want to give your signal handler
an alternate stack in that case, however, and longjmp out of the signal
handler that interrupted a longjmp would probably be boomboom time.

Larry