-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathkmalloc-top
171 lines (146 loc) · 3.8 KB
/
kmalloc-top
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/perl
#
# This script accumulates the execution paths of all calls to kmalloc
# in the kernel. On Ctrl-C (or exit of the command provided by -c option),
# it sorts, filters and displays them on
# stdout.
#
# The -e (exclude) option can be used to specify a comma-separated list
# - any stack with contents matching any of the items in the list will
# be excluded from the output.
#
# The -m (min) option can be used to specify the minimum number of
# occurrences a stack needs to be included in the output.
#
# The -t (top) option can be used to specify printing only the
# top N stack traces.
#
# The -c (command) option runs starts the command and script
# only runs for the duration of the command.
#
# The -o (options) option passes the options to systemap.
#
# Usage: ./kmalloc-top [-m min] [-e exclude list] [-t top_n] [-c command]
# [-o options]
# Ctrl-c
use Getopt::Std;
my $kmalloc_stacks;
my $total_kmallocs;
my $filtered_kmallocs;
my $sorted_stacks;
my $first_n = 1000000000;
my $min_count = 1;
my $exclude;
my $options;
$SIG{INT} = \&sigint_handler;
getopts('c:e:m:t:o:');
if ($opt_e) {
$exclude = join('|', split(/,/, $opt_e));
print "Will exclude stacks containing: $exclude\n";
}
if ($opt_t) {
$first_n = $opt_t;
print "Will print only the top $first_n stacks.\n";
}
if ($opt_m) {
$min_count = $opt_m;
}
if ($opt_c) {
$command="-c \"$opt_c\""
}
if ($opt_o) {
$options=$opt_o
}
print "Will print stacks with counts >= $min_count.\n";
print STDERR "Press Ctrl-C to stop.\n";
#The systemtap script that instruments the kmalloc
$script="
global kmalloc_stack
probe kernel.function(\"__kmalloc\") { kmalloc_stack[backtrace()]++ }
probe timer.ms(100), end
{
foreach (stack in kmalloc_stack) {
printf(\"<hashkey>\\n\")
print_syms(stack)
printf(\"</hashkey>\\n\")
printf(\"<hashval>%d</hashval>\\n\", kmalloc_stack[stack])
}
delete kmalloc_stack
}
";
open STREAM, "stap $options -e '$script' $command|" or die "Couldn't get output stream $!";
while (<STREAM>) {
if (/<hashval>(.*?)<\/hashval>/) {
update_hash($key, $1);
$key = "";
} elsif ($_ !~ (/<hashkey>|<\/hashkey>/)) {
$key .= $_;
}
}
$num_keys_before_filtering = scalar keys %kmalloc_stacks;
$total_kmallocs = count_kmallocs();
filter_stacks();
sort_stacks();
top_stacks();
sort_stacks();
$num_keys_after_filtering = scalar keys %kmalloc_stacks;
$filtered_kmallocs = count_kmallocs();
summarize();
exit();
sub update_hash
{
my($key, $val) = @_;
$kmalloc_stacks{$key} += $val;
}
sub filter_stacks
{
while (($stack, $count) = each %kmalloc_stacks) {
if ($count < $min_count) {
delete $kmalloc_stacks{$stack};
} elsif ($exclude && $stack =~ /$exclude/) {
delete $kmalloc_stacks{$stack};
}
}
}
sub top_stacks
{
$count=0;
foreach $stack(@sorted_stacks) {
$count+=1;
if ($count > $first_n) {
delete $kmalloc_stacks{$stack};
}
}
}
sub sort_stacks
{
@sorted_stacks = sort { $kmalloc_stacks{$b} <=> $kmalloc_stacks{$a} } keys %kmalloc_stacks;
}
sub count_kmallocs {
$count = 0;
foreach $stack(%kmalloc_stacks) {
$count += $kmalloc_stacks{$stack};
}
return $count;
}
sub summarize {
print "\n";
foreach $stack(@sorted_stacks) {
print "This path seen $kmalloc_stacks{$stack} times:\n$stack\n";
}
if ($total_kmallocs > 0) {
$percent = ($filtered_kmallocs)*100/$total_kmallocs;
} else {
$percent = 0;
}
print "Num stacks before filtering: $num_keys_before_filtering\n";
print "Num stacks after filtering: $num_keys_after_filtering\n";
print "Total kmallocs (before filtering): $total_kmallocs\n";
print "Total kmallocs (after filtering): $filtered_kmallocs\n";
print "The filter stacks have $percent of the total kmallocs\n";
close(STREAM);
}
sub sigint_handler
{
system("pkill kmalloc-stacks");
}