Perl: the Markov chain saw | |
PerlMonks |
This tutorial will cover the basics of profiling your code. I will tell you how to get profiling information and how to interpret it.
I generally try Devel::DProf first. If it doesn't work (i.e., it crashes), I go to Devel::Profiler.
With Devel::DProf, it's
perl -d:DProf foo.pl
With Devel::Profiler, it's
perl -MDevel::Profiler foo.pl
...or you can "use Devel::Profiler" anywhere in your code.
It's worth noting that the profiler will slow down the code you're running, so expect a slow program to get slower while you're trying to figure out why it's so slow. Also, the raw output files can get very large, especially if your program runs a long time.
With profiling turned on, a file called "tmon.out" will be created in the current directory. That file contains all the raw timing information for your run. To get a condensed report, run
dprofpp
That will read "tmon.out" in the current directory and give you a summary of profiling information.
Now that we know how to get profiling data, we have to know what it means. I'll take you through a series of examples to show you the meaning of the numbers you get.
Consider the following program:
main(); sub main { my $now = time(); for( my $x = 0; $x <= 1_000_000; $x++ ) { print scalar localtime, "\n" if $now != time(); $now = time(); } return; }
This is a single call to main(), which loops a million times. On my system, I run this, and I get the following output from dprofpp:
Total Elapsed Time = 1.859881 Seconds User+System Time = 1.389881 Seconds Exclusive Times %Time ExclSec CumulS #Calls sec/call Csec/c Name 98.5 1.370 1.370 1 1.3700 1.3700 main::main 0.72 0.010 0.010 2 0.0050 0.0050 main::BEGIN
Let's talk about what each of those numbers mean.
The next example is meant to show the difference between exclusive seconds and cumulative seconds.
main(); sub main { all_the_work() } sub all_the_work { my $now = time(); for( my $x = 0; $x <= 1_000_000; $x++ ) { print scalar localtime, "\n" if $now != time(); $now = time(); } return; }
In this program, main() does nothing but call a single function all_the_work(), which loops a million times. Here's the data:
Total Elapsed Time = 1.809848 Seconds User+System Time = 1.379848 Seconds Exclusive Times %Time ExclSec CumulS #Calls sec/call Csec/c Name 98.5 1.360 1.360 1 1.3600 1.3600 main::all_the_work 0.00 - 1.360 1 - 1.3600 main::main 0.00 - 0.010 2 - 0.0050 main::BEGIN
Notice that in the ExclSec column, all_the_work takes most of the time, and main takes so little time, it's not even noted. However, in CumulS, both of them take most of the time. The time spent in all_the_work is included in the cumulative time spent in main.
Here's the example:
main(); sub main { do_nothing(); all_the_work(); } sub do_nothing { sleep 5 } sub all_the_work { my $now = time(); for( my $x = 0; $x <= 1_000_000; $x++ ) { print scalar localtime, "\n" if $now != time(); $now = time(); } return; }
In this one, main() calls do_nothing(), which doesn't do any work, but it takes five seconds to finish (using sleep). Then main() calls all_the_work(), which loops a million times.
Here's the data:
Total Elapsed Time = 6.809867 Seconds User+System Time = 1.459867 Seconds Exclusive Times %Time ExclSec CumulS #Calls sec/call Csec/c Name 97.9 1.430 1.430 1 1.4300 1.4300 main::all_the_work 0.68 0.010 0.010 2 0.0050 0.0050 main::BEGIN 0.00 - -0.000 1 - - main::do_nothing 0.00 - 1.430 1 - 1.4300 main::main
Notice that the elapsed time is a lot higher than the user+system time. Notice also that the elapsed time doesn't show up in any of the other statistics. The numbers for do_nothing do not show that five seconds passed while it was "running."
When there's a large gap between elapsed and user+system time like that, it is often useful to run dprofpp with the -r option. Here's the same raw data used above, but displayed with dprofpp -r:
Total Elapsed Time = 6.799829 Seconds Real Time = 6.799829 Seconds Exclusive Times %Time ExclSec CumulS #Calls sec/call Csec/c Name 73.5 5.000 5.000 1 5.0000 5.0000 main::do_nothing 26.1 1.780 1.780 1 1.7800 1.7800 main::all_the_work 0.15 0.010 0.020 2 0.0050 0.0100 main::BEGIN 0.00 - 6.780 1 - 6.7800 main::main
With the -r option, dprofpp reports elapsed times for all functions instead of just the CPU time. With that, it's easy to see that most of the real time was spent in do_nothing().
What causes differences between elapsed time and user+system time? This can be anything that your program waits on when it's not actively running. Typically this is one of:
The dprofpp tool has options to make its output more useful in different situations. By default it will show you the top 15 functions sorted by user+system time. With the -g option, you can have dprofpp focus on one function. With the -O option, you can have it show any number of functions.
There are also options to show call trees and do other interesting things. See the dprofpp documentation for the full scoop.
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: Profiling your code.
by missingthepoint (Friar) on Jan 12, 2009 at 03:01 UTC | |
Re: Profiling your code.
by dHarry (Abbot) on Feb 06, 2009 at 10:46 UTC | |
by jplindstrom (Monsignor) on Feb 06, 2009 at 14:40 UTC | |
Re: Profiling your code.
by targetsmart (Curate) on Jan 28, 2009 at 06:03 UTC |