fluent-plugin-perf-tools 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,311 @@
|
|
1
|
+
#!/usr/bin/perl
|
2
|
+
#
|
3
|
+
# tcpretrans - show TCP retransmts, with address and other details.
|
4
|
+
# Written using Linux ftrace.
|
5
|
+
#
|
6
|
+
# This traces TCP retransmits, showing address, port, and TCP state information,
|
7
|
+
# and sometimes the PID (although usually not, since retransmits are usually
|
8
|
+
# sent by the kernel on timeouts). To keep overhead low, only
|
9
|
+
# tcp_retransmit_skb() calls are traced (this does not trace every packet).
|
10
|
+
#
|
11
|
+
# USAGE: ./tcpretrans [-hls]
|
12
|
+
#
|
13
|
+
# REQUIREMENTS: FTRACE and KPROBE CONFIG, tcp_retransmit_skb() kernel function,
|
14
|
+
# and tcp_send_loss_probe() when -l is used. You may have these already have
|
15
|
+
# these on recent kernels. And Perl.
|
16
|
+
#
|
17
|
+
# This was written as a proof of concept for ftrace, for older Linux systems,
|
18
|
+
# and without kernel debuginfo. It uses dynamic tracing of tcp_retransmit_skb(),
|
19
|
+
# and reads /proc/net/tcp for socket details. Its use of dynamic tracing and
|
20
|
+
# CPU registers is an unstable platform-specific workaround, and may require
|
21
|
+
# modifications to work on different kernels and platforms. This would be better
|
22
|
+
# written using a tracer such as SystemTap, and will likely be rewritten in the
|
23
|
+
# future when certain tracing features are added to the Linux kernel.
|
24
|
+
#
|
25
|
+
# When -l is used, this also uses dynamic tracing of tcp_send_loss_probe() and
|
26
|
+
# a register.
|
27
|
+
#
|
28
|
+
# Currently only IPv4 is supported, on x86_64. If you try this on a different
|
29
|
+
# architecture, you'll likely need to adjust the register locations (search
|
30
|
+
# for %di).
|
31
|
+
#
|
32
|
+
# OVERHEAD: The CPU overhead is relative to the rate of TCP retransmits, and is
|
33
|
+
# designed to be low as this does not examine every packet. Once per second the
|
34
|
+
# /proc/net/tcp file is read, and a buffer of retransmit trace events is
|
35
|
+
# retrieved from the kernel and processed.
|
36
|
+
#
|
37
|
+
# From perf-tools: https://github.com/brendangregg/perf-tools
|
38
|
+
#
|
39
|
+
# See the tcpretrans(8) man page (in perf-tools) for more info.
|
40
|
+
#
|
41
|
+
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
|
42
|
+
#
|
43
|
+
# This program is free software; you can redistribute it and/or
|
44
|
+
# modify it under the terms of the GNU General Public License
|
45
|
+
# as published by the Free Software Foundation; either version 2
|
46
|
+
# of the License, or (at your option) any later version.
|
47
|
+
#
|
48
|
+
# This program is distributed in the hope that it will be useful,
|
49
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
50
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
51
|
+
# GNU General Public License for more details.
|
52
|
+
#
|
53
|
+
# You should have received a copy of the GNU General Public License
|
54
|
+
# along with this program; if not, write to the Free Software Foundation,
|
55
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
56
|
+
#
|
57
|
+
# (http://www.gnu.org/copyleft/gpl.html)
|
58
|
+
#
|
59
|
+
# 28-Jul-2014 Brendan Gregg Created this.
|
60
|
+
|
61
|
+
use strict;
|
62
|
+
use warnings;
|
63
|
+
use POSIX qw(strftime);
|
64
|
+
use Getopt::Long;
|
65
|
+
my $tracing = "/sys/kernel/debug/tracing";
|
66
|
+
my $flock = "/var/tmp/.ftrace-lock";
|
67
|
+
my $interval = 1;
|
68
|
+
local $SIG{INT} = \&cleanup;
|
69
|
+
local $SIG{QUIT} = \&cleanup;
|
70
|
+
local $SIG{TERM} = \&cleanup;
|
71
|
+
local $SIG{PIPE} = \&cleanup;
|
72
|
+
local $SIG{HUP} = \&cleanup;
|
73
|
+
$| = 1;
|
74
|
+
|
75
|
+
### options
|
76
|
+
my ($help, $stacks, $tlp);
|
77
|
+
GetOptions("help|h" => \$help,
|
78
|
+
"stacks|s" => \$stacks,
|
79
|
+
"tlp|l" => \$tlp)
|
80
|
+
or usage();
|
81
|
+
usage() if $help;
|
82
|
+
|
83
|
+
sub usage {
|
84
|
+
print STDERR "USAGE: tcpretrans [-hls]\n";
|
85
|
+
print STDERR " -h # help message\n";
|
86
|
+
print STDERR " -l # trace TCP tail loss probes\n";
|
87
|
+
print STDERR " -s # print stack traces\n";
|
88
|
+
print STDERR " eg,\n";
|
89
|
+
print STDERR " tcpretrans # trace TCP retransmits\n";
|
90
|
+
exit;
|
91
|
+
}
|
92
|
+
|
93
|
+
# delete lock and die
|
94
|
+
sub ldie {
|
95
|
+
unlink $flock;
|
96
|
+
die @_;
|
97
|
+
}
|
98
|
+
|
99
|
+
# end tracing (silently) and die
|
100
|
+
sub edie {
|
101
|
+
print STDERR "@_\n";
|
102
|
+
close STDOUT;
|
103
|
+
close STDERR;
|
104
|
+
cleanup();
|
105
|
+
}
|
106
|
+
|
107
|
+
sub writeto {
|
108
|
+
my ($string, $file) = @_;
|
109
|
+
open FILE, ">$file" or return 0;
|
110
|
+
print FILE $string or return 0;
|
111
|
+
close FILE or return 0;
|
112
|
+
}
|
113
|
+
|
114
|
+
sub appendto {
|
115
|
+
my ($string, $file) = @_;
|
116
|
+
open FILE, ">>$file" or return 0;
|
117
|
+
print FILE $string or return 0;
|
118
|
+
close FILE or return 0;
|
119
|
+
}
|
120
|
+
|
121
|
+
# kprobe functions
|
122
|
+
sub create_kprobe {
|
123
|
+
my ($kname, $kval) = @_;
|
124
|
+
appendto "p:$kname $kval", "kprobe_events" or return 0;
|
125
|
+
}
|
126
|
+
|
127
|
+
sub enable_kprobe {
|
128
|
+
my ($kname) = @_;
|
129
|
+
writeto "1", "events/kprobes/$kname/enable" or return 0;
|
130
|
+
}
|
131
|
+
|
132
|
+
sub remove_kprobe {
|
133
|
+
my ($kname) = @_;
|
134
|
+
writeto "0", "events/kprobes/$kname/enable" or return 0;
|
135
|
+
appendto "-:$kname", "kprobe_events" or return 0;
|
136
|
+
}
|
137
|
+
|
138
|
+
# tcp socket cache
|
139
|
+
my %tcp;
|
140
|
+
sub cache_tcp {
|
141
|
+
undef %tcp;
|
142
|
+
open(TCP, "/proc/net/tcp") or ldie "ERROR: reading /proc/net/tcp.";
|
143
|
+
while (<TCP>) {
|
144
|
+
next if /^ *sl/;
|
145
|
+
my ($sl, $local_address, $rem_address, $st, $tx_rx, $tr_tm,
|
146
|
+
$retrnsmt, $uid, $timeout, $inode, $jf, $sk) = split;
|
147
|
+
$sk =~ s/^0x//;
|
148
|
+
$tcp{$sk}{laddr} = $local_address;
|
149
|
+
$tcp{$sk}{raddr} = $rem_address;
|
150
|
+
$tcp{$sk}{state} = $st;
|
151
|
+
}
|
152
|
+
close TCP;
|
153
|
+
}
|
154
|
+
|
155
|
+
my @tcpstate;
|
156
|
+
sub map_tcp_states {
|
157
|
+
push @tcpstate, "NULL";
|
158
|
+
for (<DATA>) {
|
159
|
+
chomp;
|
160
|
+
s/.*TCP_//;
|
161
|
+
s/[, ].*$//;
|
162
|
+
push @tcpstate, $_;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
# /proc/net/tcp hex addr to dotted quad decimal
|
167
|
+
sub inet_h2a {
|
168
|
+
my ($haddr) = @_;
|
169
|
+
|
170
|
+
my @addr = ();
|
171
|
+
for my $num ($haddr =~ /(..)(..)(..)(..)/) {
|
172
|
+
unshift @addr, hex($num);
|
173
|
+
}
|
174
|
+
return join(".", @addr);
|
175
|
+
}
|
176
|
+
|
177
|
+
### check permissions
|
178
|
+
chdir "$tracing" or die "ERROR: accessing tracing. Root? Kernel has FTRACE?" .
|
179
|
+
"\ndebugfs mounted? (mount -t debugfs debugfs /sys/kernel/debug)";
|
180
|
+
|
181
|
+
### ftrace lock
|
182
|
+
if (-e $flock) {
|
183
|
+
open FLOCK, $flock; my $fpid = <FLOCK>; chomp $fpid; close FLOCK;
|
184
|
+
die "ERROR: ftrace may be in use by PID $fpid ($flock)";
|
185
|
+
}
|
186
|
+
writeto "$$", $flock or die "ERROR: unable to write $flock.";
|
187
|
+
|
188
|
+
#
|
189
|
+
# Setup and begin tracing.
|
190
|
+
# Use of ldie() and edie() ensures that if an error is encountered, the
|
191
|
+
# kernel is not left in a partially configured state.
|
192
|
+
#
|
193
|
+
writeto "nop", "current_tracer" or ldie "ERROR: disabling current_tracer.";
|
194
|
+
my $kname_rtr = "tcpretrans_tcp_retransmit_skb";
|
195
|
+
my $kname_tlp = "tcpretrans_tcp_send_loss_probe";
|
196
|
+
create_kprobe $kname_rtr, "tcp_retransmit_skb sk=%di" or
|
197
|
+
ldie "ERROR: creating kprobe for tcp_retransmit_skb().";;
|
198
|
+
if ($tlp) {
|
199
|
+
create_kprobe $kname_tlp, "tcp_send_loss_probe sk=%di" or
|
200
|
+
edie "ERROR: creating kprobe for tcp_send_loss_probe(). " .
|
201
|
+
"Older kernel version?";
|
202
|
+
}
|
203
|
+
if ($stacks) {
|
204
|
+
writeto "1", "options/stacktrace" or print STDERR "WARNING: " .
|
205
|
+
"unable to enable stacktraces.\n";
|
206
|
+
}
|
207
|
+
enable_kprobe $kname_rtr or edie "ERROR: enabling $kname_rtr probe.";
|
208
|
+
if ($tlp) {
|
209
|
+
enable_kprobe $kname_tlp or edie "ERROR: enabling $kname_tlp probe.";
|
210
|
+
}
|
211
|
+
map_tcp_states();
|
212
|
+
printf "%-8s %-6s %-20s -- %-20s %-12s\n", "TIME", "PID", "LADDR:LPORT",
|
213
|
+
"RADDR:RPORT", "STATE";
|
214
|
+
|
215
|
+
#
|
216
|
+
# Read and print event data. This loop waits one second then reads the buffered
|
217
|
+
# trace data, then caches /proc/net/tcp, then iterates over the buffered trace
|
218
|
+
# data using the cached state. While this minimizes CPU overheads, it only
|
219
|
+
# works because sockets that are retransmitting are usually long lived, and
|
220
|
+
# remain in /proc/net/tcp for at least our sleep interval.
|
221
|
+
#
|
222
|
+
while (1) {
|
223
|
+
sleep $interval;
|
224
|
+
|
225
|
+
# buffer trace data
|
226
|
+
open TPIPE, "trace" or edie "ERROR: opening trace_pipe.";
|
227
|
+
my @trace = ();
|
228
|
+
while (<TPIPE>) {
|
229
|
+
next if /^#/;
|
230
|
+
push @trace, $_;
|
231
|
+
}
|
232
|
+
close TPIPE;
|
233
|
+
writeto "0", "trace" or edie "ERROR: clearing trace";
|
234
|
+
|
235
|
+
# cache /proc/net/tcp state
|
236
|
+
if (scalar @trace) {
|
237
|
+
cache_tcp();
|
238
|
+
}
|
239
|
+
|
240
|
+
# process and print events
|
241
|
+
for (@trace) {
|
242
|
+
if ($stacks && /^ *=>/) {
|
243
|
+
print $_;
|
244
|
+
next;
|
245
|
+
}
|
246
|
+
|
247
|
+
my ($taskpid, $rest) = split ' ', $_, 2;
|
248
|
+
my ($task, $pid) = $taskpid =~ /(.*)-(\d+)/;
|
249
|
+
|
250
|
+
my ($skp) = $rest =~ /sk=([0-9a-fx]*)/;
|
251
|
+
next unless defined $skp and $skp ne "";
|
252
|
+
$skp =~ s/^0x//;
|
253
|
+
|
254
|
+
my ($laddr, $lport, $raddr, $rport, $state);
|
255
|
+
if (defined $tcp{$skp}) {
|
256
|
+
# convert /proc/net/tcp hex to dotted quads
|
257
|
+
my ($hladdr, $hlport) = split /:/, $tcp{$skp}{laddr};
|
258
|
+
my ($hraddr, $hrport) = split /:/, $tcp{$skp}{raddr};
|
259
|
+
$laddr = inet_h2a($hladdr);
|
260
|
+
$raddr = inet_h2a($hraddr);
|
261
|
+
$lport = hex($hlport);
|
262
|
+
$rport = hex($hrport);
|
263
|
+
$state = $tcpstate[hex($tcp{$skp}{state})];
|
264
|
+
} else {
|
265
|
+
# socket closed too quickly
|
266
|
+
($laddr, $raddr) = ("-", "-");
|
267
|
+
($lport, $rport) = ("-", "-");
|
268
|
+
$state = "-";
|
269
|
+
}
|
270
|
+
|
271
|
+
my $now = strftime "%H:%M:%S", localtime;
|
272
|
+
printf "%-8s %-6s %-20s %s> %-20s %-12s\n", $now, $pid,
|
273
|
+
"$laddr:$lport", $rest =~ /$kname_tlp/ ? "L" : "R",
|
274
|
+
"$raddr:$rport", $state,
|
275
|
+
}
|
276
|
+
}
|
277
|
+
|
278
|
+
### end tracing
|
279
|
+
cleanup();
|
280
|
+
|
281
|
+
sub cleanup {
|
282
|
+
print "\nEnding tracing...\n";
|
283
|
+
close TPIPE;
|
284
|
+
if ($stacks) {
|
285
|
+
writeto "0", "options/stacktrace" or print STDERR "WARNING: " .
|
286
|
+
"unable to disable stacktraces.\n";
|
287
|
+
}
|
288
|
+
remove_kprobe $kname_rtr
|
289
|
+
or print STDERR "ERROR: removing kprobe $kname_rtr\n";
|
290
|
+
if ($tlp) {
|
291
|
+
remove_kprobe $kname_tlp
|
292
|
+
or print STDERR "ERROR: removing kprobe $kname_tlp\n";
|
293
|
+
}
|
294
|
+
writeto "", "trace";
|
295
|
+
unlink $flock;
|
296
|
+
exit;
|
297
|
+
}
|
298
|
+
|
299
|
+
# from /usr/include/netinet/tcp.h:
|
300
|
+
__DATA__
|
301
|
+
TCP_ESTABLISHED = 1,
|
302
|
+
TCP_SYN_SENT,
|
303
|
+
TCP_SYN_RECV,
|
304
|
+
TCP_FIN_WAIT1,
|
305
|
+
TCP_FIN_WAIT2,
|
306
|
+
TCP_TIME_WAIT,
|
307
|
+
TCP_CLOSE,
|
308
|
+
TCP_CLOSE_WAIT,
|
309
|
+
TCP_LAST_ACK,
|
310
|
+
TCP_LISTEN,
|
311
|
+
TCP_CLOSING /* now a valid state */
|
@@ -0,0 +1,280 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
#
|
3
|
+
# opensnoop - trace open() syscalls with file details.
|
4
|
+
# Written using Linux ftrace.
|
5
|
+
#
|
6
|
+
# This traces open() syscalls, showing the file name and returned file
|
7
|
+
# descriptor number (or -1, for error).
|
8
|
+
#
|
9
|
+
# This implementation is designed to work on older kernel versions, and without
|
10
|
+
# kernel debuginfo. It works by dynamic tracing of the return value of getname()
|
11
|
+
# as a string, and associating it with the following open() syscall return.
|
12
|
+
# This approach is kernel version specific, and may not work on your version.
|
13
|
+
# It is a workaround, and proof of concept for ftrace, until more kernel tracing
|
14
|
+
# functionality is available.
|
15
|
+
#
|
16
|
+
# USAGE: ./opensnoop [-htx] [-d secs] [-p pid] [-L tid] [-n name] [filename]
|
17
|
+
#
|
18
|
+
# Run "opensnoop -h" for full usage.
|
19
|
+
#
|
20
|
+
# REQUIREMENTS: FTRACE and KPROBE CONFIG, syscalls:sys_exit_open tracepoint,
|
21
|
+
# getname() kernel function (you may already have these on recent kernels),
|
22
|
+
# and awk.
|
23
|
+
#
|
24
|
+
# From perf-tools: https://github.com/brendangregg/perf-tools
|
25
|
+
#
|
26
|
+
# See the opensnoop(8) man page (in perf-tools) for more info.
|
27
|
+
#
|
28
|
+
# COPYRIGHT: Copyright (c) 2014 Brendan Gregg.
|
29
|
+
#
|
30
|
+
# This program is free software; you can redistribute it and/or
|
31
|
+
# modify it under the terms of the GNU General Public License
|
32
|
+
# as published by the Free Software Foundation; either version 2
|
33
|
+
# of the License, or (at your option) any later version.
|
34
|
+
#
|
35
|
+
# This program is distributed in the hope that it will be useful,
|
36
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
37
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
38
|
+
# GNU General Public License for more details.
|
39
|
+
#
|
40
|
+
# You should have received a copy of the GNU General Public License
|
41
|
+
# along with this program; if not, write to the Free Software Foundation,
|
42
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
43
|
+
#
|
44
|
+
# (http://www.gnu.org/copyleft/gpl.html)
|
45
|
+
#
|
46
|
+
# 20-Jul-2014 Brendan Gregg Created this.
|
47
|
+
|
48
|
+
### default variables
|
49
|
+
tracing=/sys/kernel/debug/tracing
|
50
|
+
flock=/var/tmp/.ftrace-lock; wroteflock=0
|
51
|
+
opt_duration=0; duration=; opt_name=0; name=; opt_pid=0; pid=; opt_tid=0; tid=
|
52
|
+
ftext=; opt_time=0; opt_fail=0; opt_file=0; file=
|
53
|
+
trap ':' INT QUIT TERM PIPE HUP # sends execution to end tracing section
|
54
|
+
|
55
|
+
function usage {
|
56
|
+
cat <<-END >&2
|
57
|
+
USAGE: opensnoop [-htx] [-d secs] [-p PID] [-L TID] [-n name] [filename]
|
58
|
+
-d seconds # trace duration, and use buffers
|
59
|
+
-n name # process name to match on open
|
60
|
+
-p PID # PID to match on open
|
61
|
+
-L TID # PID to match on open
|
62
|
+
-t # include time (seconds)
|
63
|
+
-x # only show failed opens
|
64
|
+
-h # this usage message
|
65
|
+
filename # match filename (partials, REs, ok)
|
66
|
+
eg,
|
67
|
+
opensnoop # watch open()s live (unbuffered)
|
68
|
+
opensnoop -d 1 # trace 1 sec (buffered)
|
69
|
+
opensnoop -p 181 # trace I/O issued by PID 181 only
|
70
|
+
opensnoop conf # trace filenames containing "conf"
|
71
|
+
opensnoop 'log$' # filenames ending in "log"
|
72
|
+
|
73
|
+
See the man page and example file for more info.
|
74
|
+
END
|
75
|
+
exit
|
76
|
+
}
|
77
|
+
|
78
|
+
function warn {
|
79
|
+
if ! eval "$@"; then
|
80
|
+
echo >&2 "WARNING: command failed \"$@\""
|
81
|
+
fi
|
82
|
+
}
|
83
|
+
|
84
|
+
function end {
|
85
|
+
# disable tracing
|
86
|
+
echo 2>/dev/null
|
87
|
+
echo "Ending tracing..." 2>/dev/null
|
88
|
+
cd $tracing
|
89
|
+
warn "echo 0 > events/kprobes/getnameprobe/enable"
|
90
|
+
warn "echo 0 > events/syscalls/sys_exit_open/enable"
|
91
|
+
warn "echo 0 > events/syscalls/sys_exit_openat/enable"
|
92
|
+
if (( opt_pid || opt_tid )); then
|
93
|
+
warn "echo 0 > events/kprobes/getnameprobe/filter"
|
94
|
+
warn "echo 0 > events/syscalls/sys_exit_open/filter"
|
95
|
+
warn "echo 0 > events/syscalls/sys_exit_openat/filter"
|
96
|
+
fi
|
97
|
+
warn "echo -:getnameprobe >> kprobe_events"
|
98
|
+
warn "echo > trace"
|
99
|
+
(( wroteflock )) && warn "rm $flock"
|
100
|
+
}
|
101
|
+
|
102
|
+
function die {
|
103
|
+
echo >&2 "$@"
|
104
|
+
exit 1
|
105
|
+
}
|
106
|
+
|
107
|
+
function edie {
|
108
|
+
# die with a quiet end()
|
109
|
+
echo >&2 "$@"
|
110
|
+
exec >/dev/null 2>&1
|
111
|
+
end
|
112
|
+
exit 1
|
113
|
+
}
|
114
|
+
|
115
|
+
### process options
|
116
|
+
while getopts d:hn:p:L:tx opt
|
117
|
+
do
|
118
|
+
case $opt in
|
119
|
+
d) opt_duration=1; duration=$OPTARG ;;
|
120
|
+
n) opt_name=1; name=$OPTARG ;;
|
121
|
+
p) opt_pid=1; pid=$OPTARG ;;
|
122
|
+
L) opt_tid=1; tid=$OPTARG ;;
|
123
|
+
t) opt_time=1 ;;
|
124
|
+
x) opt_fail=1 ;;
|
125
|
+
h|?) usage ;;
|
126
|
+
esac
|
127
|
+
done
|
128
|
+
shift $(( $OPTIND - 1 ))
|
129
|
+
if (( $# )); then
|
130
|
+
opt_file=1
|
131
|
+
file=$1
|
132
|
+
shift
|
133
|
+
fi
|
134
|
+
(( $# )) && usage
|
135
|
+
|
136
|
+
### option logic
|
137
|
+
(( opt_pid + opt_name + opt_tid > 1 )) && \
|
138
|
+
die "ERROR: use at most one of -p, -n, -L."
|
139
|
+
(( opt_pid )) && ftext=" issued by PID $pid"
|
140
|
+
(( opt_tid )) && ftext=" issued by TID $tid"
|
141
|
+
(( opt_name )) && ftext=" issued by process name \"$name\""
|
142
|
+
(( opt_file )) && ftext="$ftext for filenames containing \"$file\""
|
143
|
+
if (( opt_duration )); then
|
144
|
+
echo "Tracing open()s$ftext for $duration seconds (buffered)..."
|
145
|
+
else
|
146
|
+
echo "Tracing open()s$ftext. Ctrl-C to end."
|
147
|
+
fi
|
148
|
+
|
149
|
+
### select awk
|
150
|
+
(( opt_duration )) && use=mawk || use=gawk # workaround for mawk fflush()
|
151
|
+
[[ -x /usr/bin/$use ]] && awk=$use || awk=awk
|
152
|
+
|
153
|
+
### check permissions
|
154
|
+
cd $tracing || die "ERROR: accessing tracing. Root user? Kernel has FTRACE?
|
155
|
+
debugfs mounted? (mount -t debugfs debugfs /sys/kernel/debug)"
|
156
|
+
|
157
|
+
### ftrace lock
|
158
|
+
[[ -e $flock ]] && die "ERROR: ftrace may be in use by PID $(cat $flock) $flock"
|
159
|
+
echo $$ > $flock || die "ERROR: unable to write $flock."
|
160
|
+
wroteflock=1
|
161
|
+
|
162
|
+
### setup and begin tracing
|
163
|
+
echo nop > current_tracer
|
164
|
+
ver=$(uname -r)
|
165
|
+
if [[ "$ver" == 2.* || "$ver" == 3.[1-6].* ]]; then
|
166
|
+
# rval is char *
|
167
|
+
kprobe='r:getnameprobe getname +0($retval):string'
|
168
|
+
else
|
169
|
+
# rval is struct filename *
|
170
|
+
kprobe='r:getnameprobe getname +0(+0($retval)):string'
|
171
|
+
fi
|
172
|
+
if ! echo $kprobe >> kprobe_events; then
|
173
|
+
edie "ERROR: adding a kprobe for getname(). Exiting."
|
174
|
+
fi
|
175
|
+
if (( opt_pid )); then
|
176
|
+
filter=
|
177
|
+
for tid in /proc/$pid/task/*; do
|
178
|
+
filter="$filter || common_pid == ${tid##*/}"
|
179
|
+
done
|
180
|
+
filter=${filter:3} # trim leading ' || ' (four characters)
|
181
|
+
if ! echo $filter > events/kprobes/getnameprobe/filter || \
|
182
|
+
! echo $filter > events/syscalls/sys_exit_open/filter || \
|
183
|
+
! echo $filter > events/syscalls/sys_exit_openat/filter
|
184
|
+
then
|
185
|
+
edie "ERROR: setting -p $pid. Exiting."
|
186
|
+
fi
|
187
|
+
fi
|
188
|
+
if (( opt_tid )); then
|
189
|
+
if ! echo "common_pid == $tid" > events/kprobes/getnameprobe/filter || \
|
190
|
+
! echo "common_pid == $tid" > events/syscalls/sys_exit_open/filter || \
|
191
|
+
! echo "common_pid == $tid" > events/syscalls/sys_exit_openat/filter
|
192
|
+
then
|
193
|
+
edie "ERROR: setting -L $tid. Exiting."
|
194
|
+
fi
|
195
|
+
fi
|
196
|
+
if ! echo 1 > events/kprobes/getnameprobe/enable; then
|
197
|
+
edie "ERROR: enabling kprobe for getname(). Exiting."
|
198
|
+
fi
|
199
|
+
if ! echo 1 > events/syscalls/sys_exit_open/enable; then
|
200
|
+
edie "ERROR: enabling open() exit tracepoint. Exiting."
|
201
|
+
fi
|
202
|
+
if ! echo 1 > events/syscalls/sys_exit_openat/enable; then
|
203
|
+
edie "ERROR: enabling openat() exit tracepoint. Exiting."
|
204
|
+
fi
|
205
|
+
(( opt_time )) && printf "%-16s " "TIMEs"
|
206
|
+
printf "%-16.16s %-6s %4s %s\n" "COMM" "PID" "FD" "FILE"
|
207
|
+
|
208
|
+
#
|
209
|
+
# Determine output format. It may be one of the following (newest first):
|
210
|
+
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
|
211
|
+
# TASK-PID CPU# TIMESTAMP FUNCTION
|
212
|
+
# To differentiate between them, the number of header fields is counted,
|
213
|
+
# and an offset set, to skip the extra column when needed.
|
214
|
+
#
|
215
|
+
offset=$($awk 'BEGIN { o = 0; }
|
216
|
+
$1 == "#" && $2 ~ /TASK/ && NF == 6 { o = 1; }
|
217
|
+
$2 ~ /TASK/ { print o; exit }' trace)
|
218
|
+
|
219
|
+
### print trace buffer
|
220
|
+
warn "echo > trace"
|
221
|
+
( if (( opt_duration )); then
|
222
|
+
# wait then dump buffer
|
223
|
+
sleep $duration
|
224
|
+
cat trace
|
225
|
+
else
|
226
|
+
# print buffer live
|
227
|
+
cat trace_pipe
|
228
|
+
fi ) | $awk -v o=$offset -v opt_name=$opt_name -v name=$name \
|
229
|
+
-v opt_duration=$opt_duration -v opt_time=$opt_time -v opt_fail=$opt_fail \
|
230
|
+
-v opt_file=$opt_file -v file=$file '
|
231
|
+
# common fields
|
232
|
+
$1 != "#" {
|
233
|
+
# task name can contain dashes and space
|
234
|
+
split($0, line, "-")
|
235
|
+
sub(/^[ \t\r\n]+/, "", line[1])
|
236
|
+
comm = line[1]
|
237
|
+
if (opt_name && match(comm, name) == 0)
|
238
|
+
next
|
239
|
+
sub(/ .*$/, "", line[2])
|
240
|
+
pid = line[2]
|
241
|
+
}
|
242
|
+
|
243
|
+
# do_sys_open()
|
244
|
+
$1 != "#" && $(5+o) ~ /do_sys_open/ {
|
245
|
+
#
|
246
|
+
# eg: ... (do_sys_open+0xc3/0x220 <- getname) arg1="file1"
|
247
|
+
#
|
248
|
+
match($0, /arg1=\"(.+)\"/, m)
|
249
|
+
lastfile[pid] = m[1]
|
250
|
+
}
|
251
|
+
|
252
|
+
# sys_open() / sys_openat()
|
253
|
+
$1 != "#" && ($(4+o) == "sys_open" || $(4+o) == "sys_openat") {
|
254
|
+
filename = lastfile[pid]
|
255
|
+
if (!filename)
|
256
|
+
next
|
257
|
+
delete lastfile[pid]
|
258
|
+
if (opt_file && filename !~ file)
|
259
|
+
next
|
260
|
+
rval = $NF
|
261
|
+
# matched failed as beginning with 0xfffff
|
262
|
+
if (opt_fail && rval !~ /0xfffff/)
|
263
|
+
next
|
264
|
+
if (rval ~ /0xfffff/)
|
265
|
+
rval = -1
|
266
|
+
|
267
|
+
if (opt_time) {
|
268
|
+
time = $(3+o); sub(":", "", time)
|
269
|
+
printf "%-16s ", time
|
270
|
+
}
|
271
|
+
printf "%-16.16s %-6s %4s %s\n", comm, pid, rval, filename
|
272
|
+
}
|
273
|
+
|
274
|
+
$0 ~ /LOST.*EVENTS/ {
|
275
|
+
delete lastfile
|
276
|
+
print "WARNING: " $0 > "/dev/stderr" }
|
277
|
+
'
|
278
|
+
|
279
|
+
### end tracing
|
280
|
+
end
|