Skip to content

Loading…

Optimize flow analysis (~25% faster). Report count of skipped lines, if any. #10

Merged
merged 2 commits into from

2 participants

@timbunce

Optimizations to speed processing of large files and/or slow machines.

timbunce added some commits
@timbunce timbunce Add options for tunables. Add more tunables. Commify sample count. c1059bc
@timbunce timbunce Optimize flow anlysis (~25% faster). Report count of skipped lines, i…
…f any.

Using dumbench (https://metacpan.org/module/Dumbbench) to run flamegraph
on a file with ~140,000 lines:
old: Rounded run time per iteration: 3.472e+00 +/- 1.7e-02 (0.5%)
new: Rounded run time per iteration: 2.618e+00 +/- 1.3e-02 (0.5%)
daa7cf6
@brendangregg

impressive, thanks!

@brendangregg brendangregg merged commit 0bc421a into brendangregg:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 17, 2013
  1. @timbunce
  2. @timbunce

    Optimize flow anlysis (~25% faster). Report count of skipped lines, i…

    timbunce committed
    …f any.
    
    Using dumbench (https://metacpan.org/module/Dumbbench) to run flamegraph
    on a file with ~140,000 lines:
    old: Rounded run time per iteration: 3.472e+00 +/- 1.7e-02 (0.5%)
    new: Rounded run time per iteration: 2.618e+00 +/- 1.3e-02 (0.5%)
Showing with 47 additions and 26 deletions.
  1. +47 −26 flamegraph.pl
View
73 flamegraph.pl
@@ -47,17 +47,35 @@
#
# CDDL HEADER END
#
+# 17-Mar-2013 Tim Bunce Added options and more tunables.
# 15-Dec-2011 Dave Pacheco Support for frames with whitespace.
# 10-Sep-2011 Brendan Gregg Created this.
use strict;
+use Getopt::Long;
+
# tunables
my $fonttype = "Verdana";
my $imagewidth = 1200; # max width, pixels
my $frameheight = 16; # max height is dynamic
my $fontsize = 12; # base text size
my $minwidth = 0.1; # min function width, pixels
+my $titletext = "Flame Graph"; # centered heading
+my $nametype = "Function:"; # what are the names in the data?
+my $countname = "samples"; # what are the counts in the data?
+
+GetOptions(
+ 'fonttype=s' => \$fonttype,
+ 'width=i' => \$imagewidth,
+ 'height=i' => \$frameheight,
+ 'fontsize=i' => \$fontsize,
+ 'minwidth=f' => \$minwidth,
+ 'title=s' => \$titletext,
+ 'nametype=s' => \$nametype,
+ 'countname=s' => \$countname,
+) or exit 1;
+
# internals
my $ypad1 = $fontsize * 4; # pad top, include title
@@ -134,53 +152,54 @@ sub color {
my %Tmp;
sub flow {
- my ($a, $b, $v) = @_;
- my @A = split ";", $a;
- my @B = split ";", $b;
+ my ($last, $this, $v) = @_;
- my $len_a = $#A;
- my $len_b = $#B;
+ my $len_a = @$last - 1;
+ my $len_b = @$this - 1;
$depthmax = $len_b if $len_b > $depthmax;
my $i = 0;
- my $len_same = 0;
+ my $len_same;
for (; $i <= $len_a; $i++) {
last if $i > $len_b;
- last if $A[$i] ne $B[$i];
+ last if $last->[$i] ne $this->[$i];
}
$len_same = $i;
for ($i = $len_a; $i >= $len_same; $i--) {
- my $k = "$A[$i]--$i";
+ my $k = "$last->[$i]--$i";
# a unique ID is constructed from func--depth--etime;
# func-depth isn't unique, it may be repeated later.
- $Node{"$k--$v"}->{stime} = $Tmp{$k}->{stime};
- delete $Tmp{$k}->{stime};
+ $Node{"$k--$v"}->{stime} = delete $Tmp{$k}->{stime};
delete $Tmp{$k};
}
for ($i = $len_same; $i <= $len_b; $i++) {
- my $k = "$B[$i]--$i";
+ my $k = "$this->[$i]--$i";
$Tmp{$k}->{stime} = $v;
}
+
+ return $this;
}
# Parse input
my @Data = <>;
-my $last = "";
+my $last = [];
my $time = 0;
+my $ignored = 0;
foreach (sort @Data) {
chomp;
my ($stack, $samples) = (/^(.*)\s+(\d+)$/);
- $stack =~ s/</(/g;
- $stack =~ s/>/)/g;
- $stack = ";$stack";
- next unless defined $samples;
- flow($last, $stack, $time);
+ unless (defined $samples) {
+ ++$ignored;
+ next;
+ }
+ $stack =~ tr/<>/()/;
+ $last = flow($last, [ '', split ";", $stack ], $time);
$time += $samples;
- $last = $stack;
}
-flow($last, "", $time);
+flow($last, [], $time);
+warn "Ignored $ignored lines with invalid format\n" if $ignored;
$timemax = $time or die "ERROR: No stack counts found\n";
# Draw canvas
@@ -203,7 +222,7 @@ sub flow {
<![CDATA[
var details;
function init(evt) { details = document.getElementById("details").firstChild; }
- function s(info) { details.nodeValue = info; }
+ function s(info) { details.nodeValue = "$nametype " + info; }
function c() { details.nodeValue = ' '; }
]]>
</script>
@@ -216,16 +235,14 @@ sub flow {
$im->colorAllocate(40, 40, 40),
$im->colorAllocate(160, 160, 160),
);
-$im->stringTTF($black, $fonttype, $fontsize + 5, 0.0, int($imagewidth / 2), $fontsize * 2, "Flame Graph", "middle");
-$im->stringTTF($black, $fonttype, $fontsize, 0.0, $xpad, $imageheight - ($ypad2 / 2), 'Function:');
-$im->stringTTF($black, $fonttype, $fontsize, 0.0, $xpad + 60, $imageheight - ($ypad2 / 2), " ", "", 'id="details"');
+$im->stringTTF($black, $fonttype, $fontsize + 5, 0.0, int($imagewidth / 2), $fontsize * 2, $titletext, "middle");
+$im->stringTTF($black, $fonttype, $fontsize, 0.0, $xpad, $imageheight - ($ypad2 / 2), " ", "", 'id="details"');
# Draw frames
foreach my $id (keys %Node) {
my ($func, $depth, $etime) = split "--", $id;
die "missing start for $id" if !defined $Node{$id}->{stime};
my $stime = $Node{$id}->{stime};
- my $samples = $etime - $stime;
my $x1 = $xpad + $stime * $widthpertime;
my $x2 = $xpad + $etime * $widthpertime;
@@ -235,16 +252,20 @@ sub flow {
my $y1 = $imageheight - $ypad2 - ($depth + 1) * $frameheight + 1;
my $y2 = $imageheight - $ypad2 - $depth * $frameheight;
+ my $samples = $etime - $stime;
+ (my $samples_txt = $samples) # add commas per perlfaq5
+ =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;
+
my $info;
if ($func eq "" and $depth == 0) {
- $info = "all samples ($samples samples, 100%)";
+ $info = "all ($samples_txt $countname, 100%)";
} else {
my $pct = sprintf "%.2f", ((100 * $samples) / $timemax);
my $escaped_func = $func;
$escaped_func =~ s/&/&amp;/g;
$escaped_func =~ s/</&lt;/g;
$escaped_func =~ s/>/&gt;/g;
- $info = "$escaped_func ($samples samples, $pct%)";
+ $info = "$escaped_func ($samples_txt $countname, $pct%)";
}
$im->filledRectangle($x1, $y1, $x2, $y2, color("hot"), 'rx="2" ry="2" onmouseover="s(' . "'$info'" . ')" onmouseout="c()"');
Something went wrong with that request. Please try again.