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

I've got a hash of anonymous subs that are called from within a large loop. A different one can be called each time. They look something like this:
package Foo; our %callbacks = ( pig => sub { ... }, cat => sub { ... }, dog => sub { ... } ); while (...) { # do stuff $choice = ...; $callbacks{$choice}->(@args); }
So if another class wants to extend Foo's functionality, they can just do this:
package main; use Foo; $Foo::callbacks{iguana} = sub { ... };
So far so good. But when I tried using -d:DProf to see which of these callbacks was being slow, I don't get anywhere because DProf doesn't help much with anonymous subs. All of them get lumped into one category, and I get something as uninformative as this:
%Time ExclSec CumulS #Calls sec/call Csec/c Name 90.73 0.770 0.648 60783 0.0000 0.0000 Foo::__ANON__
Although there is an option of dprofpp to split the __ANON__ subs into several lines, it still doesn't help me determine which one is the slow one (instead of all subs grouped into the __ANON__ category, I get __ANON__(28), __ANON__(3e), etc). I have to figure out which sub is which by looking at the #Calls column and making an educated guess.

It seems like the only way to get DProf to tell me what sub was called is to (obviously) have a named sub, and to call it by name, not just through a code reference. So I've had to resort to something like this, using symbolic references and fully-qualified sub names:

package Foo; sub Foo::callbacks::pig { ... } # no more hash! sub Foo::callbacks::cat { ... } sub Foo::callbacks::dog { ... } while (...) { # do stuff $choice = ...; # of course, we also validate $choice no strict 'refs'; &{"Foo::callbacks::$choice"}(@args); # I feel so dirty! } package main; ## now extend Foo by doing this: use Foo; sub Foo::callbacks::iguana { ... }
This actually works, and gives good information in DProf, but I'm wondering if this is the best way to get DProf to play nice with my anonymous subs... Also, is this a safe way to keep things, or should I switch back to the hash-based callbacks once I've profiled to my heart's content? Apart from the symbolic reference that I use to make the call, this approach seems reasonable to me.

The only "gotcha" I'm aware of is one that merlyn brought up in the CB a few days ago -- that SUPER:: won't work, as it's based on the package scope, not the actual name of the containing sub. However, there won't be any OO-things happening in these callbacks, and there's certainly no need to bless anyone into the Foo::callbacks namespace.

blokhead

Replies are listed 'Best First'.
Re: Avoiding "Pkg::__ANON__" diagnostics with -d:DProf
by BrowserUk (Patriarch) on May 23, 2003 at 18:53 UTC

    Have you tried using Devel::SmalProf?

    As it profiles the code line-by-line rather than function-by-function, it doesn't have the same trouble with anonymous subs.

    Sample of output

    ================ SmallProf version 1.11 ================ Profile of test3.pl8 + Page 1 =============================================================== +== count wall tm cpu time line 0 0.000000 0.000000 1:$t = sub { 1010 0.000000 0.110000 2: for(1..100) { 11000 0.999900 1.133000 3: for(1..10) { 10000 0.999900 1.170000 4: $x++; 0 0.000000 0.000000 5: } 0 0.000000 0.000000 6: } 1 0.000000 0.000000 7:}; 11 0.000000 0.000000 8:for(1..10) { 10 0.000000 0.000000 9: print $t->(); 0 0.000000 0.000000 10:} 1 0.550701 0.000000 11:print 'Done';

    Be warned. It really does profile every line, modules and pragmas included. And it slows down your program by *a lot*, but the detailed information it produces is well worth the wait.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
Re: Avoiding "Pkg::__ANON__" diagnostics with -d:DProf
by rinceWind (Monsignor) on May 23, 2003 at 17:03 UTC
    This reminds me of a meditation I posted: On debugging coderefs and inside evals, which was more concerned with the perl 5 debugger. But, the same mechanisms are involved in supplying the additional information, and I was getting the same lack of info with caller being '__ANON__'