fluent-plugin-perf-tools 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +26 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +17 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/fluent-plugin-perf-tools.gemspec +48 -0
- data/lib/fluent/plugin/in_perf_tools.rb +42 -0
- data/lib/fluent/plugin/perf_tools/cachestat.rb +65 -0
- data/lib/fluent/plugin/perf_tools/command.rb +30 -0
- data/lib/fluent/plugin/perf_tools/version.rb +9 -0
- data/lib/fluent/plugin/perf_tools.rb +11 -0
- data/perf-tools/LICENSE +339 -0
- data/perf-tools/README.md +205 -0
- data/perf-tools/bin/bitesize +1 -0
- data/perf-tools/bin/cachestat +1 -0
- data/perf-tools/bin/execsnoop +1 -0
- data/perf-tools/bin/funccount +1 -0
- data/perf-tools/bin/funcgraph +1 -0
- data/perf-tools/bin/funcslower +1 -0
- data/perf-tools/bin/functrace +1 -0
- data/perf-tools/bin/iolatency +1 -0
- data/perf-tools/bin/iosnoop +1 -0
- data/perf-tools/bin/killsnoop +1 -0
- data/perf-tools/bin/kprobe +1 -0
- data/perf-tools/bin/opensnoop +1 -0
- data/perf-tools/bin/perf-stat-hist +1 -0
- data/perf-tools/bin/reset-ftrace +1 -0
- data/perf-tools/bin/syscount +1 -0
- data/perf-tools/bin/tcpretrans +1 -0
- data/perf-tools/bin/tpoint +1 -0
- data/perf-tools/bin/uprobe +1 -0
- data/perf-tools/deprecated/README.md +1 -0
- data/perf-tools/deprecated/execsnoop-proc +150 -0
- data/perf-tools/deprecated/execsnoop-proc.8 +80 -0
- data/perf-tools/deprecated/execsnoop-proc_example.txt +46 -0
- data/perf-tools/disk/bitesize +175 -0
- data/perf-tools/examples/bitesize_example.txt +63 -0
- data/perf-tools/examples/cachestat_example.txt +58 -0
- data/perf-tools/examples/execsnoop_example.txt +153 -0
- data/perf-tools/examples/funccount_example.txt +126 -0
- data/perf-tools/examples/funcgraph_example.txt +2178 -0
- data/perf-tools/examples/funcslower_example.txt +110 -0
- data/perf-tools/examples/functrace_example.txt +341 -0
- data/perf-tools/examples/iolatency_example.txt +350 -0
- data/perf-tools/examples/iosnoop_example.txt +302 -0
- data/perf-tools/examples/killsnoop_example.txt +62 -0
- data/perf-tools/examples/kprobe_example.txt +379 -0
- data/perf-tools/examples/opensnoop_example.txt +47 -0
- data/perf-tools/examples/perf-stat-hist_example.txt +149 -0
- data/perf-tools/examples/reset-ftrace_example.txt +88 -0
- data/perf-tools/examples/syscount_example.txt +297 -0
- data/perf-tools/examples/tcpretrans_example.txt +93 -0
- data/perf-tools/examples/tpoint_example.txt +210 -0
- data/perf-tools/examples/uprobe_example.txt +321 -0
- data/perf-tools/execsnoop +292 -0
- data/perf-tools/fs/cachestat +167 -0
- data/perf-tools/images/perf-tools_2016.png +0 -0
- data/perf-tools/iolatency +296 -0
- data/perf-tools/iosnoop +296 -0
- data/perf-tools/kernel/funccount +146 -0
- data/perf-tools/kernel/funcgraph +259 -0
- data/perf-tools/kernel/funcslower +248 -0
- data/perf-tools/kernel/functrace +192 -0
- data/perf-tools/kernel/kprobe +270 -0
- data/perf-tools/killsnoop +263 -0
- data/perf-tools/man/man8/bitesize.8 +70 -0
- data/perf-tools/man/man8/cachestat.8 +111 -0
- data/perf-tools/man/man8/execsnoop.8 +104 -0
- data/perf-tools/man/man8/funccount.8 +76 -0
- data/perf-tools/man/man8/funcgraph.8 +166 -0
- data/perf-tools/man/man8/funcslower.8 +129 -0
- data/perf-tools/man/man8/functrace.8 +123 -0
- data/perf-tools/man/man8/iolatency.8 +116 -0
- data/perf-tools/man/man8/iosnoop.8 +169 -0
- data/perf-tools/man/man8/killsnoop.8 +100 -0
- data/perf-tools/man/man8/kprobe.8 +162 -0
- data/perf-tools/man/man8/opensnoop.8 +113 -0
- data/perf-tools/man/man8/perf-stat-hist.8 +111 -0
- data/perf-tools/man/man8/reset-ftrace.8 +49 -0
- data/perf-tools/man/man8/syscount.8 +96 -0
- data/perf-tools/man/man8/tcpretrans.8 +93 -0
- data/perf-tools/man/man8/tpoint.8 +140 -0
- data/perf-tools/man/man8/uprobe.8 +168 -0
- data/perf-tools/misc/perf-stat-hist +223 -0
- data/perf-tools/net/tcpretrans +311 -0
- data/perf-tools/opensnoop +280 -0
- data/perf-tools/syscount +192 -0
- data/perf-tools/system/tpoint +232 -0
- data/perf-tools/tools/reset-ftrace +123 -0
- data/perf-tools/user/uprobe +390 -0
- metadata +349 -0
data/perf-tools/iosnoop
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# iosnoop - trace block device I/O.
|
|
4
|
+
# Written using Linux ftrace.
|
|
5
|
+
#
|
|
6
|
+
# This traces disk I/O at the block device interface, using the block:
|
|
7
|
+
# tracepoints. This can help characterize the I/O requested for the storage
|
|
8
|
+
# devices and their resulting performance. I/O completions can also be studied
|
|
9
|
+
# event-by-event for debugging disk and controller I/O scheduling issues.
|
|
10
|
+
#
|
|
11
|
+
# USAGE: ./iosnoop [-hQst] [-d device] [-i iotype] [-p pid] [-n name] [duration]
|
|
12
|
+
#
|
|
13
|
+
# Run "iosnoop -h" for full usage.
|
|
14
|
+
#
|
|
15
|
+
# REQUIREMENTS: FTRACE CONFIG, block:block_rq_* tracepoints (you may
|
|
16
|
+
# already have these on recent kernels).
|
|
17
|
+
#
|
|
18
|
+
# OVERHEAD: By default, iosnoop works without buffering, printing I/O events
|
|
19
|
+
# as they happen (uses trace_pipe), context switching and consuming CPU to do
|
|
20
|
+
# so. This has a limit of about 10,000 IOPS (depending on your platform), at
|
|
21
|
+
# which point iosnoop will be consuming 1 CPU. The duration mode uses buffering,
|
|
22
|
+
# and can handle much higher IOPS rates, however, the buffer has a limit of
|
|
23
|
+
# about 50,000 I/O, after which events will be dropped. You can tune this with
|
|
24
|
+
# bufsize_kb, which is per-CPU. Also note that the "-n" option is currently
|
|
25
|
+
# post-filtered, so all events are traced.
|
|
26
|
+
#
|
|
27
|
+
# This was written as a proof of concept for ftrace. It would be better written
|
|
28
|
+
# using perf_events (after some capabilities are added), which has a better
|
|
29
|
+
# buffering policy, or a tracer such as SystemTap or ktap.
|
|
30
|
+
#
|
|
31
|
+
# From perf-tools: https://github.com/brendangregg/perf-tools
|
|
32
|
+
#
|
|
33
|
+
# See the iosnoop(8) man page (in perf-tools) for more info.
|
|
34
|
+
#
|
|
35
|
+
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
|
|
36
|
+
#
|
|
37
|
+
# This program is free software; you can redistribute it and/or
|
|
38
|
+
# modify it under the terms of the GNU General Public License
|
|
39
|
+
# as published by the Free Software Foundation; either version 2
|
|
40
|
+
# of the License, or (at your option) any later version.
|
|
41
|
+
#
|
|
42
|
+
# This program is distributed in the hope that it will be useful,
|
|
43
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
44
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
45
|
+
# GNU General Public License for more details.
|
|
46
|
+
#
|
|
47
|
+
# You should have received a copy of the GNU General Public License
|
|
48
|
+
# along with this program; if not, write to the Free Software Foundation,
|
|
49
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
50
|
+
#
|
|
51
|
+
# (http://www.gnu.org/copyleft/gpl.html)
|
|
52
|
+
#
|
|
53
|
+
# 12-Jul-2014 Brendan Gregg Created this.
|
|
54
|
+
|
|
55
|
+
### default variables
|
|
56
|
+
tracing=/sys/kernel/debug/tracing
|
|
57
|
+
flock=/var/tmp/.ftrace-lock
|
|
58
|
+
bufsize_kb=4096
|
|
59
|
+
opt_duration=0; duration=; opt_name=0; name=; opt_pid=0; pid=; ftext=
|
|
60
|
+
opt_start=0; opt_end=0; opt_device=0; device=; opt_iotype=0; iotype=
|
|
61
|
+
opt_queue=0
|
|
62
|
+
trap ':' INT QUIT TERM PIPE HUP # sends execution to end tracing section
|
|
63
|
+
|
|
64
|
+
function usage {
|
|
65
|
+
cat <<-END >&2
|
|
66
|
+
USAGE: iosnoop [-hQst] [-d device] [-i iotype] [-p PID] [-n name]
|
|
67
|
+
[duration]
|
|
68
|
+
-d device # device string (eg, "202,1)
|
|
69
|
+
-i iotype # match type (eg, '*R*' for all reads)
|
|
70
|
+
-n name # process name to match on I/O issue
|
|
71
|
+
-p PID # PID to match on I/O issue
|
|
72
|
+
-Q # use queue insert as start time
|
|
73
|
+
-s # include start time of I/O (s)
|
|
74
|
+
-t # include completion time of I/O (s)
|
|
75
|
+
-h # this usage message
|
|
76
|
+
duration # duration seconds, and use buffers
|
|
77
|
+
eg,
|
|
78
|
+
iosnoop # watch block I/O live (unbuffered)
|
|
79
|
+
iosnoop 1 # trace 1 sec (buffered)
|
|
80
|
+
iosnoop -Q # include queueing time in LATms
|
|
81
|
+
iosnoop -ts # include start and end timestamps
|
|
82
|
+
iosnoop -i '*R*' # trace reads
|
|
83
|
+
iosnoop -p 91 # show I/O issued when PID 91 is on-CPU
|
|
84
|
+
iosnoop -Qp 91 # show I/O queued by PID 91, queue time
|
|
85
|
+
|
|
86
|
+
See the man page and example file for more info.
|
|
87
|
+
END
|
|
88
|
+
exit
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function warn {
|
|
92
|
+
if ! eval "$@"; then
|
|
93
|
+
echo >&2 "WARNING: command failed \"$@\""
|
|
94
|
+
fi
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function end {
|
|
98
|
+
# disable tracing
|
|
99
|
+
echo 2>/dev/null
|
|
100
|
+
echo "Ending tracing..." 2>/dev/null
|
|
101
|
+
cd $tracing
|
|
102
|
+
warn "echo 0 > events/block/$b_start/enable"
|
|
103
|
+
warn "echo 0 > events/block/block_rq_complete/enable"
|
|
104
|
+
if (( opt_device || opt_iotype || opt_pid )); then
|
|
105
|
+
warn "echo 0 > events/block/$b_start/filter"
|
|
106
|
+
warn "echo 0 > events/block/block_rq_complete/filter"
|
|
107
|
+
fi
|
|
108
|
+
warn "echo > trace"
|
|
109
|
+
(( wroteflock )) && warn "rm $flock"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function die {
|
|
113
|
+
echo >&2 "$@"
|
|
114
|
+
exit 1
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function edie {
|
|
118
|
+
# die with a quiet end()
|
|
119
|
+
echo >&2 "$@"
|
|
120
|
+
exec >/dev/null 2>&1
|
|
121
|
+
end
|
|
122
|
+
exit 1
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
### process options
|
|
126
|
+
while getopts d:hi:n:p:Qst opt
|
|
127
|
+
do
|
|
128
|
+
case $opt in
|
|
129
|
+
d) opt_device=1; device=$OPTARG ;;
|
|
130
|
+
i) opt_iotype=1; iotype=$OPTARG ;;
|
|
131
|
+
n) opt_name=1; name=$OPTARG ;;
|
|
132
|
+
p) opt_pid=1; pid=$OPTARG ;;
|
|
133
|
+
Q) opt_queue=1 ;;
|
|
134
|
+
s) opt_start=1 ;;
|
|
135
|
+
t) opt_end=1 ;;
|
|
136
|
+
h|?) usage ;;
|
|
137
|
+
esac
|
|
138
|
+
done
|
|
139
|
+
shift $(( $OPTIND - 1 ))
|
|
140
|
+
if (( $# )); then
|
|
141
|
+
opt_duration=1
|
|
142
|
+
duration=$1
|
|
143
|
+
shift
|
|
144
|
+
fi
|
|
145
|
+
if (( opt_device )); then
|
|
146
|
+
major=${device%,*}
|
|
147
|
+
minor=${device#*,}
|
|
148
|
+
dev=$(( (major << 20) + minor ))
|
|
149
|
+
fi
|
|
150
|
+
|
|
151
|
+
### option logic
|
|
152
|
+
(( opt_pid && opt_name )) && die "ERROR: use either -p or -n."
|
|
153
|
+
(( opt_pid )) && ftext=" issued by PID $pid"
|
|
154
|
+
(( opt_name )) && ftext=" issued by process name \"$name\""
|
|
155
|
+
if (( opt_duration )); then
|
|
156
|
+
echo "Tracing block I/O$ftext for $duration seconds (buffered)..."
|
|
157
|
+
else
|
|
158
|
+
echo "Tracing block I/O$ftext. Ctrl-C to end."
|
|
159
|
+
fi
|
|
160
|
+
if (( opt_queue )); then
|
|
161
|
+
b_start=block_rq_insert
|
|
162
|
+
else
|
|
163
|
+
b_start=block_rq_issue
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
### select awk
|
|
167
|
+
(( opt_duration )) && use=mawk || use=gawk # workaround for mawk fflush()
|
|
168
|
+
[[ -x /usr/bin/$use ]] && awk=$use || awk=awk
|
|
169
|
+
wroteflock=1
|
|
170
|
+
|
|
171
|
+
### check permissions
|
|
172
|
+
cd $tracing || die "ERROR: accessing tracing. Root user? Kernel has FTRACE?
|
|
173
|
+
debugfs mounted? (mount -t debugfs debugfs /sys/kernel/debug)"
|
|
174
|
+
|
|
175
|
+
### ftrace lock
|
|
176
|
+
[[ -e $flock ]] && die "ERROR: ftrace may be in use by PID $(cat $flock) $flock"
|
|
177
|
+
echo $$ > $flock || die "ERROR: unable to write $flock."
|
|
178
|
+
|
|
179
|
+
### setup and begin tracing
|
|
180
|
+
echo nop > current_tracer
|
|
181
|
+
warn "echo $bufsize_kb > buffer_size_kb"
|
|
182
|
+
filter=
|
|
183
|
+
if (( opt_iotype )); then
|
|
184
|
+
filter="rwbs ~ \"$iotype\""
|
|
185
|
+
fi
|
|
186
|
+
if (( opt_device )); then
|
|
187
|
+
[[ "$filter" != "" ]] && filter="$filter && "
|
|
188
|
+
filter="${filter}dev == $dev"
|
|
189
|
+
fi
|
|
190
|
+
filter_i=$filter
|
|
191
|
+
if (( opt_pid )); then
|
|
192
|
+
[[ "$filter_i" != "" ]] && filter_i="$filter_i && "
|
|
193
|
+
filter_i="${filter_i}common_pid == $pid"
|
|
194
|
+
[[ "$filter" == "" ]] && filter=0
|
|
195
|
+
fi
|
|
196
|
+
if (( opt_iotype || opt_device || opt_pid )); then
|
|
197
|
+
if ! echo "$filter_i" > events/block/$b_start/filter || \
|
|
198
|
+
! echo "$filter" > events/block/block_rq_complete/filter
|
|
199
|
+
then
|
|
200
|
+
edie "ERROR: setting -d or -t filter. Exiting."
|
|
201
|
+
fi
|
|
202
|
+
fi
|
|
203
|
+
if ! echo 1 > events/block/$b_start/enable || \
|
|
204
|
+
! echo 1 > events/block/block_rq_complete/enable; then
|
|
205
|
+
edie "ERROR: enabling block I/O tracepoints. Exiting."
|
|
206
|
+
fi
|
|
207
|
+
(( opt_start )) && printf "%-15s " "STARTs"
|
|
208
|
+
(( opt_end )) && printf "%-15s " "ENDs"
|
|
209
|
+
printf "%-12.12s %-6s %-4s %-8s %-12s %-6s %8s\n" \
|
|
210
|
+
"COMM" "PID" "TYPE" "DEV" "BLOCK" "BYTES" "LATms"
|
|
211
|
+
|
|
212
|
+
#
|
|
213
|
+
# Determine output format. It may be one of the following (newest first):
|
|
214
|
+
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
|
|
215
|
+
# TASK-PID CPU# TIMESTAMP FUNCTION
|
|
216
|
+
# To differentiate between them, the number of header fields is counted,
|
|
217
|
+
# and an offset set, to skip the extra column when needed.
|
|
218
|
+
#
|
|
219
|
+
offset=$($awk 'BEGIN { o = 0; }
|
|
220
|
+
$1 == "#" && $2 ~ /TASK/ && NF == 6 { o = 1; }
|
|
221
|
+
$2 ~ /TASK/ { print o; exit }' trace)
|
|
222
|
+
|
|
223
|
+
### print trace buffer
|
|
224
|
+
warn "echo > trace"
|
|
225
|
+
( if (( opt_duration )); then
|
|
226
|
+
# wait then dump buffer
|
|
227
|
+
sleep $duration
|
|
228
|
+
cat trace
|
|
229
|
+
else
|
|
230
|
+
# print buffer live
|
|
231
|
+
cat trace_pipe
|
|
232
|
+
fi ) | $awk -v o=$offset -v opt_name=$opt_name -v name=$name \
|
|
233
|
+
-v opt_duration=$opt_duration -v opt_start=$opt_start -v opt_end=$opt_end \
|
|
234
|
+
-v b_start=$b_start '
|
|
235
|
+
# common fields
|
|
236
|
+
$1 != "#" {
|
|
237
|
+
# task name can contain dashes
|
|
238
|
+
comm = pid = $1
|
|
239
|
+
sub(/-[0-9][0-9]*/, "", comm)
|
|
240
|
+
sub(/.*-/, "", pid)
|
|
241
|
+
time = $(3+o); sub(":", "", time)
|
|
242
|
+
dev = $(5+o)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
# block I/O request
|
|
246
|
+
$1 != "#" && $0 ~ b_start {
|
|
247
|
+
if (opt_name && match(comm, name) == 0)
|
|
248
|
+
next
|
|
249
|
+
#
|
|
250
|
+
# example: (fields1..4+o) 202,1 W 0 () 12862264 + 8 [tar]
|
|
251
|
+
# The cmd field "()" might contain multiple words (hex),
|
|
252
|
+
# hence stepping from the right (NF-3).
|
|
253
|
+
#
|
|
254
|
+
loc = $(NF-3)
|
|
255
|
+
starts[dev, loc] = time
|
|
256
|
+
comms[dev, loc] = comm
|
|
257
|
+
pids[dev, loc] = pid
|
|
258
|
+
next
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# block I/O completion
|
|
262
|
+
$1 != "#" && $0 ~ /rq_complete/ {
|
|
263
|
+
#
|
|
264
|
+
# example: (fields1..4+o) 202,1 W () 12862256 + 8 [0]
|
|
265
|
+
#
|
|
266
|
+
dir = $(6+o)
|
|
267
|
+
loc = $(NF-3)
|
|
268
|
+
nsec = $(NF-1)
|
|
269
|
+
|
|
270
|
+
if (starts[dev, loc] > 0) {
|
|
271
|
+
latency = sprintf("%.2f",
|
|
272
|
+
1000 * (time - starts[dev, loc]))
|
|
273
|
+
comm = comms[dev, loc]
|
|
274
|
+
pid = pids[dev, loc]
|
|
275
|
+
|
|
276
|
+
if (opt_start)
|
|
277
|
+
printf "%-15s ", starts[dev, loc]
|
|
278
|
+
if (opt_end)
|
|
279
|
+
printf "%-15s ", time
|
|
280
|
+
printf "%-12.12s %-6s %-4s %-8s %-12s %-6s %8s\n",
|
|
281
|
+
comm, pid, dir, dev, loc, nsec * 512, latency
|
|
282
|
+
if (!opt_duration)
|
|
283
|
+
fflush()
|
|
284
|
+
|
|
285
|
+
delete starts[dev, loc]
|
|
286
|
+
delete comms[dev, loc]
|
|
287
|
+
delete pids[dev, loc]
|
|
288
|
+
}
|
|
289
|
+
next
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
$0 ~ /LOST.*EVENTS/ { print "WARNING: " $0 > "/dev/stderr" }
|
|
293
|
+
'
|
|
294
|
+
|
|
295
|
+
### end tracing
|
|
296
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# funccount - count kernel function calls matching specified wildcards.
|
|
4
|
+
# Uses Linux ftrace.
|
|
5
|
+
#
|
|
6
|
+
# This is a proof of concept using Linux ftrace capabilities on older kernels,
|
|
7
|
+
# and works by using function profiling: in-kernel counters.
|
|
8
|
+
#
|
|
9
|
+
# USAGE: funccount [-hT] [-i secs] [-d secs] [-t top] funcstring
|
|
10
|
+
# eg,
|
|
11
|
+
# funccount 'ext3*' # count all ext3* kernel function calls
|
|
12
|
+
#
|
|
13
|
+
# Run "funccount -h" for full usage.
|
|
14
|
+
#
|
|
15
|
+
# WARNING: This uses dynamic tracing of kernel functions, and could cause
|
|
16
|
+
# kernel panics or freezes. Test, and know what you are doing, before use.
|
|
17
|
+
#
|
|
18
|
+
# REQUIREMENTS: CONFIG_FUNCTION_PROFILER, awk.
|
|
19
|
+
#
|
|
20
|
+
# From perf-tools: https://github.com/brendangregg/perf-tools
|
|
21
|
+
#
|
|
22
|
+
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
|
|
23
|
+
#
|
|
24
|
+
# This program is free software; you can redistribute it and/or
|
|
25
|
+
# modify it under the terms of the GNU General Public License
|
|
26
|
+
# as published by the Free Software Foundation; either version 2
|
|
27
|
+
# of the License, or (at your option) any later version.
|
|
28
|
+
#
|
|
29
|
+
# This program is distributed in the hope that it will be useful,
|
|
30
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
31
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
32
|
+
# GNU General Public License for more details.
|
|
33
|
+
#
|
|
34
|
+
# You should have received a copy of the GNU General Public License
|
|
35
|
+
# along with this program; if not, write to the Free Software Foundation,
|
|
36
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
37
|
+
#
|
|
38
|
+
# (http://www.gnu.org/copyleft/gpl.html)
|
|
39
|
+
#
|
|
40
|
+
# 12-Jul-2014 Brendan Gregg Created this.
|
|
41
|
+
|
|
42
|
+
### default variables
|
|
43
|
+
tracing=/sys/kernel/debug/tracing
|
|
44
|
+
opt_duration=0; duration=; opt_interval=0; interval=999999; opt_timestamp=0
|
|
45
|
+
opt_tail=0; tcmd=cat; ttext=
|
|
46
|
+
trap 'quit=1' INT QUIT TERM PIPE HUP # sends execution to end tracing section
|
|
47
|
+
|
|
48
|
+
function usage {
|
|
49
|
+
cat <<-END >&2
|
|
50
|
+
USAGE: funccount [-hT] [-i secs] [-d secs] [-t top] funcstring
|
|
51
|
+
-d seconds # total duration of trace
|
|
52
|
+
-h # this usage message
|
|
53
|
+
-i seconds # interval summary
|
|
54
|
+
-t top # show top num entries only
|
|
55
|
+
-T # include timestamp (for -i)
|
|
56
|
+
eg,
|
|
57
|
+
funccount 'vfs*' # trace all funcs that match "vfs*"
|
|
58
|
+
funccount -d 5 'tcp*' # trace "tcp*" funcs for 5 seconds
|
|
59
|
+
funccount -t 10 'ext3*' # show top 10 "ext3*" funcs
|
|
60
|
+
funccount -i 1 'ext3*' # summary every 1 second
|
|
61
|
+
funccount -i 1 -d 5 'ext3*' # 5 x 1 second summaries
|
|
62
|
+
|
|
63
|
+
See the man page and example file for more info.
|
|
64
|
+
END
|
|
65
|
+
exit
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function warn {
|
|
69
|
+
if ! eval "$@"; then
|
|
70
|
+
echo >&2 "WARNING: command failed \"$@\""
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function die {
|
|
75
|
+
echo >&2 "$@"
|
|
76
|
+
exit 1
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
### process options
|
|
80
|
+
while getopts d:hi:t:T opt
|
|
81
|
+
do
|
|
82
|
+
case $opt in
|
|
83
|
+
d) opt_duration=1; duration=$OPTARG ;;
|
|
84
|
+
i) opt_interval=1; interval=$OPTARG ;;
|
|
85
|
+
t) opt_tail=1; tnum=$OPTARG ;;
|
|
86
|
+
T) opt_timestamp=1 ;;
|
|
87
|
+
h|?) usage ;;
|
|
88
|
+
esac
|
|
89
|
+
done
|
|
90
|
+
shift $(( $OPTIND - 1 ))
|
|
91
|
+
|
|
92
|
+
### option logic
|
|
93
|
+
(( $# == 0 )) && usage
|
|
94
|
+
funcs="$1"
|
|
95
|
+
if (( opt_tail )); then
|
|
96
|
+
tcmd="tail -$tnum"
|
|
97
|
+
ttext=" Top $tnum only."
|
|
98
|
+
fi
|
|
99
|
+
if (( opt_duration )); then
|
|
100
|
+
echo "Tracing \"$funcs\" for $duration seconds.$ttext.."
|
|
101
|
+
else
|
|
102
|
+
echo "Tracing \"$funcs\".$ttext.. Ctrl-C to end."
|
|
103
|
+
fi
|
|
104
|
+
(( opt_duration && !opt_interval )) && interval=$duration
|
|
105
|
+
|
|
106
|
+
### check permissions
|
|
107
|
+
cd $tracing || die "ERROR: accessing tracing. Root user? Kernel has FTRACE?
|
|
108
|
+
debugfs mounted? (mount -t debugfs debugfs /sys/kernel/debug)"
|
|
109
|
+
|
|
110
|
+
### enable tracing
|
|
111
|
+
sysctl -q kernel.ftrace_enabled=1 # doesn't set exit status
|
|
112
|
+
echo "$funcs" > set_ftrace_filter || die "ERROR: enabling \"$funcs\". Exiting."
|
|
113
|
+
warn "echo nop > current_tracer"
|
|
114
|
+
if ! echo 1 > function_profile_enabled; then
|
|
115
|
+
echo > set_ftrace_filter
|
|
116
|
+
die "ERROR: enabling function profiling."\
|
|
117
|
+
"Have CONFIG_FUNCTION_PROFILER? Exiting."
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
### summarize
|
|
121
|
+
quit=0; secs=0
|
|
122
|
+
while (( !quit && (!opt_duration || secs < duration) )); do
|
|
123
|
+
(( secs += interval ))
|
|
124
|
+
echo 0 > function_profile_enabled
|
|
125
|
+
echo 1 > function_profile_enabled
|
|
126
|
+
sleep $interval
|
|
127
|
+
|
|
128
|
+
echo
|
|
129
|
+
(( opt_timestamp )) && date
|
|
130
|
+
printf "%-30s %8s\n" "FUNC" "COUNT"
|
|
131
|
+
|
|
132
|
+
cat trace_stat/function* | awk '
|
|
133
|
+
# skip headers by matching on the numeric hit column
|
|
134
|
+
$2 ~ /[0-9]/ { a[$1] += $2 }
|
|
135
|
+
END {
|
|
136
|
+
for (k in a) {
|
|
137
|
+
printf "%-30s %8d\n", k, a[k]
|
|
138
|
+
}
|
|
139
|
+
}' | sort -n -k2 | $tcmd
|
|
140
|
+
done
|
|
141
|
+
|
|
142
|
+
### end tracing
|
|
143
|
+
echo 2>/dev/null
|
|
144
|
+
echo "Ending tracing..." 2>/dev/null
|
|
145
|
+
warn "echo 0 > function_profile_enabled"
|
|
146
|
+
warn "echo > set_ftrace_filter"
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# funcgraph - trace kernel function graph, showing child function calls.
|
|
4
|
+
# Uses Linux ftrace.
|
|
5
|
+
#
|
|
6
|
+
# This is an exploratory tool that shows the graph of child function calls
|
|
7
|
+
# for a given kernel function. This can cost moderate overhead to execute, and
|
|
8
|
+
# should only be used to understand kernel behavior for a given function before
|
|
9
|
+
# using other, lower overhead tools. This is a proof of concept using Linux
|
|
10
|
+
# ftrace capabilities on older kernels.
|
|
11
|
+
#
|
|
12
|
+
# USAGE: funcgraph [-aCDhHPtT] [-m maxdepth] [-p PID] [-L TID] [-d secs] funcstring
|
|
13
|
+
#
|
|
14
|
+
# Run "funcgraph -h" for full usage.
|
|
15
|
+
#
|
|
16
|
+
# The output format is the same as the ftrace function graph trace format,
|
|
17
|
+
# described in the kernel source under Documentation/trace/ftrace.txt.
|
|
18
|
+
# Note that the output may be shuffled when different CPU buffers are read;
|
|
19
|
+
# check the CPU column for changes, or include timestamps (-t) and post sort.
|
|
20
|
+
#
|
|
21
|
+
# The "-d duration" mode leaves the trace data in the kernel buffer, and
|
|
22
|
+
# only reads it at the end. If the trace data is large, beware of exhausting
|
|
23
|
+
# buffer space (/sys/kernel/debug/tracing/buffer_size_kb) and losing data.
|
|
24
|
+
#
|
|
25
|
+
# Also beware of feedback loops: tracing tcp* functions over an ssh session,
|
|
26
|
+
# or writing ext4* functions to an ext4 file system. For the former, tcp
|
|
27
|
+
# trace data could be redirected to a file (as in the usage message). For
|
|
28
|
+
# the latter, trace to the screen or a different file system.
|
|
29
|
+
#
|
|
30
|
+
# WARNING: This uses dynamic tracing of kernel functions, and could cause
|
|
31
|
+
# kernel panics or freezes. Test, and know what you are doing, before use.
|
|
32
|
+
#
|
|
33
|
+
# OVERHEADS: This tool causes moderate to high overheads. Use with caution for
|
|
34
|
+
# exploratory purposes, then switch to lower overhead techniques based on
|
|
35
|
+
# findings. It's expected that the kernel will run at least 50% slower while
|
|
36
|
+
# this tool is running -- even while no output is being generated. This is
|
|
37
|
+
# because ALL kernel functions are traced, and filtered based on the function
|
|
38
|
+
# of interest. When output is generated, it can generate many lines quickly
|
|
39
|
+
# depending on the traced event. Such data will cause performance overheads.
|
|
40
|
+
# This also works without buffering by default, printing function events
|
|
41
|
+
# as they happen (uses trace_pipe), context switching and consuming CPU to do
|
|
42
|
+
# so. If needed, you can try the "-d secs" option, which buffers events
|
|
43
|
+
# instead, reducing overhead. If you think the buffer option is losing events,
|
|
44
|
+
# try increasing the buffer size (buffer_size_kb).
|
|
45
|
+
#
|
|
46
|
+
# From perf-tools: https://github.com/brendangregg/perf-tools
|
|
47
|
+
#
|
|
48
|
+
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
|
|
49
|
+
#
|
|
50
|
+
# This program is free software; you can redistribute it and/or
|
|
51
|
+
# modify it under the terms of the GNU General Public License
|
|
52
|
+
# as published by the Free Software Foundation; either version 2
|
|
53
|
+
# of the License, or (at your option) any later version.
|
|
54
|
+
#
|
|
55
|
+
# This program is distributed in the hope that it will be useful,
|
|
56
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
57
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
58
|
+
# GNU General Public License for more details.
|
|
59
|
+
#
|
|
60
|
+
# You should have received a copy of the GNU General Public License
|
|
61
|
+
# along with this program; if not, write to the Free Software Foundation,
|
|
62
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
63
|
+
#
|
|
64
|
+
# (http://www.gnu.org/copyleft/gpl.html)
|
|
65
|
+
#
|
|
66
|
+
# 12-Jul-2014 Brendan Gregg Created this.
|
|
67
|
+
|
|
68
|
+
### default variables
|
|
69
|
+
tracing=/sys/kernel/debug/tracing
|
|
70
|
+
flock=/var/tmp/.ftrace-lock
|
|
71
|
+
opt_duration=0; duration=; opt_pid=0; pid=; opt_tid=0; tid=; pidtext=
|
|
72
|
+
opt_headers=0; opt_proc=0; opt_time=0; opt_tail=0; opt_nodur=0; opt_cpu=0
|
|
73
|
+
opt_max=0; max=0
|
|
74
|
+
trap ':' INT QUIT TERM PIPE HUP # sends execution to end tracing section
|
|
75
|
+
|
|
76
|
+
function usage {
|
|
77
|
+
cat <<-END >&2
|
|
78
|
+
USAGE: funcgraph [-aCDhHPtT] [-m maxdepth] [-p PID] [-L TID] [-d secs] funcstring
|
|
79
|
+
-a # all info (same as -HPt)
|
|
80
|
+
-C # measure on-CPU time only
|
|
81
|
+
-d seconds # trace duration, and use buffers
|
|
82
|
+
-D # do not show function duration
|
|
83
|
+
-h # this usage message
|
|
84
|
+
-H # include column headers
|
|
85
|
+
-m maxdepth # max stack depth to show
|
|
86
|
+
-p PID # trace when this pid is on-CPU
|
|
87
|
+
-L TID # trace when this thread is on-CPU
|
|
88
|
+
-P # show process names & PIDs
|
|
89
|
+
-t # show timestamps
|
|
90
|
+
-T # comment function tails
|
|
91
|
+
eg,
|
|
92
|
+
funcgraph do_nanosleep # trace do_nanosleep() and children
|
|
93
|
+
funcgraph -m 3 do_sys_open # trace do_sys_open() to 3 levels only
|
|
94
|
+
funcgraph -a do_sys_open # include timestamps and process name
|
|
95
|
+
funcgraph -p 198 do_sys_open # trace vfs_read() for PID 198 only
|
|
96
|
+
funcgraph -d 1 do_sys_open >out # trace 1 sec, then write to file
|
|
97
|
+
|
|
98
|
+
See the man page and example file for more info.
|
|
99
|
+
END
|
|
100
|
+
exit
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function warn {
|
|
104
|
+
if ! eval "$@"; then
|
|
105
|
+
echo >&2 "WARNING: command failed \"$@\""
|
|
106
|
+
fi
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function end {
|
|
110
|
+
# disable tracing
|
|
111
|
+
echo 2>/dev/null
|
|
112
|
+
echo "Ending tracing..." 2>/dev/null
|
|
113
|
+
cd $tracing
|
|
114
|
+
|
|
115
|
+
(( opt_time )) && warn "echo nofuncgraph-abstime > trace_options"
|
|
116
|
+
(( opt_proc )) && warn "echo nofuncgraph-proc > trace_options"
|
|
117
|
+
(( opt_tail )) && warn "echo nofuncgraph-tail > trace_options"
|
|
118
|
+
(( opt_nodur )) && warn "echo funcgraph-duration > trace_options"
|
|
119
|
+
(( opt_cpu )) && warn "echo sleep-time > trace_options"
|
|
120
|
+
|
|
121
|
+
warn "echo nop > current_tracer"
|
|
122
|
+
(( opt_pid || opt_tid )) && warn "echo > set_ftrace_pid"
|
|
123
|
+
(( opt_max )) && warn "echo 0 > max_graph_depth"
|
|
124
|
+
warn "echo > set_graph_function"
|
|
125
|
+
warn "echo > trace"
|
|
126
|
+
|
|
127
|
+
(( wroteflock )) && warn "rm $flock"
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function die {
|
|
131
|
+
echo >&2 "$@"
|
|
132
|
+
exit 1
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function edie {
|
|
136
|
+
# die with a quiet end()
|
|
137
|
+
echo >&2 "$@"
|
|
138
|
+
exec >/dev/null 2>&1
|
|
139
|
+
end
|
|
140
|
+
exit 1
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
### process options
|
|
144
|
+
while getopts aCd:DhHm:p:L:PtT opt
|
|
145
|
+
do
|
|
146
|
+
case $opt in
|
|
147
|
+
a) opt_headers=1; opt_proc=1; opt_time=1 ;;
|
|
148
|
+
C) opt_cpu=1; ;;
|
|
149
|
+
d) opt_duration=1; duration=$OPTARG ;;
|
|
150
|
+
D) opt_nodur=1; ;;
|
|
151
|
+
m) opt_max=1; max=$OPTARG ;;
|
|
152
|
+
p) opt_pid=1; pid=$OPTARG ;;
|
|
153
|
+
L) opt_tid=1; tid=$OPTARG ;;
|
|
154
|
+
H) opt_headers=1; ;;
|
|
155
|
+
P) opt_proc=1; ;;
|
|
156
|
+
t) opt_time=1; ;;
|
|
157
|
+
T) opt_tail=1; ;;
|
|
158
|
+
h|?) usage ;;
|
|
159
|
+
esac
|
|
160
|
+
done
|
|
161
|
+
shift $(( $OPTIND - 1 ))
|
|
162
|
+
|
|
163
|
+
### option logic
|
|
164
|
+
(( $# == 0 )) && usage
|
|
165
|
+
(( opt_pid && opt_tid )) && edie "ERROR: You can use -p or -L but not both."
|
|
166
|
+
funcs="$1"
|
|
167
|
+
(( opt_pid )) && pidtext=" for PID $pid"
|
|
168
|
+
(( opt_tid )) && pidtext=" for TID $tid"
|
|
169
|
+
if (( opt_duration )); then
|
|
170
|
+
echo "Tracing \"$funcs\"$pidtext for $duration seconds..."
|
|
171
|
+
else
|
|
172
|
+
echo "Tracing \"$funcs\"$pidtext... Ctrl-C to end."
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
### check permissions
|
|
176
|
+
cd $tracing || die "ERROR: accessing tracing. Root user? Kernel has FTRACE?
|
|
177
|
+
debugfs mounted? (mount -t debugfs debugfs /sys/kernel/debug)"
|
|
178
|
+
|
|
179
|
+
### ftrace lock
|
|
180
|
+
[[ -e $flock ]] && die "ERROR: ftrace may be in use by PID $(cat $flock) $flock"
|
|
181
|
+
echo $$ > $flock || die "ERROR: unable to write $flock."
|
|
182
|
+
wroteflock=1
|
|
183
|
+
|
|
184
|
+
### setup and commence tracing
|
|
185
|
+
sysctl -q kernel.ftrace_enabled=1 # doesn't set exit status
|
|
186
|
+
read mode < current_tracer
|
|
187
|
+
[[ "$mode" != "nop" ]] && edie "ERROR: ftrace active (current_tracer=$mode)"
|
|
188
|
+
if (( opt_max )); then
|
|
189
|
+
if ! echo $max > max_graph_depth; then
|
|
190
|
+
edie "ERROR: setting -m $max. Older kernel version? Exiting."
|
|
191
|
+
fi
|
|
192
|
+
fi
|
|
193
|
+
if (( opt_pid )); then
|
|
194
|
+
echo > set_ftrace_pid
|
|
195
|
+
# ftrace expects kernel pids, which are thread ids
|
|
196
|
+
for tid in /proc/$pid/task/*; do
|
|
197
|
+
if ! echo ${tid##*/} >> set_ftrace_pid; then
|
|
198
|
+
edie "ERROR: setting -p $pid (PID exist?). Exiting."
|
|
199
|
+
fi
|
|
200
|
+
done
|
|
201
|
+
fi
|
|
202
|
+
if (( opt_tid )); then
|
|
203
|
+
if ! echo $tid > set_ftrace_pid; then
|
|
204
|
+
edie "ERROR: setting -L $tid (TID exist?). Exiting."
|
|
205
|
+
fi
|
|
206
|
+
fi
|
|
207
|
+
if ! echo > set_ftrace_filter; then
|
|
208
|
+
edie "ERROR: writing to set_ftrace_filter. Exiting."
|
|
209
|
+
fi
|
|
210
|
+
if ! echo "$funcs" > set_graph_function; then
|
|
211
|
+
edie "ERROR: enabling \"$funcs\". Exiting."
|
|
212
|
+
fi
|
|
213
|
+
if ! echo function_graph > current_tracer; then
|
|
214
|
+
edie "ERROR: setting current_tracer to \"function\". Exiting."
|
|
215
|
+
fi
|
|
216
|
+
if (( opt_cpu )); then
|
|
217
|
+
if ! echo nosleep-time > trace_options; then
|
|
218
|
+
edie "ERROR: setting -C (nosleep-time). Exiting."
|
|
219
|
+
fi
|
|
220
|
+
fi
|
|
221
|
+
# the following must be done after setting current_tracer
|
|
222
|
+
if (( opt_time )); then
|
|
223
|
+
if ! echo funcgraph-abstime > trace_options; then
|
|
224
|
+
edie "ERROR: setting -t (funcgraph-abstime). Exiting."
|
|
225
|
+
fi
|
|
226
|
+
fi
|
|
227
|
+
if (( opt_proc )); then
|
|
228
|
+
if ! echo funcgraph-proc > trace_options; then
|
|
229
|
+
edie "ERROR: setting -P (funcgraph-proc). Exiting."
|
|
230
|
+
fi
|
|
231
|
+
fi
|
|
232
|
+
if (( opt_tail )); then
|
|
233
|
+
if ! echo funcgraph-tail > trace_options; then
|
|
234
|
+
edie "ERROR: setting -T (funcgraph-tail). Old kernel? Exiting."
|
|
235
|
+
fi
|
|
236
|
+
fi
|
|
237
|
+
if (( opt_nodur )); then
|
|
238
|
+
if ! echo nofuncgraph-duration > trace_options; then
|
|
239
|
+
edie "ERROR: setting -D (nofuncgraph-duration). Exiting."
|
|
240
|
+
fi
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
### print trace buffer
|
|
244
|
+
warn "echo > trace"
|
|
245
|
+
if (( opt_duration )); then
|
|
246
|
+
sleep $duration
|
|
247
|
+
if (( opt_headers )); then
|
|
248
|
+
cat trace
|
|
249
|
+
else
|
|
250
|
+
grep -v '^#' trace
|
|
251
|
+
fi
|
|
252
|
+
else
|
|
253
|
+
# trace_pipe lack headers, so fetch them from trace
|
|
254
|
+
(( opt_headers )) && cat trace
|
|
255
|
+
cat trace_pipe
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
### end tracing
|
|
259
|
+
end
|