1 #!/usr/bin/perl -w
2 #
3 # stackcolllapse.pl collapse multiline stacks into single lines.
4 #
5 # Parses a multiline stack followed by a number on a separate line, and
6 # outputs a semicolon separated stack followed by a space and the number.
7 # If memory addresses (+0xd) are present, they are stripped, and resulting
8 # identical stacks are colased with their counts summed.
9 #
10 # USAGE: ./stackcollapse.pl infile > outfile
11 #
12 # Example input:
13 #
14 # unix`i86_mwait+0xd
15 # unix`cpu_idle_mwait+0xf1
16 # unix`idle+0x114
17 # unix`thread_start+0x8
18 # 1641
19 #
20 # Example output:
21 #
22 # unix`thread_start;unix`idle;unix`cpu_idle_mwait;unix`i86_mwait 1641
23 #
24 # Input may contain many stacks, and can be generated using DTrace. The
25 # first few lines of input are skipped (see $headerlines).
26 #
27 # Copyright 2011 Joyent, Inc. All rights reserved.
28 # Copyright 2011 Brendan Gregg. All rights reserved.
29 #
30 # CDDL HEADER START
31 #
32 # The contents of this file are subject to the terms of the
33 # Common Development and Distribution License (the "License").
34 # You may not use this file except in compliance with the License.
35 #
36 # You can obtain a copy of the license at docs/cddl1.txt or
37 # http://opensource.org/licenses/CDDL-1.0.
38 # See the License for the specific language governing permissions
39 # and limitations under the License.
40 #
41 # When distributing Covered Code, include this CDDL HEADER in each
42 # file and include the License file at docs/cddl1.txt.
43 # If applicable, add the following below this CDDL HEADER, with the
44 # fields enclosed by brackets "[]" replaced with your own identifying
45 # information: Portions Copyright [yyyy] [name of copyright owner]
46 #
47 # CDDL HEADER END
48 #
49 # 14-Aug-2011 Brendan Gregg Created this.
50
51 use strict;
52
53 my $headerlines = 3; # number of input lines to skip
54 my $includeoffset = 0; # include function offset (except leafs)
55 my %collapsed;
56
57 sub remember_stack {
58 my ($stack, $count) = @_;
59 $collapsed{$stack} += $count;
60 }
61
62 my $nr = 0;
63 my @stack;
64
65 foreach (<>) {
66 next if $nr++ < $headerlines;
67 chomp;
68
69 if (m/^\s*(\d+)+$/) {
70 my $count = $1;
71 my $joined = join(";", @stack);
72
73 # trim leaf offset if these were retained:
74 $joined =~ s/\+[^+]*$// if $includeoffset;
75
76 remember_stack($joined, $count);
77 @stack = ();
78 next;
79 }
80
81 next if (m/^\s*$/);
82
83 my $frame = $_;
84 $frame =~ s/^\s*//;
85 $frame =~ s/\+[^+]*$// unless $includeoffset;
86
87 # Remove arguments from C++ function names:
88 $frame =~ s/(::.*)[(<].*/$1/;
89
90 $frame = "-" if $frame eq "";
91 unshift @stack, $frame;
92 }
93
94 foreach my $k (sort { $a cmp $b } keys %collapsed) {
95 print "$k $collapsed{$k}\n";
96 }