-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
perf-stat-hist
executable file
·223 lines (206 loc) · 6.62 KB
/
perf-stat-hist
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/bin/bash
#
# perf-stat-hist - perf_events stat histogram hack.
# Written using Linux perf_events (aka "perf").
#
# This is a proof-of-concept showing in-kernel histogram summaries of a
# tracepoint variable.
#
# USAGE: perf-stat-hist [-h] [-b buckets|-P power] [-m max] tracepoint
# variable [seconds]
#
# Run "perf-stat-hist -h" for full usage.
#
# This uses multiple counting tracepoints with different filters, one for each
# histogram bucket. While this is summarized in-kernel, the use of multiple
# tracepoints does add addiitonal overhead, which is more evident if you change
# the power-of size from 4 to 2 (which creates more buckets). Hopefully, in the
# future this this functionality will be provided in an efficient way from
# perf_events itself, at which point this tool can be rewritten.
#
# From perf-tools: https://github.com/brendangregg/perf-tools
#
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# (http://www.gnu.org/copyleft/gpl.html)
#
# 30-Jun-2014 Brendan Gregg Created this.
opt_buckets=0; buckets=; opt_power=0; power=4; opt_max=0; max=$((1024 * 1024))
opt_filter=0; filter=; duration=0; debug=0
trap ':' INT QUIT TERM PIPE HUP
function usage {
cat <<-END >&2
USAGE: perf-stat-hist [-h] [-b buckets|-P power] [-m max] [-f filter]
tracepoint variable [seconds]
-b buckets # specify histogram bucket points
-P power # power-of (default is 4)
-m max # max value for power-of
-f filter # specify a filter
-h # this usage message
eg,
perf-stat-hist syscalls:sys_enter_read count 5
# read() request histogram, 5 seconds
perf-stat-hist syscalls:sys_exit_read ret 5
# read() return histogram, 5 seconds
perf-stat-hist -P 10 syscalls:sys_exit_read ret 5
# ... use power-of-10
perf-stat-hist -P 2 -m 1024 syscalls:sys_exit_read ret 5
# ... use power-of-2, max 1024
perf-stat-hist -b "10 50 100 500" syscalls:sys_exit_read ret 5
# ... histogram based on these bucket ranges
perf-stat-hist -b 10 syscalls:sys_exit_read ret 5
# ... bifurcate by the value 10 (lowest overhead)
perf-stat-hist -f 'rwbs == "WS"' block:block_rq_complete nr_sector 5
# ... synchronous writes histogram, 5 seconds
See the man page and example file for more info.
END
exit
}
function die {
echo >&2 "$@"
exit 1
}
### process options
while getopts b:hm:P:f: opt
do
case $opt in
b) opt_buckets=1; buckets=($OPTARG) ;;
P) opt_power=1; power=$OPTARG ;;
m) opt_max=1; max=$OPTARG ;;
f) opt_filter=1; filter="$OPTARG && " ;;
h|?) usage ;;
esac
done
shift $(( $OPTIND - 1 ))
(( $# < 2 )) && usage
tpoint=$1 # tracepoint
var=$2 # variable for histogram
duration=${3}
### option logic
(( opt_buckets && opt_power )) && die "ERROR: use either -b or -P"
(( opt_power && power < 2 )) && die "ERROR: -P power must be 2 or higher"
### check that tracepoint exists
if ! grep "^$tpoint\$" /sys/kernel/debug/tracing/available_events > /dev/null
then
echo >&2 "ERROR: tracepoint \"$tpoint\" not found. Exiting..."
[[ "$USER" != "root" ]] && echo >&2 "Not root user?"
exit 1
fi
### auto build power-of buckets
if (( !opt_buckets )); then
b=0
s=1
while (( s <= max )); do
b="$b $s"
(( s *= power ))
done
buckets=($b)
fi
### build list of tracepoints and filters for each histogram bucket
max=${buckets[${#buckets[@]} - 1]} # last element
((max_i = ${#buckets[*]} - 1))
tpoints="-e $tpoint --filter \"$filter $var < ${buckets[0]}\""
awkarray=
i=0
while (( i < max_i )); do
if (( i && ${buckets[$i]} <= ${buckets[$i - 1]} )); then
die "ERROR: bucket list must increase in size."
fi
tpoints="$tpoints -e $tpoint --filter \"$filter $var >= ${buckets[$i]} && "
tpoints="$tpoints $var < ${buckets[$i + 1]}\""
awkarray="$awkarray buckets[$i]=${buckets[$i]};"
(( i++ ))
done
awkarray="$awkarray buckets[$max_i]=${buckets[$max_i]};"
tpoints="$tpoints -e $tpoint --filter \"$filter $var >= ${buckets[$max_i]}\""
if (( debug )); then
echo buckets: ${buckets[*]}
echo tracepoints: $tpoints
echo awkarray: ${awkarray[*]}
fi
### prepare to run
if (( duration )); then
etext="for $duration seconds"
cmd="sleep $duration"
else
etext="until Ctrl-C"
cmd="sleep 999999"
fi
p_tpoint=$tpoint
if [ -n "$filter" ]; then
p_tpoint="$tpoint (Filter: ${filter%????})"
fi
if (( opt_buckets )); then
echo "Tracing $p_tpoint, specified buckets, $etext..."
else
echo "Tracing $p_tpoint, power-of-$power, max $max, $etext..."
fi
### run perf
out="-o /dev/stdout" # a workaround needed in linux 3.2; not by 3.4.15
stat=$(eval perf stat $tpoints -a $out $cmd 2>&1)
if (( $? != 0 )); then
echo >&2 "ERROR running perf:"
echo >&2 "$stat"
exit
fi
if (( debug )); then
echo raw output:
echo "$stat"
echo
fi
### find max value for ASCII histogram
most=$(echo "$stat" | awk -v tpoint=$tpoint '
$2 == tpoint { gsub(/,/, ""); if ($1 > m) { m = $1 } }
END { print m }'
)
### process output
echo
echo "$stat" | awk -v tpoint=$tpoint -v max_i=$max_i -v most=$most '
function star(sval, smax, swidth) {
stars = ""
if (smax == 0) return ""
for (si = 0; si < (swidth * sval / smax); si++) {
stars = stars "#"
}
return stars
}
BEGIN {
'"$awkarray"'
printf(" %-15s: %-8s %s\n", "Range", "Count",
"Distribution")
}
/Performance counter stats/ { i = -1 }
# reverse order of rule set is important
{ ok = 0 }
$2 == tpoint { num = $1; gsub(/,/, "", num); ok = 1 }
ok && i >= max_i {
printf(" %10d -> %-10s: %-8s |%-38s|\n", buckets[i],
"", num, star(num, most, 38))
next
}
ok && i >= 0 && i < max_i {
printf(" %10d -> %-10d: %-8s |%-38s|\n", buckets[i],
buckets[i+1] - 1, num, star(num, most, 38))
i++
next
}
ok && i == -1 {
printf(" %10s -> %-10d: %-8s |%-38s|\n", "",
buckets[0] - 1, num, star(num, most, 38))
i++
}
'