http://www.perlmonks.org?node_id=113154

I see often on the CB people talking of using print "whatever" if $DEBUG. The (admittedly small) problem: the debug code is compiled in, even if $DEBUG is later set to 0 in the life-cycle of the program

One may prefer to say:

sub DEBUG() { 1 } ... print "whatever" if DEBUG;
In the compiled code, there is no subroutine call but a constant value. So when DEBUG is defined to be 1, peephole optmization makes the print "whatever" inconditional. When DEBUG is defined to be 0, the whole printing statement is optimized out. See the Camel p 229 for the definition of "Inlining Constant Functions".

I am probably not the first coming with this idea. So I would be happy to add credit and pointers.

-- stefp

Replies are listed 'Best First'.
Re: inlned DEBUG constant versus $DEBUG
by dragonchild (Archbishop) on Sep 18, 2001 at 20:37 UTC
    C's method is to use preprocessing, which I've heard is coming out (in some form) in Perl6. Thus, if DEBUG is set to 0, the compiler would just skip over that code and not even compile it to optimize it away.

    As a note, just do

    use constant DEBUG => (1);
    if you're in 5.6.0 or higher. (It may be available earlier, but I'm not sure.)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      If you are wondering whether use constant is available in versions prior to 5.6.0, it was introduced in 5.004. In fact if you were using the late 5.003 versions (circa 5.003_90+) it was there in betas leading up to 5.004.

      Nevertheless, it's been there for a long time, at least as far as scalars go. Constant hashes and arrays didn't work correctly until around 5.005_03.

      --
      g r i n d e r
      You can use a pre-processor with Perl too. See Filter::cpp.
Re: inlined DEBUG constant versus $DEBUG
by derby (Abbot) on Sep 19, 2001 at 17:44 UTC
    stefp,

    Let's look at the numbers:

    #!/usr/local/bin/perl use Benchmark; use constant DEBUG_C => (1); sub DEBUG_S() { 1 } $DEBUG_V = 1; timethese( 4000000, { 'constant' => sub { my $x = 1 if DEBUG_C; my $y=2; }, 'subroutine' => sub { my $x = 1 if DEBUG_S; my $y=2; }, 'variable' => sub { my $x = 1 if $DEBUG_V; my $y=2; }, } );
    produces the following (for DEBUG set to 1 and 0)
    DEBUG 0, Run 1
    Benchmark: timing 4000000 iterations of constant, subroutine, variable...
      constant:  3 wallclock secs ( 2.00 usr +  0.01 sys =  2.01 CPU) @ 1990049.75/s (n=4000000)
    subroutine:  3 wallclock secs ( 1.99 usr +  0.00 sys =  1.99 CPU) @ 2010050.25/s (n=4000000)
      variable:  5 wallclock secs ( 3.93 usr +  0.00 sys =  3.93 CPU) @ 1017811.70/s (n=4000000)
    
    DEBUG 0, Run 2
    Benchmark: timing 4000000 iterations of constant, subroutine, variable...
      constant:  1 wallclock secs ( 1.99 usr +  0.00 sys =  1.99 CPU) @ 2010050.25/s (n=4000000)
    subroutine:  1 wallclock secs ( 2.13 usr +  0.00 sys =  2.13 CPU) @ 1877934.27/s (n=4000000)
      variable:  3 wallclock secs ( 3.85 usr +  0.00 sys =  3.85 CPU) @ 1038961.04/s (n=4000000)
    
    DEBUG 0, Run 3
    Benchmark: timing 4000000 iterations of constant, subroutine, variable...
      constant:  1 wallclock secs ( 2.07 usr +  0.00 sys =  2.07 CPU) @ 1932367.15/s (n=4000000)
    subroutine:  1 wallclock secs ( 2.19 usr +  0.00 sys =  2.19 CPU) @ 1826484.02/s (n=4000000)
      variable:  3 wallclock secs ( 3.78 usr +  0.00 sys =  3.78 CPU) @ 1058201.06/s (n=4000000)
    
    DEBUG 1, Run 1
    Benchmark: timing 4000000 iterations of constant, subroutine, variable...
      constant:  8 wallclock secs ( 7.47 usr +  0.00 sys =  7.47 CPU) @ 535475.23/s (n=4000000)
    subroutine:  8 wallclock secs ( 7.49 usr +  0.00 sys =  7.49 CPU) @ 534045.39/s (n=4000000)
      variable:  9 wallclock secs ( 9.13 usr +  0.00 sys =  9.13 CPU) @ 438116.10/s (n=4000000)
    
    DEBUG 1, Run 2
    Benchmark: timing 4000000 iterations of constant, subroutine, variable...
      constant:  8 wallclock secs ( 7.53 usr +  0.00 sys =  7.53 CPU) @ 531208.50/s (n=4000000)
    subroutine:  7 wallclock secs ( 7.41 usr +  0.00 sys =  7.41 CPU) @ 539811.07/s (n=4000000)
      variable:  8 wallclock secs ( 9.27 usr +  0.00 sys =  9.27 CPU) @ 431499.46/s (n=4000000)
    
    DEBUG 2, Run 3
    Benchmark: timing 4000000 iterations of constant, subroutine, variable...
      constant:  8 wallclock secs ( 7.38 usr +  0.00 sys =  7.38 CPU) @ 542005.42/s (n=4000000)
    subroutine:  8 wallclock secs ( 7.23 usr +  0.00 sys =  7.23 CPU) @ 553250.35/s (n=4000000)
      variable:  9 wallclock secs ( 9.06 usr +  0.00 sys =  9.06 CPU) @ 441501.10/s (n=4000000)
    
    Looking at those numbers - sure $DEBUG is a bit slower but I'd say the savings are a wash - especially if there's some network or database code also in the script. The amount of time you save from not using $DEBUG is really down in the noise. The key here is to choose one method and be consistent with it's application across all scripts/modules in your project(s).

    -derby

      I never claimed significant speed improvement. What I had in mind is debugging thru the perl debugger. In that case the print statement becomes noise. I don't want anything to print, I even don't want to bother to go thru the statement that contains the print. Oddly, with use constant DEBUG => 0 I indeed step thru the statement that contains the print:  print "whatever\n" if DEBUG.
      Worse I also step thru one line of constant.pm!

      With sub DEBUG() { 0 } I still step thru the statement that contains the print. When debugging one goes from one nextstate opcode to the next. We see that consecutive nextstate statements are not fusionned as I expected them to be:

      Both oneliners give me the same tree: perl -e ' sub DEBUG() { 0 } ; use O qw( Concise -exec); print "toto" if DEBUG; print "toto" if DEBUG'

      perl -e ' use constant DEBUG =>0; use O qw( Concise -exec); print "tot +o" if DEBUG; print "toto" if DEBUG' 1 <0> enter 2 <;> nextstate(main 1 -e:1) v 3 <;> nextstate(main 1 -e:1) v 4 <@> leave[t1] vKP/REFC

      I don't understand how I get thru one line of constant.pm when debugging using constants!!!

      I tested using perl 5.6.1

      -- stefp

        stefp,

        That's why I tend to favor 'n' over 's'. However, when I debug code that contains

        sub DEBUG () { 0 }
        I still step through the DEBUG subroutine. Which is what I would expect while debugging. Try:

        perl -de 'use constant DEBUG =>0; use O qw( Concise -exec); print "toto" if DEBUG; print "toto" if DEBUG'

        perl -de 'sub DEBUG() { 0 }; use O qw( Concise -exec); print "toto" if DEBUG; print "toto" if DEBUG'

        -derby

Using CONSTANTS in perl
by doran (Deacon) on Sep 21, 2001 at 08:44 UTC
      The link you posted has changed, the article has been moved here.
Re: inlined DEBUG constant versus $DEBUG
by bluto (Curate) on Sep 20, 2001 at 05:00 UTC
    I usually end up using the variable rather than the constant since it's very easy to alter this using a command line option (e.g. the ubiquitous '-d'). I hate to edit code to get additional diagnostics printed out for a program that is giving me problems (esp. on a production machine). If the program is large and I have a good logging mechanizm built in, then a constant is usually fine though.

    Just curious, does anyone know if there is an easy, clean way of doing this with 'use constant'?

    bluto

Re: inlined DEBUG constant versus $DEBUG
by mugwumpjism (Hermit) on Sep 19, 2001 at 19:09 UTC

    Here's an idea:

    sub say { print "$_[0]\n"; } sub moan { print STDERR "WARNING: $_[0]\n"; } sub mutter { print "debug: $_[0]\n"; } if (!$DEBUG) { eval "sub mutter { }"; }

    Then the code reads well too :-)