diff --git a/README.md b/README.md index 1aa3ecda..48532990 100644 --- a/README.md +++ b/README.md @@ -223,3 +223,18 @@ Take a look at the demo directory for an example: palette-example-working.svg palette-example-broken.svg + +Streaming mode +============== + +`stackcollapse-perf.pl` provides a streaming mode. This mode output the +stack sample lines in a streaming fashion. This can be used to efficiently +subsample from a large capture: + +~~~sh +perf script | +./stackcollapse-perf.pl --stream | +shuf -n 50000 | # Take 50000 random stack samples +./stackcollapse-sum.pl | # Merge identical stack samples +./flamegraph.pl +~~~ diff --git a/stackcollapse-perf.pl b/stackcollapse-perf.pl index 652b113e..752c8a78 100755 --- a/stackcollapse-perf.pl +++ b/stackcollapse-perf.pl @@ -88,6 +88,7 @@ sub remember_stack { my $show_inline = 0; my $show_context = 0; +my $streaming = 0; # stream the stacks without summing them my $srcline_in_input = 0; # if there are extra lines with source location (perf script -F+srcline) GetOptions('inline' => \$show_inline, @@ -99,7 +100,8 @@ sub remember_stack { 'all' => \$annotate_all, 'tid' => \$include_tid, 'addrs' => \$include_addrs, - 'event-filter=s' => \$event_filter) + 'event-filter=s' => \$event_filter, + 'streaming' => \$streaming) or die < outfile\n --pid # include PID with process names [1] @@ -111,7 +113,8 @@ sub remember_stack { --context # adds source context to --inline --srcline # parses output of 'perf script -F+srcline' and adds source context --addrs # include raw addresses where symbols can't be found - --event-filter=EVENT # event name filter\n + --event-filter=EVENT # event name filter + --streaming # stream the stacks without summing them\n [1] perf script must emit both PID and TIDs for these to work; eg, Linux < 4.1: perf script -f comm,pid,tid,cpu,time,event,ip,sym,dso,trace for Linux >= 4.1: @@ -233,7 +236,11 @@ sub inline { unshift @stack, ""; } } - remember_stack(join(";", @stack), $m_period) if @stack; + if ($streaming) { + print join(";", @stack) . " $m_period\n" if @stack; + } else { + remember_stack(join(";", @stack), $m_period) if @stack; + } undef @stack; undef $pname; next; @@ -430,6 +437,9 @@ sub inline { } } +if ($streaming) { + exit(0); +} foreach my $k (sort { $a cmp $b } keys %collapsed) { print "$k $collapsed{$k}\n"; } diff --git a/stackcollapse-sum.pl b/stackcollapse-sum.pl new file mode 100755 index 00000000..b91108e1 --- /dev/null +++ b/stackcollapse-sum.pl @@ -0,0 +1,47 @@ +#!/usr/bin/perl -ws +# +# stackcollapse-sum Merge identical stack samples +# +# Example input: +# +# foo;bar 1 +# foo;bar 1 +# +# Output: +# +# foo;bar 2 +# +# Copyright 2022 Gabriel Corona. All rights reserved. +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at docs/cddl1.txt or +# http://opensource.org/licenses/CDDL-1.0. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at docs/cddl1.txt. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END + +my %stacks; + +while(<>) { + chomp; + my ($stack, $value) = (/^(.*)\s+?(\d+(?:\.\d*)?)$/); + if ($stack) { + $stacks{$stack} += $value; + } +} + +foreach my $k (sort { $a cmp $b } keys %stacks) { + print "$k $stacks{$k}\n"; +}