Outaspace has asked for the wisdom of the Perl Monks concerning the following question:

Hello fellow Monks,

I just wondered if it is possible to have trace like macros in a Perl script. By now I do this:
use constant DEBUG => 1; print "Test something" if (DEBUG);
But I would rather use something like:
use constant DEBUG => 1; DEBUG("Test something");
but without the overhead of a function call. I already looked at some modules at CPAN (like Trace), but they allways seem to call functions even if DEBUG = 0 and in a large Perl script it gives me to much overhead (especially when using the DB Module).
So now I ask you, it is possible to do the second variant without calling a sub if DEBUG = 0 ?

Andre

Replies are listed 'Best First'.
Re: Debug Macro
by Ovid (Cardinal) on Mar 27, 2007 at 09:47 UTC

    It's not perfect, but here's a hack on Devel::Trace I once threw together:

    package Devel::Trace; $VERSION = '0.10'; $TRACE = 1; $REGEX = qr//; # This is the important part. The rest is just fluff. sub DB::DB { return unless $TRACE; my ( $p, $f, $l ) = caller; my $code = \@{"::_<$f"}; my $line = ">> $f:$l: $code->[$l]"; print STDERR $line if $line =~ $REGEX; } sub import { my $package = shift; while ( defined( $_ = shift @_ ) ) { if ( $_ eq 'trace' ) { my $caller = caller; *{ $caller . '::trace' } = \&{ $package . '::trace' }; } elsif ( $_ eq 'match' ) { my $regex = shift; $REGEX = qr/$regex/; } else { use Carp; croak "Package $package does not export `$_'; aborting"; } } } my %tracearg = ( 'on' => 1, 'off' => 0 ); sub trace { my $arg = shift; $arg = $tracearg{$arg} while exists $tracearg{$arg}; $TRACE = $arg; } 1;

    That's "not ready for prime time", but now I can do this:

    perl -d:Trace=match,some_regex some_prog.pl 2>logfile

    And only lines which match the regex are printed. That's handy if you want to limit it to a particular package. It's not perfect, but it was a good enough hack to let me see a nasty execution flow error that I was having trouble following in the debugger (the debugger can be a right pain to use with interactive programs).

    You could probably start hacking in this to get something closer to what you want.

    Cheers,
    Ovid

    New address of my CGI Course.

Re: Debug Macro
by sgt (Deacon) on Mar 27, 2007 at 09:43 UTC

    you can use a full-blown logging system like log4p Log::Log4perl o Log::Dispatch o something like Smart::Comments to selectively enable some of your comments as print statements.

    hth --stephan

      No this doesn't help. You're still paying the cost of a function call. And function calls are s-l-o-w in Perl.

      I recently encountered a program of which 20% of the run time was being absorbed by a debug() that was being called to do nothing. (postgrey, in case you were wondering).

      My solution was to change the code to

      debug("foo") if DEBUG;

      ... but only because I was worried about performance. From a readability point of view, it sucks.

      True macros would be a nice addition to Perl. I know that there's a Macro module that purports to do just this, but I have never used it.

      • another intruder with the mooring in the heart of the Perl

        If you want a nice project, you could write PPI::Macro, a macro system based on PPI. Not sure how much work it would take, but I know that many folks would be quite happy with this.

        (Or you could wait for Perl 6 and its true macros, but your beer might get warm while you're waiting)

        Cheers,
        Ovid

        New address of my CGI Course.

        No this doesn't help. You're still paying the cost of a function call. And function calls are s-l-o-w in Perl.

        actually with filtering you don't pay for it, it is there or not (a bit like when you use dynamic linking and you switch some instrumenting lib for a non-instrumenting one -- so you can use a wrapper)

        then with code like this

         foo() if $foo;

        why do you pay for a function call?

        anyway your comment reminds of that perl command line flag (-P) that calls the C preprocessor on your code... maybe it could be useful for this can of debugging?! (chess notation)

        cheers --stephan p.s by the way for me true macros are lispish macros, the others do textual substitution (meaning not caring about syntax) and that can break easily like perl filters or cpp)
Re: Debug Macro
by ferreira (Chaplain) on Mar 27, 2007 at 14:47 UTC

    That looks like a good use for a solution with Module::Compile. The original source would be manipulated (via PPI or whatever) and a compiled version with DEBUG() calls replaced by print @_ if 1 would be written as a .pmc files.

    The obvious drawback is that once enabled in a program run, the macros won't see runtime changes. But that's coherent with the desire to eliminate the overhead of function calls, since we suppose that the mechanism for recompiling macros at runtime would be as heavy or even worse.

    That would make feasible to build constructs that worked for instance like use which is kind of a macro for

    BEGIN { require $foo; $foo->import(@args); # if any args }

    Hum. May be a good idea or not.

      Hi,

      do you have any experience with Module::Compile ? I looked at it once, because precompiling Modules would be a great advantage , but I couldn't figure out who to use it. Do you have any example or a good web resource that I can look at? Would appreciate it a lot.

      Andre