Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Pontificating on Perl Profiling


Published on

Dyn Inc's VP Of Engineering Lisa Hagemann's Scale9x presentation, 'Pontificating on Perl Profiling', a session that will guide the beginner Perl user through the whys and hows of code profiling.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

Pontificating on Perl Profiling

  1. 1. Pontificating on Perl Profiling Lisa Hagemann VP Engineering, Dyn Inc. @lhagemann @dyninc
  2. 2. What is Profiling?A way to evaluate what is yourprogram doing.Commonly evaluates the behavior ofthe program, measuring frequency andduration of different call pathsincluding the call paths.Used to evaluate areas ripe foroptimization.
  3. 3. What is Benchmarking? Defining a measurement for comparison Benchmark time, memory, database calls Provides data, not answers
  4. 4. TMTOWTDIThere’s More Than One Way To Do ItWhat’s the Best way to do it? use Benchmark;
  5. 5. use Benchmark;perldoc BenchmarkBuilt in module which encapsulates anumber of routines to help you figureout how long it takes to execute somecode.
  6. 6. 1 #!/usr/bin/env perl use Benchmark; 2 Built in module 3 #List::Util::first() is slower than a for loop: encapsulates a number of 4 5 use Benchmark qw(:all :hireswallclock); routines to help you 6 use List::Util qw(first); figure out how long it 7 takes to execute some 8 my @list = 1..100; code. 910 my $results = timethese(1_000_000, { timethese (COUNT,11 first => sub { CODEHASHREF,[STYLE])12 my $f; Time COUNT iterations of13 $f = first { $_ == 5 } @list;14 return $f; CODEHASHREF.15 },16 loop => sub { cmpthese ( COUNT,17 my $f; CODEHASHREF, [ STYLE ] )18 for (@list) { or19 if ($_ == 5) { cmpthese20 $f = $_; ( RESULTSHASHREF,21 last; [ STYLE ] )22 } Uses timethese (or the23 }24 return $f; results of a timethese()25 }, call and outputs in a26 }); comparison table2728 cmpthese($results);
  7. 7. $ perl simpleloop2.plBenchmark: timing 1000000 iterations of first, loop... first: 1.59767 wallclock secs ( 1.48 usr + 0.01 sys = 1.49 CPU) @671140.94/s (n=1000000) loop: 1.08002 wallclock secs ( 0.92 usr + 0.01 sys = 0.93 CPU) @1075268.82/s (n=1000000) Rate first loopfirst 671141/s -- -38%loop 1075269/s 60% --output from timethese() is the default style ‘auto’key of coderef followed by the times for wallclock time,user time, and system time followed by the rateoutput from cmpthese() gives us a comparison chart sortedfrom slowest to fastest, and shows the percent speeddifference between each pair of tests.
  8. 8. Things to considerFocus on code that will be executedthe most (think loops) Are there expensive comparisons/computations that can be cached sensibly? Are there chains of comparisons that arent optimized statistically?Unnecessary sorting?Are you reinventing the wheel?
  9. 9. An Example simple text parsing scriptUses a package for creating objectsSimple parsing of a zone file intoDNS records: hash ‘em if we know how20K lines to parse
  10. 10. 1 #!/usr/bin/env perl -l use Benchmark; 2 use strict; Built in module encapsulates 3 use warnings; a number of routines to help 4 use RR; you figure out how long it 5 use Net::DNS::RR; takes to execute some code. 6 use Benchmark qw(:hireswallclock); 7 new(): 8 my $t0 = new Benchmark; Returns the current time as 9 while (my $line = <>) { an object the Benchmark10 chomp($line); methods use1112 # Ignore blank lines timediff( T1 , T2 ):13 next unless $line; A Benchmark object14 representing the difference15 my $obj = RR->new($line); between two Benchmark times,16 suitable for passing to17 # Generate Net::DNS::RRs timestr();18 my $rr;19 if ($obj->as_hash()) { timestr ( TIMEDIFF, [ STYLE,20 $rr = Net::DNS::RR->new($obj->as_hash()); [ FORMAT ] ] ):21 } else { returns a string in the22 $rr = Net::DNS::RR->new($obj->as_string()); requested format suitable for23 } printing. Format defaults to24 } ‘%5.2f’.25 my $t1 = new Benchmark;26 my $runtime = timestr(timediff($t1,$t0));2728 print "Zone parse time: $runtime";
  11. 11. Benchmark$ perl parse time: 4.61972 wallclock secs ( 4.55 usr + 0.02 sys = 4.57 CPU) 4.61 seconds to process the file Good? Bad? Can it be better?
  12. 12. Profiling PackagesDevel::DProf Built in, produces an output file, utility to format that watches subroutine calls noting elapsed time totals each run into a total time spent in the subroutineDevel::SmallProf Install from CPAN Human readable output file, clunky for programs with imported librariesDevel::NYTProf
  13. 13. Devel::NYTProf from CPAN is apowerful, fast, feature-rich perlsource code profiler*Statement and Subroutine profilingshowing Inclusive and Exclusive Time Inclusive includes time spent in subroutines called from within another subroutineHandy report HTML generator
  14. 14. Run the script with Devel::NYTProf$ perl -d:NYTProf -d flag starts the debug mode which is shorthand for -MDevel:: loads the module Devel::NYTProf before running the provided script produces nytprof.out file Adds a little overhead
  15. 15. $ nytprofhtml -o ./nytprof_run1 -f ./nytprof_run1.outReading ./nytprof_run1.outProcessing ./nytprof_run1.out dataWriting sub reports to ./nytprof_run1 directory 100% ...Writing block reports to ./nytprof_run1 directory 100% ...Writing line reports to ./nytprof_run1 directory nytprofhtml generates HTML report Useful flags for keeping multiple runs -f --file: file name to use; defaults to ./nytprof.out -o --out: the output directory to place all the html files
  16. 16. 1 #!/usr/bin/perl -l 2 3 use strict; 4 use warnings; 5 6 use RR; 7 use Net::DNS::RR; 8 9 use Benchmark qw(:hireswallclock);1011 my $t0 = new Benchmark;1213 while (my $line = <>) {14 chomp($line);1516 # Ignore blank lines17 next unless $line;1819 my $obj = RR->new($line);2021 # Generate Net::DNS::RRs22 my $rr = Net::DNS::RR->new($obj->as_string());23 }2425 my $t1 = new Benchmark;26 my $runtime = timestr(timediff($t1,$t0));2728 print "Zone parse time: $runtime";
  17. 17. Benchmark$ perl parse time: 2.03943 wallclock secs ( 2.01 usr + 0.01 sys = 2.02 CPU) 4.61 seconds down to 2.03 seconds > 50% speed up! Any others?$ perl -d:NYTProf parse time: 10 wallclock secs ( 9.43 usr + 0.03 sys = 9.46 CPU)$ nytprofhtml -o ./nytprof_run2 -f ./nytprof_run2.out --openReading ./nytprof_run2.outProcessing ./nytprof_run2.out dataWriting sub reports to ./nytprof_run2 directory 100% ...Writing block reports to ./nytprof_run2 directory 100% ...Writing line reports to ./nytprof_run2 directory 100% ...
  18. 18. Net::DNS presentation2wirename2labels wire2presentation stripdot Net::DNS::RR::new_from_string
  19. 19. 1 #!/usr/env/bin perl -l 2 3 use strict; 4 use warnings; 5 6 use RR; 7 use Net::DNS; 8 use Net::DNS::RR; 9 use Benchmark qw(:hireswallclock);1011 sub stripdot {12 my ($str) = @_;13 #Replace any period at the end of a label that is not escaped by 14 $str =~ s{(?<!).s*$}{};15 return $str;16 }1718 #override the Net::DNS stripdot19 *Net::DNS::RR::stripdot = &stripdot;2021 my $t0 = new Benchmark;2223 while (my $line = <>) { ...33 }3435 my $t1 = new Benchmark;36 my $runtime = timestr(timediff($t1,$t0));37 print "Zone parse time: $runtime";
  20. 20. Benchmark$ perl Net::DNS::RR::stripdot redefined at line 19.Zone parse time: 1.10183 wallclock secs ( 1.10 usr + 0.00 sys = 1.10 CPU) 2.03 seconds to 1.10 seconds Another ~50% speed up!$ perl -d:NYTProf Net::DNS::RR::stripdot redefined at line 19.Zone parse time: 3 wallclock secs ( 3.51 usr + 0.02 sys = 3.53 CPU)$ nytprofhtml -o ./nytprof_run3 -f ./nytprof_run3.out --openReading ./nytprof_run3.outProcessing ./nytprof_run3.out dataWriting sub reports to ./nytprof_run3 directory 100% ...Writing block reports to ./nytprof_run3 directory 100% ...Writing line reports to ./nytprof_run3 directory 100% ...
  21. 21. 77% speed upTotal run time: 4.61 seconds down to1.10 secondsTime in external module reduced fromnearly 5 secs to 6ms. This includes the overhead of calling the profiling module
  22. 22. ReferencesCPAN Best Practices by Damian ConwayModern Perl by chromatic