• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Pontificating on Perl Profiling
 

Pontificating on Perl Profiling

on

  • 1,836 views

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.

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.

Statistics

Views

Total Views
1,836
Views on SlideShare
1,836
Embed Views
0

Actions

Likes
0
Downloads
1
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Quick Intro of me and what Dyn Does\nOpen Source Company: BIND, Postfix, MySQL, Perl, Python, FreeBSD\n
  • Assumptions, Hypothesizing\n\n
  • Slow? What is Slow? Compared to what? \nBenchmark memory, database calls, more than just speed (but that is what I focus on)\n\n
  • Benchmarking == data\nuse the data to made decisions\n
  • \n
  • Make sure you read the perl doc, as not all methods are exported, you need to explicitly import them as I have here\n:hireswallclock ... uses Time::HiRes gives us microseconds, the samples are small enough that the microseconds are important\n
  • \n
  • type to id method ... checking the edge cases first ... Changing the logic to start with the most common events saved time \n
  • Somewhat contrived ... I wanted to make it a simple example, and remove any database dependancies ... but it is based on a specific functionality we had in our application.\nBasis of the script is to parse through a zone file, and create DNS record objects. For our example we are not transmitting these records, we just want to get the zone file parsed into usable pieces.\n
  • Use Benchmark in order to get some timing data about how long it takes to parse this 20K line zone file.\nThe methods I’m using are exported by default, but I am importing :hireswallclock again in order to get microsecond measurements.\n
  • Note the output ... the Benchmark::timestr method handles the formatting of the time for our output\nyou can format it using the standard printf formats, this is the default floating point 5 decimal places\nThis is where Profiling comes into play\n
  • DProf: On my Mac install the dprofpp was not executable and was owned by root\n\n
  • \n
  • \n
  • \n
  • The overhead I talked about ... our 4.6 seconds is now 13 seconds\nWe know our script is making new DNS record objects ... look at the two different new calls\nDo we really care if they use a hash? probably not .... overhead worth it?\n
  • \n
  • \n
  • new_from_string ... 5.27s that’s about half of what the two calls were from our first run\nour overall time in the Net::DNS module has gone down\nwhat are those presentation calls? Not alot of time, but the number of times called is 3x the number of lines in our file? what’s up with that. Let’s explore.\n
  • \n
  • override the subroutine by redifining it in the Symbol Table\nNOTE: Generally this is bad practice, careful consideration and good documentation, careful implementation\n
  • \n
  • \n
  • \n
  • \n

Pontificating on Perl Profiling Pontificating on Perl Profiling Presentation Transcript

  • Pontificating on Perl Profiling Lisa Hagemann VP Engineering, Dyn Inc. @lhagemann @dyninc
  • 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.
  • What is Benchmarking? Defining a measurement for comparison Benchmark time, memory, database calls Provides data, not answers
  • TMTOWTDIThere’s More Than One Way To Do ItWhat’s the Best way to do it? use Benchmark;
  • use Benchmark;perldoc BenchmarkBuilt in module which encapsulates anumber of routines to help you figureout how long it takes to execute somecode.
  • 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);
  • $ 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.
  • 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?
  • 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
  • 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";
  • Benchmark$ perl zoneparse.pl zone.com.txtZone 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?
  • 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
  • Devel::NYTProfhttp://search.cpan.org/~timb/Devel-NYTProf-4.06/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
  • Run the script with Devel::NYTProf$ perl -d:NYTProf zoneparse.pl zone.com.txt -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
  • $ 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
  • 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";
  • Benchmark$ perl zoneparse2.pl zone.com.txtZone 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 zoneparse2.pl zone.com.txtZone 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% ...
  • Net::DNS presentation2wirename2labels wire2presentation stripdot Net::DNS::RR::new_from_string
  • 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";
  • Benchmark$ perl zoneparse3.pl zone.com.txtSubroutine Net::DNS::RR::stripdot redefined at zoneparse3.pl 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 zoneparse3.pl zone.com.txtSubroutine Net::DNS::RR::stripdot redefined at zoneparse3.pl 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% ...
  • 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
  • ReferencesCPAN http://search.cpan.org/~timb/Devel-NYTProf-4.06/ http://search.cpan.org/~salva/Devel-SmallProf-2.02/PerlMonks.orgPerl Best Practices by Damian ConwayModern Perl by chromatic