|
1 #!/usr/bin/perl -w |
|
2 # |
|
3 # This Source Code Form is subject to the terms of the Mozilla Public |
|
4 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
6 |
|
7 # This tool is used to construct the ``type inference'' file. It |
|
8 # prints the total number of bytes that are attributed to a type that |
|
9 # cannot be inferred, grouped by stack trace; e.g., |
|
10 # |
|
11 # (100) PR_Malloc |
|
12 # (50) foo |
|
13 # (50) foo2::foo2 |
|
14 # (25) bar |
|
15 # (25) baz |
|
16 # (50) __builtin_new |
|
17 # (50) foo2::foo2 |
|
18 # |
|
19 # |
|
20 # Which indicates that 100 bytes were allocated by uninferrable |
|
21 # classes via PR_Malloc(). Of that 100 bytes, 50 were allocated from |
|
22 # calls by foo(), 25 from calls by bar(), and 25 from calls by baz(). |
|
23 # 50 bytes were allocated by __builtin_new from foo2's ctor. |
|
24 # |
|
25 # |
|
26 # From this, we might be able to infer the type of the object that was |
|
27 # created by examining the PR_Malloc() usage in foo() and the |
|
28 # ::operator new() usage in foo2(), and could add new type inference |
|
29 # rules; e.g., |
|
30 # |
|
31 # <unclassified-string> |
|
32 # foo |
|
33 # foo2 |
|
34 # |
|
35 # # Attribute ::operator new() usage in foo2's ctor to foo2 |
|
36 # <foo2> |
|
37 # __builtin_new |
|
38 # foo2::foo2 |
|
39 |
|
40 use 5.004; |
|
41 use strict; |
|
42 use Getopt::Long; |
|
43 |
|
44 # So we can find TraceMalloc.pm |
|
45 use FindBin; |
|
46 use lib "$FindBin::Bin"; |
|
47 |
|
48 use TraceMalloc; |
|
49 |
|
50 # Collect program options |
|
51 $::opt_help = 0; |
|
52 $::opt_depth = 10; |
|
53 $::opt_types = "${FindBin::Bin}/types.dat"; |
|
54 GetOptions("help", "depth=n", "types=s"); |
|
55 |
|
56 if ($::opt_help) { |
|
57 die "usage: uncategorized.pl [options] <dumpfile> |
|
58 --help Display this message |
|
59 --depth=<n> Display at most <n> stack frames |
|
60 --types=<file> Read type heuristics from <file>"; |
|
61 } |
|
62 |
|
63 # Initialize type inference juju from the type file specified by |
|
64 # ``--types''. |
|
65 TraceMalloc::init_type_inference($::opt_types); |
|
66 |
|
67 # Read the objects from the dump file. For each object, remember up to |
|
68 # ``--depth'' stack frames (from the top). Thread together common |
|
69 # stack prefixes, accumulating the number of bytes attributed to the |
|
70 # prefix. |
|
71 |
|
72 # This'll hold the inverted stacks |
|
73 $::Stacks = { '#bytes#' => 0 }; |
|
74 |
|
75 sub collect_stacks($) { |
|
76 my ($object) = @_; |
|
77 my $stack = $object->{'stack'}; |
|
78 |
|
79 return unless ($object->{'type'} eq 'void*') && (TraceMalloc::infer_type($stack) eq 'void*'); |
|
80 |
|
81 my $count = 0; |
|
82 my $link = \%::Stacks; |
|
83 FRAME: foreach my $frame (@$stack) { |
|
84 last FRAME unless $count++ < $::opt_depth; |
|
85 |
|
86 $link->{'#bytes#'} += $object->{'size'}; |
|
87 $link->{$frame} = { '#bytes#' => 0 } unless $link->{$frame}; |
|
88 $link = $link->{$frame}; |
|
89 } |
|
90 } |
|
91 |
|
92 TraceMalloc::read(\&collect_stacks); |
|
93 |
|
94 # Do a depth-first walk of the inverted stack tree. |
|
95 |
|
96 sub walk($$) { |
|
97 my ($links, $indent) = @_; |
|
98 |
|
99 my @keys; |
|
100 KEY: foreach my $key (keys %$links) { |
|
101 next KEY if $key eq '#bytes#'; |
|
102 $keys[$#keys + 1] = $key; |
|
103 } |
|
104 |
|
105 foreach my $key (sort { $links->{$b}->{'#bytes#'} <=> $links->{$a}->{'#bytes#'} } @keys) { |
|
106 for (my $i = 0; $i < $indent; ++$i) { |
|
107 print " "; |
|
108 } |
|
109 |
|
110 print "($links->{$key}->{'#bytes#'}) $key\n"; |
|
111 |
|
112 walk($links->{$key}, $indent + 1); |
|
113 } |
|
114 } |
|
115 |
|
116 walk(\%::Stacks, 0); |
|
117 |