Commit bdf0773f authored by Alexei Starovoitov's avatar Alexei Starovoitov

fix pep8 lint errors in the rest of the tools

no functional changes
Signed-off-by: default avatarAlexei Starovoitov <ast@fb.com>
parent a0aa7f28
...@@ -5,7 +5,7 @@ biolatency traces block device I/O (disk I/O), and records the distribution ...@@ -5,7 +5,7 @@ biolatency traces block device I/O (disk I/O), and records the distribution
of I/O latency (time), printing this as a histogram when Ctrl-C is hit. of I/O latency (time), printing this as a histogram when Ctrl-C is hit.
For example: For example:
# ./biolatency # ./biolatency
Tracing block device I/O... Hit Ctrl-C to end. Tracing block device I/O... Hit Ctrl-C to end.
^C ^C
usecs : count distribution usecs : count distribution
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# funccount Count kernel function calls. # funccount Count kernel function calls.
# For Linux, uses BCC, eBPF. See .c file. # For Linux, uses BCC, eBPF. See .c file.
# #
# USAGE: funccount [-h] [-p PID] [-i INTERVAL] [-T] [-r] pattern # USAGE: funccount [-h] [-p PID] [-i INTERVAL] [-T] [-r] pattern
# #
...@@ -11,7 +12,7 @@ ...@@ -11,7 +12,7 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 09-Sep-2015 Brendan Gregg Created this. # 09-Sep-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -28,63 +29,63 @@ examples = """examples: ...@@ -28,63 +29,63 @@ examples = """examples:
./funccount -p 185 'vfs_*' # count vfs calls for PID 181 only ./funccount -p 185 'vfs_*' # count vfs calls for PID 181 only
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Count kernel function calls", description="Count kernel function calls",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-p", "--pid", parser.add_argument("-p", "--pid",
help="trace this PID only") help="trace this PID only")
parser.add_argument("-i", "--interval", default=99999999, parser.add_argument("-i", "--interval", default=99999999,
help="summary interval, seconds") help="summary interval, seconds")
parser.add_argument("-T", "--timestamp", action="store_true", parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-r", "--regexp", action="store_true", parser.add_argument("-r", "--regexp", action="store_true",
help="use regular expressions. Default is \"*\" wildcards only.") help="use regular expressions. Default is \"*\" wildcards only.")
parser.add_argument("pattern", parser.add_argument("pattern",
help="search expression for kernel functions") help="search expression for kernel functions")
args = parser.parse_args() args = parser.parse_args()
pattern = args.pattern pattern = args.pattern
if not args.regexp: if not args.regexp:
pattern = pattern.replace('*', '.*') pattern = pattern.replace('*', '.*')
pattern = '^' + pattern + '$' pattern = '^' + pattern + '$'
debug = 0 debug = 0
# signal handler # signal handler
def signal_ignore(signal, frame): def signal_ignore(signal, frame):
print() print()
# load BPF program # load BPF program
bpf_text = """ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
struct key_t { struct key_t {
u64 ip; u64 ip;
}; };
BPF_HASH(counts, struct key_t); BPF_HASH(counts, struct key_t);
int trace_count(struct pt_regs *ctx) { int trace_count(struct pt_regs *ctx) {
FILTER FILTER
struct key_t key = {}; struct key_t key = {};
u64 zero = 0, *val; u64 zero = 0, *val;
key.ip = ctx->ip; key.ip = ctx->ip;
val = counts.lookup_or_init(&key, &zero); val = counts.lookup_or_init(&key, &zero);
(*val)++; (*val)++;
return 0; return 0;
} }
""" """
if args.pid: if args.pid:
bpf_text = bpf_text.replace('FILTER', bpf_text = bpf_text.replace('FILTER',
('u32 pid; pid = bpf_get_current_pid_tgid(); ' + ('u32 pid; pid = bpf_get_current_pid_tgid(); ' +
'if (pid != %s) { return 0; }') % (args.pid)) 'if (pid != %s) { return 0; }') % (args.pid))
else: else:
bpf_text = bpf_text.replace('FILTER', '') bpf_text = bpf_text.replace('FILTER', '')
if debug: if debug:
print(bpf_text) print(bpf_text)
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
b.attach_kprobe(event_re=pattern, fn_name="trace_count") b.attach_kprobe(event_re=pattern, fn_name="trace_count")
matched = b.num_open_kprobes() matched = b.num_open_kprobes()
if matched == 0: if matched == 0:
print("0 functions matched by \"%s\". Exiting." % args.pattern) print("0 functions matched by \"%s\". Exiting." % args.pattern)
exit() exit()
# header # header
print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." % print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
...@@ -93,23 +94,23 @@ print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." % ...@@ -93,23 +94,23 @@ print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
# output # output
exiting = 0 if args.interval else 1 exiting = 0 if args.interval else 1
while (1): while (1):
try: try:
sleep(int(args.interval)) sleep(int(args.interval))
except KeyboardInterrupt: except KeyboardInterrupt:
exiting=1 exiting = 1
# as cleanup can take many seconds, trap Ctrl-C: # as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, signal_ignore) signal.signal(signal.SIGINT, signal_ignore)
print() print()
if args.timestamp: if args.timestamp:
print("%-8s\n" % strftime("%H:%M:%S"), end="") print("%-8s\n" % strftime("%H:%M:%S"), end="")
print("%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT")) print("%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT"))
counts = b.get_table("counts") counts = b.get_table("counts")
for k, v in sorted(counts.items(), key=lambda counts: counts[1].value): for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
print("%-16x %-26s %8d" % (k.ip, b.ksym(k.ip), v.value)) print("%-16x %-26s %8d" % (k.ip, b.ksym(k.ip), v.value))
counts.clear() counts.clear()
if exiting: if exiting:
print("Detaching...") print("Detaching...")
exit() exit()
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# funclatency Time kernel funcitons and print latency as a histogram. # funclatency Time kernel funcitons and print latency as a histogram.
# For Linux, uses BCC, eBPF. # For Linux, uses BCC, eBPF.
# #
# USAGE: funclatency [-h] [-p PID] [-i INTERVAL] [-T] [-u] [-m] [-r] pattern # USAGE: funclatency [-h] [-p PID] [-i INTERVAL] [-T] [-u] [-m] [-r] pattern
# #
...@@ -20,7 +21,7 @@ ...@@ -20,7 +21,7 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 20-Sep-2015 Brendan Gregg Created this. # 20-Sep-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -39,30 +40,30 @@ examples = """examples: ...@@ -39,30 +40,30 @@ examples = """examples:
./funclatency -F 'vfs_r*' # show one histogram per matched function ./funclatency -F 'vfs_r*' # show one histogram per matched function
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Time kernel funcitons and print latency as a histogram", description="Time kernel funcitons and print latency as a histogram",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-p", "--pid", parser.add_argument("-p", "--pid",
help="trace this PID only") help="trace this PID only")
parser.add_argument("-i", "--interval", default=99999999, parser.add_argument("-i", "--interval", default=99999999,
help="summary interval, seconds") help="summary interval, seconds")
parser.add_argument("-T", "--timestamp", action="store_true", parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-u", "--microseconds", action="store_true", parser.add_argument("-u", "--microseconds", action="store_true",
help="microsecond histogram") help="microsecond histogram")
parser.add_argument("-m", "--milliseconds", action="store_true", parser.add_argument("-m", "--milliseconds", action="store_true",
help="millisecond histogram") help="millisecond histogram")
parser.add_argument("-F", "--function", action="store_true", parser.add_argument("-F", "--function", action="store_true",
help="show a separate histogram per function") help="show a separate histogram per function")
parser.add_argument("-r", "--regexp", action="store_true", parser.add_argument("-r", "--regexp", action="store_true",
help="use regular expressions. Default is \"*\" wildcards only.") help="use regular expressions. Default is \"*\" wildcards only.")
parser.add_argument("pattern", parser.add_argument("pattern",
help="search expression for kernel functions") help="search expression for kernel functions")
args = parser.parse_args() args = parser.parse_args()
pattern = args.pattern pattern = args.pattern
if not args.regexp: if not args.regexp:
pattern = pattern.replace('*', '.*') pattern = pattern.replace('*', '.*')
pattern = '^' + pattern + '$' pattern = '^' + pattern + '$'
debug = 0 debug = 0
# define BPF program # define BPF program
...@@ -71,8 +72,8 @@ bpf_text = """ ...@@ -71,8 +72,8 @@ bpf_text = """
#include <linux/blkdev.h> #include <linux/blkdev.h>
typedef struct ip_key { typedef struct ip_key {
u64 ip; u64 ip;
u64 slot; u64 slot;
} ip_key_t; } ip_key_t;
BPF_HASH(start, u32); BPF_HASH(start, u32);
...@@ -80,73 +81,73 @@ STORAGE ...@@ -80,73 +81,73 @@ STORAGE
int trace_func_entry(struct pt_regs *ctx) int trace_func_entry(struct pt_regs *ctx)
{ {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
u64 ts = bpf_ktime_get_ns(); u64 ts = bpf_ktime_get_ns();
FILTER FILTER
ENTRYSTORE ENTRYSTORE
start.update(&pid, &ts); start.update(&pid, &ts);
return 0; return 0;
} }
int trace_func_return(struct pt_regs *ctx) int trace_func_return(struct pt_regs *ctx)
{ {
u64 *tsp, delta; u64 *tsp, delta;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
// calculate delta time // calculate delta time
tsp = start.lookup(&pid); tsp = start.lookup(&pid);
if (tsp == 0) { if (tsp == 0) {
return 0; // missed start return 0; // missed start
} }
delta = bpf_ktime_get_ns() - *tsp; delta = bpf_ktime_get_ns() - *tsp;
start.delete(&pid); start.delete(&pid);
FACTOR FACTOR
// store as histogram // store as histogram
STORE STORE
return 0; return 0;
} }
""" """
# code substitutions # code substitutions
if args.pid: if args.pid:
bpf_text = bpf_text.replace('FILTER', bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid) 'if (pid != %s) { return 0; }' % args.pid)
else: else:
bpf_text = bpf_text.replace('FILTER', '') bpf_text = bpf_text.replace('FILTER', '')
if args.milliseconds: if args.milliseconds:
bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000000;') bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000000;')
label = "msecs" label = "msecs"
elif args.microseconds: elif args.microseconds:
bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000;') bpf_text = bpf_text.replace('FACTOR', 'delta /= 1000;')
label = "usecs" label = "usecs"
else: else:
bpf_text = bpf_text.replace('FACTOR', '') bpf_text = bpf_text.replace('FACTOR', '')
label = "nsecs" label = "nsecs"
if args.function: if args.function:
bpf_text = bpf_text.replace('STORAGE', 'BPF_HASH(ipaddr, u32);\n' + bpf_text = bpf_text.replace('STORAGE', 'BPF_HASH(ipaddr, u32);\n' +
'BPF_HISTOGRAM(dist, ip_key_t);') 'BPF_HISTOGRAM(dist, ip_key_t);')
# stash the IP on entry, as on return it's kretprobe_trampoline: # stash the IP on entry, as on return it's kretprobe_trampoline:
bpf_text = bpf_text.replace('ENTRYSTORE', bpf_text = bpf_text.replace('ENTRYSTORE',
'u64 ip = ctx->ip; ipaddr.update(&pid, &ip);') 'u64 ip = ctx->ip; ipaddr.update(&pid, &ip);')
bpf_text = bpf_text.replace('STORE', bpf_text = bpf_text.replace('STORE',
'u64 ip, *ipp = ipaddr.lookup(&pid); if (ipp) { ip = *ipp; ' + 'u64 ip, *ipp = ipaddr.lookup(&pid); if (ipp) { ip = *ipp; ' +
'dist.increment((ip_key_t){ip, bpf_log2l(delta)}); ' + 'dist.increment((ip_key_t){ip, bpf_log2l(delta)}); ' +
'ipaddr.delete(&pid); }') 'ipaddr.delete(&pid); }')
else: else:
bpf_text = bpf_text.replace('STORAGE', 'BPF_HISTOGRAM(dist);') bpf_text = bpf_text.replace('STORAGE', 'BPF_HISTOGRAM(dist);')
bpf_text = bpf_text.replace('ENTRYSTORE', '') bpf_text = bpf_text.replace('ENTRYSTORE', '')
bpf_text = bpf_text.replace('STORE', bpf_text = bpf_text.replace('STORE',
'dist.increment(bpf_log2l(delta));') 'dist.increment(bpf_log2l(delta));')
if debug: if debug:
print(bpf_text) print(bpf_text)
# signal handler # signal handler
def signal_ignore(signal, frame): def signal_ignore(signal, frame):
print() print()
# load BPF program # load BPF program
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
...@@ -154,8 +155,8 @@ b.attach_kprobe(event_re=pattern, fn_name="trace_func_entry") ...@@ -154,8 +155,8 @@ b.attach_kprobe(event_re=pattern, fn_name="trace_func_entry")
b.attach_kretprobe(event_re=pattern, fn_name="trace_func_return") b.attach_kretprobe(event_re=pattern, fn_name="trace_func_return")
matched = b.num_open_kprobes() matched = b.num_open_kprobes()
if matched == 0: if matched == 0:
print("0 functions matched by \"%s\". Exiting." % args.pattern) print("0 functions matched by \"%s\". Exiting." % args.pattern)
exit() exit()
# header # header
print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." % print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
...@@ -165,23 +166,23 @@ print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." % ...@@ -165,23 +166,23 @@ print("Tracing %d functions for \"%s\"... Hit Ctrl-C to end." %
exiting = 0 if args.interval else 1 exiting = 0 if args.interval else 1
dist = b.get_table("dist") dist = b.get_table("dist")
while (1): while (1):
try: try:
sleep(int(args.interval)) sleep(int(args.interval))
except KeyboardInterrupt: except KeyboardInterrupt:
exiting=1 exiting = 1
# as cleanup can take many seconds, trap Ctrl-C: # as cleanup can take many seconds, trap Ctrl-C:
signal.signal(signal.SIGINT, signal_ignore) signal.signal(signal.SIGINT, signal_ignore)
print() print()
if args.timestamp: if args.timestamp:
print("%-8s\n" % strftime("%H:%M:%S"), end="") print("%-8s\n" % strftime("%H:%M:%S"), end="")
if args.function: if args.function:
dist.print_log2_hist(label, "Function", BPF.ksym) dist.print_log2_hist(label, "Function", BPF.ksym)
else: else:
dist.print_log2_hist(label) dist.print_log2_hist(label)
dist.clear() dist.clear()
if exiting: if exiting:
print("Detaching...") print("Detaching...")
exit() exit()
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# hardirqs Summarize hard IRQ (interrupt) event time. # hardirqs Summarize hard IRQ (interrupt) event time.
# For Linux, uses BCC, eBPF. # For Linux, uses BCC, eBPF.
# #
# USAGE: hardirqs [-h] [-T] [-Q] [-m] [-D] [interval] [count] # USAGE: hardirqs [-h] [-T] [-Q] [-m] [-D] [interval] [count]
# #
...@@ -10,7 +11,7 @@ ...@@ -10,7 +11,7 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 19-Oct-2015 Brendan Gregg Created this. # 19-Oct-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -25,27 +26,27 @@ examples = """examples: ...@@ -25,27 +26,27 @@ examples = """examples:
./hardirqs -NT 1 # 1s summaries, nanoseconds, and timestamps ./hardirqs -NT 1 # 1s summaries, nanoseconds, and timestamps
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Summarize hard irq event time as histograms", description="Summarize hard irq event time as histograms",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-T", "--timestamp", action="store_true", parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-N", "--nanoseconds", action="store_true", parser.add_argument("-N", "--nanoseconds", action="store_true",
help="output in nanoseconds") help="output in nanoseconds")
parser.add_argument("-d", "--dist", action="store_true", parser.add_argument("-d", "--dist", action="store_true",
help="show distributions as histograms") help="show distributions as histograms")
parser.add_argument("interval", nargs="?", default=99999999, parser.add_argument("interval", nargs="?", default=99999999,
help="output interval, in seconds") help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999, parser.add_argument("count", nargs="?", default=99999999,
help="number of outputs") help="number of outputs")
args = parser.parse_args() args = parser.parse_args()
countdown = int(args.count) countdown = int(args.count)
if args.nanoseconds: if args.nanoseconds:
factor = 1 factor = 1
label = "nsecs" label = "nsecs"
else: else:
factor = 1000 factor = 1000
label = "usecs" label = "usecs"
debug = 0 debug = 0
### define BPF program ### define BPF program
...@@ -56,8 +57,8 @@ bpf_text = """ ...@@ -56,8 +57,8 @@ bpf_text = """
#include <linux/interrupt.h> #include <linux/interrupt.h>
typedef struct irq_key { typedef struct irq_key {
char name[32]; char name[32];
u64 slot; u64 slot;
} irq_key_t; } irq_key_t;
BPF_HASH(start, u32); BPF_HASH(start, u32);
BPF_HASH(irqdesc, u32, struct irq_desc *); BPF_HASH(irqdesc, u32, struct irq_desc *);
...@@ -66,59 +67,59 @@ BPF_HISTOGRAM(dist, irq_key_t); ...@@ -66,59 +67,59 @@ BPF_HISTOGRAM(dist, irq_key_t);
// time IRQ // time IRQ
int trace_start(struct pt_regs *ctx, struct irq_desc *desc) int trace_start(struct pt_regs *ctx, struct irq_desc *desc)
{ {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
u64 ts = bpf_ktime_get_ns(); u64 ts = bpf_ktime_get_ns();
start.update(&pid, &ts); start.update(&pid, &ts);
irqdesc.update(&pid, &desc); irqdesc.update(&pid, &desc);
return 0; return 0;
} }
int trace_completion(struct pt_regs *ctx) int trace_completion(struct pt_regs *ctx)
{ {
u64 *tsp, delta; u64 *tsp, delta;
struct irq_desc **descp; struct irq_desc **descp;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
// fetch timestamp and calculate delta // fetch timestamp and calculate delta
tsp = start.lookup(&pid); tsp = start.lookup(&pid);
descp = irqdesc.lookup(&pid); descp = irqdesc.lookup(&pid);
if (tsp == 0 || descp == 0) { if (tsp == 0 || descp == 0) {
return 0; // missed start return 0; // missed start
} }
// Note: descp is a value from map, so '&' can be done without // Note: descp is a value from map, so '&' can be done without
// probe_read, but the next level irqaction * needs a probe read. // probe_read, but the next level irqaction * needs a probe read.
// Do these steps first after reading the map, otherwise some of these // Do these steps first after reading the map, otherwise some of these
// pointers may get pushed onto the stack and verifier will fail. // pointers may get pushed onto the stack and verifier will fail.
struct irqaction *action = 0; struct irqaction *action = 0;
bpf_probe_read(&action, sizeof(action), &(*descp)->action); bpf_probe_read(&action, sizeof(action), &(*descp)->action);
const char **namep = &action->name; const char **namep = &action->name;
char *name = 0; char *name = 0;
bpf_probe_read(&name, sizeof(name), namep); bpf_probe_read(&name, sizeof(name), namep);
delta = bpf_ktime_get_ns() - *tsp; delta = bpf_ktime_get_ns() - *tsp;
// store as sum or histogram // store as sum or histogram
STORE STORE
start.delete(&pid); start.delete(&pid);
irqdesc.delete(&pid); irqdesc.delete(&pid);
return 0; return 0;
} }
""" """
### code substitutions ### code substitutions
if args.dist: if args.dist:
bpf_text = bpf_text.replace('STORE', bpf_text = bpf_text.replace('STORE',
'irq_key_t key = {.slot = bpf_log2l(delta)};' + 'irq_key_t key = {.slot = bpf_log2l(delta)};' +
'bpf_probe_read(&key.name, sizeof(key.name), name);' + 'bpf_probe_read(&key.name, sizeof(key.name), name);' +
'dist.increment(key);') 'dist.increment(key);')
else: else:
bpf_text = bpf_text.replace('STORE', bpf_text = bpf_text.replace('STORE',
'irq_key_t key = {.slot = 0 /* ignore */};' + 'irq_key_t key = {.slot = 0 /* ignore */};' +
'bpf_probe_read(&key.name, sizeof(key.name), name);' + 'bpf_probe_read(&key.name, sizeof(key.name), name);' +
'u64 zero = 0, *vp = dist.lookup_or_init(&key, &zero);' + 'u64 zero = 0, *vp = dist.lookup_or_init(&key, &zero);' +
'(*vp) += delta;') '(*vp) += delta;')
if debug: if debug:
print(bpf_text) print(bpf_text)
### load BPF program ### load BPF program
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
...@@ -133,23 +134,23 @@ print("Tracing hard irq event time... Hit Ctrl-C to end.") ...@@ -133,23 +134,23 @@ print("Tracing hard irq event time... Hit Ctrl-C to end.")
exiting = 0 if args.interval else 1 exiting = 0 if args.interval else 1
dist = b.get_table("dist") dist = b.get_table("dist")
while (1): while (1):
try: try:
sleep(int(args.interval)) sleep(int(args.interval))
except KeyboardInterrupt: except KeyboardInterrupt:
exiting=1 exiting = 1
print() print()
if args.timestamp: if args.timestamp:
print("%-8s\n" % strftime("%H:%M:%S"), end="") print("%-8s\n" % strftime("%H:%M:%S"), end="")
if args.dist: if args.dist:
dist.print_log2_hist(label, "hardirq") dist.print_log2_hist(label, "hardirq")
else: else:
print("%-26s %11s" % ("HARDIRQ", "TOTAL_" + label)) print("%-26s %11s" % ("HARDIRQ", "TOTAL_" + label))
for k, v in sorted(dist.items(), key=lambda dist: dist[1].value): for k, v in sorted(dist.items(), key=lambda dist: dist[1].value):
print("%-26s %11d" % (k.name, v.value / factor)) print("%-26s %11d" % (k.name, v.value / factor))
dist.clear() dist.clear()
countdown -= 1 countdown -= 1
if exiting or countdown == 0: if exiting or countdown == 0:
exit() exit()
...@@ -4,7 +4,7 @@ Demonstrations of hardirqs, the Linux eBPF/bcc version. ...@@ -4,7 +4,7 @@ Demonstrations of hardirqs, the Linux eBPF/bcc version.
This program traces hard interrupts (irqs), and stores timing statistics This program traces hard interrupts (irqs), and stores timing statistics
in-kernel for efficiency. For example: in-kernel for efficiency. For example:
# ./hardirqs # ./hardirqs
Tracing hard irq event time... Hit Ctrl-C to end. Tracing hard irq event time... Hit Ctrl-C to end.
^C ^C
HARDIRQ TOTAL_usecs HARDIRQ TOTAL_usecs
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# killsnoop Trace signals issued by the kill() syscall. # killsnoop Trace signals issued by the kill() syscall.
# For Linux, uses BCC, eBPF. Embedded C. # For Linux, uses BCC, eBPF. Embedded C.
# #
# USAGE: killsnoop [-h] [-t] [-x] [-p PID] # USAGE: killsnoop [-h] [-t] [-x] [-p PID]
# #
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 20-Sep-2015 Brendan Gregg Created this. # 20-Sep-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -22,15 +23,15 @@ examples = """examples: ...@@ -22,15 +23,15 @@ examples = """examples:
./killsnoop -p 181 # only trace PID 181 ./killsnoop -p 181 # only trace PID 181
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Trace signals issued by the kill() syscall", description="Trace signals issued by the kill() syscall",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-t", "--timestamp", action="store_true", parser.add_argument("-t", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-x", "--failed", action="store_true", parser.add_argument("-x", "--failed", action="store_true",
help="only show failed opens") help="only show failed opens")
parser.add_argument("-p", "--pid", parser.add_argument("-p", "--pid",
help="trace this PID only") help="trace this PID only")
args = parser.parse_args() args = parser.parse_args()
debug = 0 debug = 0
...@@ -43,63 +44,63 @@ BPF_HASH(args_sig, u32, int); ...@@ -43,63 +44,63 @@ BPF_HASH(args_sig, u32, int);
int kprobe__sys_kill(struct pt_regs *ctx, int tpid, int sig) int kprobe__sys_kill(struct pt_regs *ctx, int tpid, int sig)
{ {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
FILTER FILTER
args_pid.update(&pid, &tpid); args_pid.update(&pid, &tpid);
args_sig.update(&pid, &sig); args_sig.update(&pid, &sig);
return 0; return 0;
}; };
int kretprobe__sys_kill(struct pt_regs *ctx) int kretprobe__sys_kill(struct pt_regs *ctx)
{ {
int *tpidp, *sigp, ret = ctx->ax; int *tpidp, *sigp, ret = ctx->ax;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
tpidp = args_pid.lookup(&pid); tpidp = args_pid.lookup(&pid);
sigp = args_sig.lookup(&pid); sigp = args_sig.lookup(&pid);
if (tpidp == 0 || sigp == 0) { if (tpidp == 0 || sigp == 0) {
return 0; // missed entry return 0; // missed entry
} }
bpf_trace_printk("%d %d %d\\n", *tpidp, *sigp, ret); bpf_trace_printk("%d %d %d\\n", *tpidp, *sigp, ret);
args_pid.delete(&pid); args_pid.delete(&pid);
args_sig.delete(&pid); args_sig.delete(&pid);
return 0; return 0;
} }
""" """
if args.pid: if args.pid:
bpf_text = bpf_text.replace('FILTER', bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid) 'if (pid != %s) { return 0; }' % args.pid)
else: else:
bpf_text = bpf_text.replace('FILTER', '') bpf_text = bpf_text.replace('FILTER', '')
if debug: if debug:
print(bpf_text) print(bpf_text)
# initialize BPF # initialize BPF
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
# header # header
if args.timestamp: if args.timestamp:
print("%-14s" % ("TIME(s)"), end="") print("%-14s" % ("TIME(s)"), end="")
print("%-6s %-16s %-4s %-6s %s" % ("PID", "COMM", "SIG", "TPID", "RESULT")) print("%-6s %-16s %-4s %-6s %s" % ("PID", "COMM", "SIG", "TPID", "RESULT"))
start_ts = 0 start_ts = 0
# format output # format output
while 1: while 1:
(task, pid, cpu, flags, ts, msg) = b.trace_fields() (task, pid, cpu, flags, ts, msg) = b.trace_fields()
(tpid_s, sig_s, ret_s) = msg.split(" ") (tpid_s, sig_s, ret_s) = msg.split(" ")
ret = int(ret_s) ret = int(ret_s)
if (args.failed and (ret >= 0)): if (args.failed and (ret >= 0)):
continue continue
# print columns # print columns
if args.timestamp: if args.timestamp:
if start_ts == 0: if start_ts == 0:
start_ts = ts start_ts = ts
print("%-14.9f" % (ts - start_ts), end="") print("%-14.9f" % (ts - start_ts), end="")
print("%-6d %-16s %-4s %-6s %s" % (pid, task, sig_s, tpid_s, ret_s)) print("%-6d %-16s %-4s %-6s %s" % (pid, task, sig_s, tpid_s, ret_s))
...@@ -3,7 +3,7 @@ Demonstrations of killsnoop, the Linux eBPF/bcc version. ...@@ -3,7 +3,7 @@ Demonstrations of killsnoop, the Linux eBPF/bcc version.
This traces signals sent via the kill() syscall. For example: This traces signals sent via the kill() syscall. For example:
# ./killsnoop # ./killsnoop
PID COMM SIG TPID RESULT PID COMM SIG TPID RESULT
17064 bash 9 27682 0 17064 bash 9 27682 0
17064 bash 9 27682 -3 17064 bash 9 27682 -3
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# opensnoop Trace open() syscalls. # opensnoop Trace open() syscalls.
# For Linux, uses BCC, eBPF. Embedded C. # For Linux, uses BCC, eBPF. Embedded C.
# #
# USAGE: opensnoop [-h] [-t] [-x] [-p PID] # USAGE: opensnoop [-h] [-t] [-x] [-p PID]
# #
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 17-Sep-2015 Brendan Gregg Created this. # 17-Sep-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -22,15 +23,15 @@ examples = """examples: ...@@ -22,15 +23,15 @@ examples = """examples:
./opensnoop -p 181 # only trace PID 181 ./opensnoop -p 181 # only trace PID 181
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Trace open() syscalls", description="Trace open() syscalls",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-t", "--timestamp", action="store_true", parser.add_argument("-t", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-x", "--failed", action="store_true", parser.add_argument("-x", "--failed", action="store_true",
help="only show failed opens") help="only show failed opens")
parser.add_argument("-p", "--pid", parser.add_argument("-p", "--pid",
help="trace this PID only") help="trace this PID only")
args = parser.parse_args() args = parser.parse_args()
debug = 0 debug = 0
...@@ -42,68 +43,70 @@ BPF_HASH(args_filename, u32, const char *); ...@@ -42,68 +43,70 @@ BPF_HASH(args_filename, u32, const char *);
int kprobe__sys_open(struct pt_regs *ctx, const char __user *filename) int kprobe__sys_open(struct pt_regs *ctx, const char __user *filename)
{ {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
FILTER FILTER
args_filename.update(&pid, &filename); args_filename.update(&pid, &filename);
return 0; return 0;
}; };
int kretprobe__sys_open(struct pt_regs *ctx) int kretprobe__sys_open(struct pt_regs *ctx)
{ {
const char **filenamep; const char **filenamep;
int ret = ctx->ax; int ret = ctx->ax;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
filenamep = args_filename.lookup(&pid); filenamep = args_filename.lookup(&pid);
if (filenamep == 0) { if (filenamep == 0) {
// missed entry // missed entry
return 0; return 0;
} }
bpf_trace_printk("%s %d\\n", *filenamep, ret); bpf_trace_printk("%s %d\\n", *filenamep, ret);
args_filename.delete(&pid); args_filename.delete(&pid);
return 0; return 0;
} }
""" """
if args.pid: if args.pid:
bpf_text = bpf_text.replace('FILTER', bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid) 'if (pid != %s) { return 0; }' % args.pid)
else: else:
bpf_text = bpf_text.replace('FILTER', '') bpf_text = bpf_text.replace('FILTER', '')
if debug: if debug:
print(bpf_text) print(bpf_text)
# initialize BPF # initialize BPF
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
# header # header
if args.timestamp: if args.timestamp:
print("%-14s" % ("TIME(s)"), end="") print("%-14s" % ("TIME(s)"), end="")
print("%-6s %-16s %4s %3s %s" % ("PID", "COMM", "FD", "ERR", "PATH")) print("%-6s %-16s %4s %3s %s" % ("PID", "COMM", "FD", "ERR", "PATH"))
start_ts = 0 start_ts = 0
# format output # format output
while 1: while 1:
(task, pid, cpu, flags, ts, msg) = b.trace_fields() (task, pid, cpu, flags, ts, msg) = b.trace_fields()
(filename, ret_s) = msg.split(" ") (filename, ret_s) = msg.split(" ")
ret = int(ret_s) ret = int(ret_s)
if (args.failed and (ret >= 0)): if (args.failed and (ret >= 0)):
continue continue
# split return value into FD and errno columns # split return value into FD and errno columns
if ret >= 0: if ret >= 0:
fd_s = ret; err = 0 fd_s = ret
else: err = 0
fd_s = "-1"; err = - ret else:
fd_s = "-1"
# print columns err = - ret
if args.timestamp:
if start_ts == 0: # print columns
start_ts = ts if args.timestamp:
print("%-14.9f" % (ts - start_ts), end="") if start_ts == 0:
print("%-6d %-16s %4s %3s %s" % (pid, task, fd_s, err, filename)) start_ts = ts
print("%-14.9f" % (ts - start_ts), end="")
print("%-6d %-16s %4s %3s %s" % (pid, task, fd_s, err, filename))
...@@ -5,38 +5,38 @@ opensnoop traces the open() syscall system-wide, and prints various details. ...@@ -5,38 +5,38 @@ opensnoop traces the open() syscall system-wide, and prints various details.
Example output: Example output:
# ./opensnoop # ./opensnoop
PID COMM FD ERR PATH PID COMM FD ERR PATH
17326 <...> 7 0 /sys/kernel/debug/tracing/trace_pipe 17326 <...> 7 0 /sys/kernel/debug/tracing/trace_pipe
1576 snmpd 9 0 /proc/net/dev 1576 snmpd 9 0 /proc/net/dev
1576 snmpd 11 0 /proc/net/if_inet6 1576 snmpd 11 0 /proc/net/if_inet6
1576 snmpd 11 0 /proc/sys/net/ipv4/neigh/eth0/retrans_time_ms 1576 snmpd 11 0 /proc/sys/net/ipv4/neigh/eth0/retrans_time_ms
1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/eth0/retrans_time_ms 1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/eth0/retrans_time_ms
1576 snmpd 11 0 /proc/sys/net/ipv6/conf/eth0/forwarding 1576 snmpd 11 0 /proc/sys/net/ipv6/conf/eth0/forwarding
1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/eth0/base_reachable_time_ms 1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/eth0/base_reachable_time_ms
1576 snmpd 11 0 /proc/sys/net/ipv4/neigh/lo/retrans_time_ms 1576 snmpd 11 0 /proc/sys/net/ipv4/neigh/lo/retrans_time_ms
1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/lo/retrans_time_ms 1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/lo/retrans_time_ms
1576 snmpd 11 0 /proc/sys/net/ipv6/conf/lo/forwarding 1576 snmpd 11 0 /proc/sys/net/ipv6/conf/lo/forwarding
1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/lo/base_reachable_time_ms 1576 snmpd 11 0 /proc/sys/net/ipv6/neigh/lo/base_reachable_time_ms
1576 snmpd 9 0 /proc/diskstats 1576 snmpd 9 0 /proc/diskstats
1576 snmpd 9 0 /proc/stat 1576 snmpd 9 0 /proc/stat
1576 snmpd 9 0 /proc/vmstat 1576 snmpd 9 0 /proc/vmstat
1956 supervise 9 0 supervise/status.new 1956 supervise 9 0 supervise/status.new
1956 supervise 9 0 supervise/status.new 1956 supervise 9 0 supervise/status.new
17358 run 3 0 /etc/ld.so.cache 17358 run 3 0 /etc/ld.so.cache
17358 run 3 0 /lib/x86_64-linux-gnu/libtinfo.so.5 17358 run 3 0 /lib/x86_64-linux-gnu/libtinfo.so.5
17358 run 3 0 /lib/x86_64-linux-gnu/libdl.so.2 17358 run 3 0 /lib/x86_64-linux-gnu/libdl.so.2
17358 run 3 0 /lib/x86_64-linux-gnu/libc.so.6 17358 run 3 0 /lib/x86_64-linux-gnu/libc.so.6
17358 run -1 6 /dev/tty 17358 run -1 6 /dev/tty
17358 run 3 0 /proc/meminfo 17358 run 3 0 /proc/meminfo
17358 run 3 0 /etc/nsswitch.conf 17358 run 3 0 /etc/nsswitch.conf
17358 run 3 0 /etc/ld.so.cache 17358 run 3 0 /etc/ld.so.cache
17358 run 3 0 /lib/x86_64-linux-gnu/libnss_compat.so.2 17358 run 3 0 /lib/x86_64-linux-gnu/libnss_compat.so.2
17358 run 3 0 /lib/x86_64-linux-gnu/libnsl.so.1 17358 run 3 0 /lib/x86_64-linux-gnu/libnsl.so.1
17358 run 3 0 /etc/ld.so.cache 17358 run 3 0 /etc/ld.so.cache
17358 run 3 0 /lib/x86_64-linux-gnu/libnss_nis.so.2 17358 run 3 0 /lib/x86_64-linux-gnu/libnss_nis.so.2
17358 run 3 0 /lib/x86_64-linux-gnu/libnss_files.so.2 17358 run 3 0 /lib/x86_64-linux-gnu/libnss_files.so.2
17358 run 3 0 /etc/passwd 17358 run 3 0 /etc/passwd
17358 run 3 0 ./run 17358 run 3 0 ./run
^C ^C
While tracing, the snmpd process opened various /proc files (reading metrics), While tracing, the snmpd process opened various /proc files (reading metrics),
...@@ -68,25 +68,19 @@ second. ...@@ -68,25 +68,19 @@ second.
The -x option only prints failed opens: The -x option only prints failed opens:
# ./opensnoop -x # ./opensnoop -x
PID COMM FD ERR PATH PID COMM FD ERR PATH
18372 run -1 6 /dev/tty 18372 run -1 6 /dev/tty
18373 run -1 6 /dev/tty 18373 run -1 6 /dev/tty
18373 multilog -1 13 lock 18373 multilog -1 13 lock
18372 multilog -1 13 lock 18372 multilog -1 13 lock
18384 df -1 2 /usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo 18384 df -1 2 /usr/share/locale/en_US.UTF-8/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo 18384 df -1 2 /usr/share/locale/en_US.utf8/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale/en_US/LC_MESSAGES/coreutils.mo 18384 df -1 2 /usr/share/locale/en_US/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo 18384 df -1 2 /usr/share/locale/en.UTF-8/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo 18384 df -1 2 /usr/share/locale/en.utf8/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale/en/LC_MESSAGES/coreutils.mo 18384 df -1 2 /usr/share/locale/en/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale-langpack/en_US.UTF-8/LC_MESSAGES/coreutils.mo 18385 run -1 6 /dev/tty
18384 df -1 2 /usr/share/locale-langpack/en_US.utf8/LC_MESSAGES/coreutils.mo 18386 run -1 6 /dev/tty
18384 df -1 2 /usr/share/locale-langpack/en_US/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale-langpack/en.UTF-8/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale-langpack/en.utf8/LC_MESSAGES/coreutils.mo
18384 df -1 2 /usr/share/locale-langpack/en/LC_MESSAGES/coreutils.mo
18385 run -1 6 /dev/tty
18386 run -1 6 /dev/tty
This caught a df command failing to open a coreutils.mo file, and trying from This caught a df command failing to open a coreutils.mo file, and trying from
different directories. different directories.
......
#!/usr/bin/python #!/usr/bin/python
# vim: ts=8 noet sw=8 # @lint-avoid-python-3-compatibility-imports
# #
# pidpersec Count new processes (via fork). # pidpersec Count new processes (via fork).
# For Linux, uses BCC, eBPF. See .c file. # For Linux, uses BCC, eBPF. See .c file.
# #
# USAGE: pidpersec # USAGE: pidpersec
# #
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 11-Aug-2015 Brendan Gregg Created this. # 11-Aug-2015 Brendan Gregg Created this.
from bcc import BPF from bcc import BPF
from ctypes import c_ushort, c_int, c_ulonglong from ctypes import c_int
from time import sleep, strftime from time import sleep, strftime
# load BPF program # load BPF program
b = BPF(src_file = "pidpersec.c") b = BPF(src_file="pidpersec.c")
b.attach_kprobe(event="sched_fork", fn_name="do_count") b.attach_kprobe(event="sched_fork", fn_name="do_count")
# stat indexes # stat indexes
...@@ -29,11 +29,11 @@ print("Tracing... Ctrl-C to end.") ...@@ -29,11 +29,11 @@ print("Tracing... Ctrl-C to end.")
# output # output
while (1): while (1):
try: try:
sleep(1) sleep(1)
except KeyboardInterrupt: except KeyboardInterrupt:
exit() exit()
print("%s: PIDs/sec: %d" % (strftime("%H:%M:%S"), print("%s: PIDs/sec: %d" % (strftime("%H:%M:%S"),
b["stats"][S_COUNT].value)) b["stats"][S_COUNT].value))
b["stats"].clear() b["stats"].clear()
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# softirqs Summarize soft IRQ (interrupt) event time. # softirqs Summarize soft IRQ (interrupt) event time.
# For Linux, uses BCC, eBPF. # For Linux, uses BCC, eBPF.
# #
# USAGE: softirqs [-h] [-T] [-N] [-d] [interval] [count] # USAGE: softirqs [-h] [-T] [-N] [-d] [interval] [count]
# #
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 20-Oct-2015 Brendan Gregg Created this. # 20-Oct-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -23,27 +24,27 @@ examples = """examples: ...@@ -23,27 +24,27 @@ examples = """examples:
./softirqs -NT 1 # 1s summaries, nanoseconds, and timestamps ./softirqs -NT 1 # 1s summaries, nanoseconds, and timestamps
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Summarize soft irq event time as histograms", description="Summarize soft irq event time as histograms",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-T", "--timestamp", action="store_true", parser.add_argument("-T", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-N", "--nanoseconds", action="store_true", parser.add_argument("-N", "--nanoseconds", action="store_true",
help="output in nanoseconds") help="output in nanoseconds")
parser.add_argument("-d", "--dist", action="store_true", parser.add_argument("-d", "--dist", action="store_true",
help="show distributions as histograms") help="show distributions as histograms")
parser.add_argument("interval", nargs="?", default=99999999, parser.add_argument("interval", nargs="?", default=99999999,
help="output interval, in seconds") help="output interval, in seconds")
parser.add_argument("count", nargs="?", default=99999999, parser.add_argument("count", nargs="?", default=99999999,
help="number of outputs") help="number of outputs")
args = parser.parse_args() args = parser.parse_args()
countdown = int(args.count) countdown = int(args.count)
if args.nanoseconds: if args.nanoseconds:
factor = 1 factor = 1
label = "nsecs" label = "nsecs"
else: else:
factor = 1000 factor = 1000
label = "usecs" label = "usecs"
debug = 0 debug = 0
### define BPF program ### define BPF program
...@@ -51,8 +52,8 @@ bpf_text = """ ...@@ -51,8 +52,8 @@ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
typedef struct irq_key { typedef struct irq_key {
u64 ip; u64 ip;
u64 slot; u64 slot;
} irq_key_t; } irq_key_t;
BPF_HASH(start, u32); BPF_HASH(start, u32);
BPF_HASH(iptr, u32); BPF_HASH(iptr, u32);
...@@ -61,48 +62,48 @@ BPF_HISTOGRAM(dist, irq_key_t); ...@@ -61,48 +62,48 @@ BPF_HISTOGRAM(dist, irq_key_t);
// time IRQ // time IRQ
int trace_start(struct pt_regs *ctx) int trace_start(struct pt_regs *ctx)
{ {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
u64 ip = ctx->ip, ts = bpf_ktime_get_ns(); u64 ip = ctx->ip, ts = bpf_ktime_get_ns();
start.update(&pid, &ts); start.update(&pid, &ts);
iptr.update(&pid, &ip); iptr.update(&pid, &ip);
return 0; return 0;
} }
int trace_completion(struct pt_regs *ctx) int trace_completion(struct pt_regs *ctx)
{ {
u64 *tsp, delta, ip, *ipp; u64 *tsp, delta, ip, *ipp;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
// fetch timestamp and calculate delta // fetch timestamp and calculate delta
tsp = start.lookup(&pid); tsp = start.lookup(&pid);
ipp = iptr.lookup(&pid); ipp = iptr.lookup(&pid);
if (tsp == 0 || ipp == 0) { if (tsp == 0 || ipp == 0) {
return 0; // missed start return 0; // missed start
} }
delta = bpf_ktime_get_ns() - *tsp; delta = bpf_ktime_get_ns() - *tsp;
ip = *ipp; ip = *ipp;
// store as sum or histogram // store as sum or histogram
STORE STORE
start.delete(&pid); start.delete(&pid);
iptr.delete(&pid); iptr.delete(&pid);
return 0; return 0;
} }
""" """
### code substitutions ### code substitutions
if args.dist: if args.dist:
bpf_text = bpf_text.replace('STORE', bpf_text = bpf_text.replace('STORE',
'irq_key_t key = {.ip = ip, .slot = bpf_log2l(delta)};' + 'irq_key_t key = {.ip = ip, .slot = bpf_log2l(delta)};' +
'dist.increment(key);') 'dist.increment(key);')
else: else:
bpf_text = bpf_text.replace('STORE', bpf_text = bpf_text.replace('STORE',
'irq_key_t key = {.ip = ip, .slot = 0 /* ignore */};' + 'irq_key_t key = {.ip = ip, .slot = 0 /* ignore */};' +
'u64 zero = 0, *vp = dist.lookup_or_init(&key, &zero);' + 'u64 zero = 0, *vp = dist.lookup_or_init(&key, &zero);' +
'(*vp) += delta;') '(*vp) += delta;')
if debug: if debug:
print(bpf_text) print(bpf_text)
### load BPF program ### load BPF program
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
...@@ -114,8 +115,8 @@ for softirqfunc in ("blk_iopoll_softirq", "blk_done_softirq", ...@@ -114,8 +115,8 @@ for softirqfunc in ("blk_iopoll_softirq", "blk_done_softirq",
"rcu_process_callbacks", "run_rebalance_domains", "tasklet_action", "rcu_process_callbacks", "run_rebalance_domains", "tasklet_action",
"tasklet_hi_action", "run_timer_softirq", "net_tx_action", "tasklet_hi_action", "run_timer_softirq", "net_tx_action",
"net_rx_action"): "net_rx_action"):
b.attach_kprobe(event=softirqfunc, fn_name="trace_start") b.attach_kprobe(event=softirqfunc, fn_name="trace_start")
b.attach_kretprobe(event=softirqfunc, fn_name="trace_completion") b.attach_kretprobe(event=softirqfunc, fn_name="trace_completion")
print("Tracing soft irq event time... Hit Ctrl-C to end.") print("Tracing soft irq event time... Hit Ctrl-C to end.")
...@@ -123,23 +124,23 @@ print("Tracing soft irq event time... Hit Ctrl-C to end.") ...@@ -123,23 +124,23 @@ print("Tracing soft irq event time... Hit Ctrl-C to end.")
exiting = 0 if args.interval else 1 exiting = 0 if args.interval else 1
dist = b.get_table("dist") dist = b.get_table("dist")
while (1): while (1):
try: try:
sleep(int(args.interval)) sleep(int(args.interval))
except KeyboardInterrupt: except KeyboardInterrupt:
exiting=1 exiting = 1
print() print()
if args.timestamp: if args.timestamp:
print("%-8s\n" % strftime("%H:%M:%S"), end="") print("%-8s\n" % strftime("%H:%M:%S"), end="")
if args.dist: if args.dist:
dist.print_log2_hist(label, "softirq", section_print_fn=b.ksym) dist.print_log2_hist(label, "softirq", section_print_fn=b.ksym)
else: else:
print("%-26s %11s" % ("SOFTIRQ", "TOTAL_" + label)) print("%-26s %11s" % ("SOFTIRQ", "TOTAL_" + label))
for k, v in sorted(dist.items(), key=lambda dist: dist[1].value): for k, v in sorted(dist.items(), key=lambda dist: dist[1].value):
print("%-26s %11d" % (b.ksym(k.ip), v.value / factor)) print("%-26s %11d" % (b.ksym(k.ip), v.value / factor))
dist.clear() dist.clear()
countdown -= 1 countdown -= 1
if exiting or countdown == 0: if exiting or countdown == 0:
exit() exit()
...@@ -4,7 +4,7 @@ Demonstrations of softirqs, the Linux eBPF/bcc version. ...@@ -4,7 +4,7 @@ Demonstrations of softirqs, the Linux eBPF/bcc version.
This program traces soft interrupts (irqs), and stores timing statistics This program traces soft interrupts (irqs), and stores timing statistics
in-kernel for efficiency. For example: in-kernel for efficiency. For example:
# ./softirqs # ./softirqs
Tracing soft irq event time... Hit Ctrl-C to end. Tracing soft irq event time... Hit Ctrl-C to end.
^C ^C
SOFTIRQ TOTAL_usecs SOFTIRQ TOTAL_usecs
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# syncsnoop Trace sync() syscall. # syncsnoop Trace sync() syscall.
# For Linux, uses BCC, eBPF. Embedded C. # For Linux, uses BCC, eBPF. Embedded C.
# #
# Written as a basic example of BCC trace & reformat. See # Written as a basic example of BCC trace & reformat. See
# examples/hello_world.py for a BCC trace with default output example. # examples/hello_world.py for a BCC trace with default output example.
...@@ -9,15 +10,15 @@ ...@@ -9,15 +10,15 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 13-Aug-2015 Brendan Gregg Created this. # 13-Aug-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
# load BPF program # load BPF program
b = BPF(text = """ b = BPF(text="""
void kprobe__sys_sync(void *ctx) { void kprobe__sys_sync(void *ctx) {
bpf_trace_printk("sync()\\n"); bpf_trace_printk("sync()\\n");
}; };
""") """)
...@@ -26,5 +27,5 @@ print("%-18s %s" % ("TIME(s)", "CALL")) ...@@ -26,5 +27,5 @@ print("%-18s %s" % ("TIME(s)", "CALL"))
# format output # format output
while 1: while 1:
(task, pid, cpu, flags, ts, msg) = b.trace_fields() (task, pid, cpu, flags, ts, msg) = b.trace_fields()
print("%-18.9f %s" % (ts, msg)) print("%-18.9f %s" % (ts, msg))
...@@ -3,7 +3,7 @@ Demonstrations of syncsnoop, the Linux eBPF/bcc version. ...@@ -3,7 +3,7 @@ Demonstrations of syncsnoop, the Linux eBPF/bcc version.
This program traces calls to the kernel sync() routine, with basic timestamps: This program traces calls to the kernel sync() routine, with basic timestamps:
# ./syncsnoop # ./syncsnoop
TIME(s) CALL TIME(s) CALL
16458148.611952 sync() 16458148.611952 sync()
16458151.533709 sync() 16458151.533709 sync()
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# tcpaccept Trace TCP accept()s. # tcpaccept Trace TCP accept()s.
# For Linux, uses BCC, eBPF. Embedded C. # For Linux, uses BCC, eBPF. Embedded C.
# #
# USAGE: tcpaccept [-h] [-t] [-p PID] # USAGE: tcpaccept [-h] [-t] [-p PID]
# #
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 13-Oct-2015 Brendan Gregg Created this. # 13-Oct-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -28,13 +29,13 @@ examples = """examples: ...@@ -28,13 +29,13 @@ examples = """examples:
./tcpaccept -p 181 # only trace PID 181 ./tcpaccept -p 181 # only trace PID 181
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Trace TCP accepts", description="Trace TCP accepts",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-t", "--timestamp", action="store_true", parser.add_argument("-t", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-p", "--pid", parser.add_argument("-p", "--pid",
help="trace this PID only") help="trace this PID only")
args = parser.parse_args() args = parser.parse_args()
debug = 0 debug = 0
...@@ -46,88 +47,88 @@ bpf_text = """ ...@@ -46,88 +47,88 @@ bpf_text = """
int kretprobe__inet_csk_accept(struct pt_regs *ctx) int kretprobe__inet_csk_accept(struct pt_regs *ctx)
{ {
struct sock *newsk = (struct sock *)ctx->ax; struct sock *newsk = (struct sock *)ctx->ax;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
if (newsk == NULL) if (newsk == NULL)
return 0; return 0;
// check this is TCP // check this is TCP
u8 protocol = 0; u8 protocol = 0;
// workaround for reading the sk_protocol bitfield: // workaround for reading the sk_protocol bitfield:
bpf_probe_read(&protocol, 1, (void *)((long)&newsk->sk_wmem_queued) - 3); bpf_probe_read(&protocol, 1, (void *)((long)&newsk->sk_wmem_queued) - 3);
if (protocol != IPPROTO_TCP) if (protocol != IPPROTO_TCP)
return 0; return 0;
// pull in details // pull in details
u16 family = 0, lport = 0; u16 family = 0, lport = 0;
u32 saddr = 0, daddr = 0; u32 saddr = 0, daddr = 0;
bpf_probe_read(&family, sizeof(family), &newsk->__sk_common.skc_family); bpf_probe_read(&family, sizeof(family), &newsk->__sk_common.skc_family);
bpf_probe_read(&lport, sizeof(lport), &newsk->__sk_common.skc_num); bpf_probe_read(&lport, sizeof(lport), &newsk->__sk_common.skc_num);
if (family == AF_INET) { if (family == AF_INET) {
bpf_probe_read(&saddr, sizeof(saddr), bpf_probe_read(&saddr, sizeof(saddr),
&newsk->__sk_common.skc_rcv_saddr); &newsk->__sk_common.skc_rcv_saddr);
bpf_probe_read(&daddr, sizeof(daddr), bpf_probe_read(&daddr, sizeof(daddr),
&newsk->__sk_common.skc_daddr); &newsk->__sk_common.skc_daddr);
// output // output
bpf_trace_printk("4 %x %x %d\\n", daddr, saddr, lport); bpf_trace_printk("4 %x %x %d\\n", daddr, saddr, lport);
} else if (family == AF_INET6) { } else if (family == AF_INET6) {
// just grab the last 4 bytes for now // just grab the last 4 bytes for now
bpf_probe_read(&saddr, sizeof(saddr), bpf_probe_read(&saddr, sizeof(saddr),
&newsk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[3]); &newsk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[3]);
bpf_probe_read(&daddr, sizeof(daddr), bpf_probe_read(&daddr, sizeof(daddr),
&newsk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[3]); &newsk->__sk_common.skc_v6_daddr.in6_u.u6_addr32[3]);
// output and flip byte order of addresses // output and flip byte order of addresses
bpf_trace_printk("6 %x %x %d\\n", bpf_ntohl(daddr), bpf_trace_printk("6 %x %x %d\\n", bpf_ntohl(daddr),
bpf_ntohl(saddr), lport); bpf_ntohl(saddr), lport);
} }
// else drop // else drop
return 0; return 0;
} }
""" """
# code substitutions # code substitutions
if args.pid: if args.pid:
bpf_text = bpf_text.replace('FILTER', bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid) 'if (pid != %s) { return 0; }' % args.pid)
else: else:
bpf_text = bpf_text.replace('FILTER', '') bpf_text = bpf_text.replace('FILTER', '')
if debug: if debug:
print(bpf_text) print(bpf_text)
# initialize BPF # initialize BPF
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
# header # header
if args.timestamp: if args.timestamp:
print("%-9s" % ("TIME(s)"), end="") print("%-9s" % ("TIME(s)"), end="")
print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "RADDR", print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "RADDR",
"LADDR", "LPORT")) "LADDR", "LPORT"))
start_ts = 0 start_ts = 0
def inet_ntoa(addr): def inet_ntoa(addr):
dq = '' dq = ''
for i in range(0, 4): for i in range(0, 4):
dq = dq + str(addr & 0xff) dq = dq + str(addr & 0xff)
if (i != 3): if (i != 3):
dq = dq + '.' dq = dq + '.'
addr = addr >> 8 addr = addr >> 8
return dq return dq
# format output # format output
while 1: while 1:
(task, pid, cpu, flags, ts, msg) = b.trace_fields() (task, pid, cpu, flags, ts, msg) = b.trace_fields()
(ip_s, raddr_hs, laddr_hs, lport_s) = msg.split(" ") (ip_s, raddr_hs, laddr_hs, lport_s) = msg.split(" ")
if args.timestamp: if args.timestamp:
if start_ts == 0: if start_ts == 0:
start_ts = ts start_ts = ts
print("%-9.3f" % (ts - start_ts), end="") print("%-9.3f" % (ts - start_ts), end="")
print("%-6d %-12.12s %-2s %-16s %-16s %-4s" % (pid, task, ip_s, print("%-6d %-12.12s %-2s %-16s %-16s %-4s" % (pid, task, ip_s,
inet_ntoa(int(raddr_hs, 16)) if ip_s == "4" else "..." + raddr_hs, inet_ntoa(int(raddr_hs, 16)) if ip_s == "4" else "..." + raddr_hs,
inet_ntoa(int(laddr_hs, 16)) if ip_s == "4" else "..." + laddr_hs, inet_ntoa(int(laddr_hs, 16)) if ip_s == "4" else "..." + laddr_hs,
lport_s)) lport_s))
...@@ -7,8 +7,8 @@ addresses changed to protect the innocent): ...@@ -7,8 +7,8 @@ addresses changed to protect the innocent):
# ./tcpaccept # ./tcpaccept
PID COMM IP RADDR LADDR LPORT PID COMM IP RADDR LADDR LPORT
907 sshd 4 192.168.56.1 192.168.56.102 22 907 sshd 4 192.168.56.1 192.168.56.102 22
907 sshd 4 127.0.0.1 127.0.0.1 22 907 sshd 4 127.0.0.1 127.0.0.1 22
5389 perl 6 ...fec0ae21 ...fec0ae21 7001 5389 perl 6 ...fec0ae21 ...fec0ae21 7001
This output shows three connections, two to PID 907, an "sshd" process listening This output shows three connections, two to PID 907, an "sshd" process listening
...@@ -30,9 +30,9 @@ The -t option prints a timestamp column: ...@@ -30,9 +30,9 @@ The -t option prints a timestamp column:
# ./tcpaccept -t # ./tcpaccept -t
TIME(s) PID COMM IP RADDR LADDR LPORT TIME(s) PID COMM IP RADDR LADDR LPORT
0.000 907 sshd 4 127.0.0.1 127.0.0.1 22 0.000 907 sshd 4 127.0.0.1 127.0.0.1 22
0.992 907 sshd 4 127.0.0.1 127.0.0.1 22 0.992 907 sshd 4 127.0.0.1 127.0.0.1 22
1.984 907 sshd 4 127.0.0.1 127.0.0.1 22 1.984 907 sshd 4 127.0.0.1 127.0.0.1 22
USAGE message: USAGE message:
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# tcpconnect Trace TCP connect()s. # tcpconnect Trace TCP connect()s.
# For Linux, uses BCC, eBPF. Embedded C. # For Linux, uses BCC, eBPF. Embedded C.
# #
# USAGE: tcpconnect [-h] [-t] [-p PID] # USAGE: tcpconnect [-h] [-t] [-p PID]
# #
...@@ -10,7 +11,7 @@ ...@@ -10,7 +11,7 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 25-Sep-2015 Brendan Gregg Created this. # 25-Sep-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
...@@ -23,13 +24,13 @@ examples = """examples: ...@@ -23,13 +24,13 @@ examples = """examples:
./tcpconnect -p 181 # only trace PID 181 ./tcpconnect -p 181 # only trace PID 181
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Trace TCP connects", description="Trace TCP connects",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=examples) epilog=examples)
parser.add_argument("-t", "--timestamp", action="store_true", parser.add_argument("-t", "--timestamp", action="store_true",
help="include timestamp on output") help="include timestamp on output")
parser.add_argument("-p", "--pid", parser.add_argument("-p", "--pid",
help="trace this PID only") help="trace this PID only")
args = parser.parse_args() args = parser.parse_args()
debug = 0 debug = 0
...@@ -43,82 +44,82 @@ BPF_HASH(currsock, u32, struct sock *); ...@@ -43,82 +44,82 @@ BPF_HASH(currsock, u32, struct sock *);
int trace_connect_entry(struct pt_regs *ctx, struct sock *sk) int trace_connect_entry(struct pt_regs *ctx, struct sock *sk)
{ {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
FILTER FILTER
// stash the sock ptr for lookup on return // stash the sock ptr for lookup on return
currsock.update(&pid, &sk); currsock.update(&pid, &sk);
return 0; return 0;
}; };
static int trace_connect_return(struct pt_regs *ctx, short ipver) static int trace_connect_return(struct pt_regs *ctx, short ipver)
{ {
int ret = ctx->ax; int ret = ctx->ax;
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
struct sock **skpp; struct sock **skpp;
skpp = currsock.lookup(&pid); skpp = currsock.lookup(&pid);
if (skpp == 0) { if (skpp == 0) {
return 0; // missed entry return 0; // missed entry
} }
if (ret != 0) { if (ret != 0) {
// failed to send SYNC packet, may not have populated // failed to send SYNC packet, may not have populated
// socket __sk_common.{skc_rcv_saddr, ...} // socket __sk_common.{skc_rcv_saddr, ...}
currsock.delete(&pid); currsock.delete(&pid);
return 0; return 0;
} }
// pull in details // pull in details
struct sock *skp = *skpp; struct sock *skp = *skpp;
u32 saddr = 0, daddr = 0; u32 saddr = 0, daddr = 0;
u16 dport = 0; u16 dport = 0;
bpf_probe_read(&dport, sizeof(dport), &skp->__sk_common.skc_dport); bpf_probe_read(&dport, sizeof(dport), &skp->__sk_common.skc_dport);
if (ipver == 4) { if (ipver == 4) {
bpf_probe_read(&saddr, sizeof(saddr), bpf_probe_read(&saddr, sizeof(saddr),
&skp->__sk_common.skc_rcv_saddr); &skp->__sk_common.skc_rcv_saddr);
bpf_probe_read(&daddr, sizeof(daddr), bpf_probe_read(&daddr, sizeof(daddr),
&skp->__sk_common.skc_daddr); &skp->__sk_common.skc_daddr);
// output // output
bpf_trace_printk("4 %x %x %d\\n", saddr, daddr, ntohs(dport)); bpf_trace_printk("4 %x %x %d\\n", saddr, daddr, ntohs(dport));
} else /* 6 */ { } else /* 6 */ {
// just grab the last 4 bytes for now // just grab the last 4 bytes for now
bpf_probe_read(&saddr, sizeof(saddr), bpf_probe_read(&saddr, sizeof(saddr),
&skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[3]); &skp->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[3]);
bpf_probe_read(&daddr, sizeof(daddr), bpf_probe_read(&daddr, sizeof(daddr),
&skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32[3]); &skp->__sk_common.skc_v6_daddr.in6_u.u6_addr32[3]);
// output and flip byte order of addresses // output and flip byte order of addresses
bpf_trace_printk("6 %x %x %d\\n", bpf_ntohl(saddr), bpf_trace_printk("6 %x %x %d\\n", bpf_ntohl(saddr),
bpf_ntohl(daddr), ntohs(dport)); bpf_ntohl(daddr), ntohs(dport));
} }
currsock.delete(&pid); currsock.delete(&pid);
return 0; return 0;
} }
int trace_connect_v4_return(struct pt_regs *ctx) int trace_connect_v4_return(struct pt_regs *ctx)
{ {
return trace_connect_return(ctx, 4); return trace_connect_return(ctx, 4);
} }
int trace_connect_v6_return(struct pt_regs *ctx) int trace_connect_v6_return(struct pt_regs *ctx)
{ {
return trace_connect_return(ctx, 6); return trace_connect_return(ctx, 6);
} }
""" """
# code substitutions # code substitutions
if args.pid: if args.pid:
bpf_text = bpf_text.replace('FILTER', bpf_text = bpf_text.replace('FILTER',
'if (pid != %s) { return 0; }' % args.pid) 'if (pid != %s) { return 0; }' % args.pid)
else: else:
bpf_text = bpf_text.replace('FILTER', '') bpf_text = bpf_text.replace('FILTER', '')
if debug: if debug:
print(bpf_text) print(bpf_text)
# initialize BPF # initialize BPF
b = BPF(text=bpf_text) b = BPF(text=bpf_text)
...@@ -129,31 +130,31 @@ b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return") ...@@ -129,31 +130,31 @@ b.attach_kretprobe(event="tcp_v6_connect", fn_name="trace_connect_v6_return")
# header # header
if args.timestamp: if args.timestamp:
print("%-9s" % ("TIME(s)"), end="") print("%-9s" % ("TIME(s)"), end="")
print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "SADDR", print("%-6s %-12s %-2s %-16s %-16s %-4s" % ("PID", "COMM", "IP", "SADDR",
"DADDR", "DPORT")) "DADDR", "DPORT"))
start_ts = 0 start_ts = 0
def inet_ntoa(addr): def inet_ntoa(addr):
dq = '' dq = ''
for i in range(0, 4): for i in range(0, 4):
dq = dq + str(addr & 0xff) dq = dq + str(addr & 0xff)
if (i != 3): if (i != 3):
dq = dq + '.' dq = dq + '.'
addr = addr >> 8 addr = addr >> 8
return dq return dq
# format output # format output
while 1: while 1:
(task, pid, cpu, flags, ts, msg) = b.trace_fields() (task, pid, cpu, flags, ts, msg) = b.trace_fields()
(ip_s, saddr_hs, daddr_hs, dport_s) = msg.split(" ") (ip_s, saddr_hs, daddr_hs, dport_s) = msg.split(" ")
if args.timestamp: if args.timestamp:
if start_ts == 0: if start_ts == 0:
start_ts = ts start_ts = ts
print("%-9.3f" % (ts - start_ts), end="") print("%-9.3f" % (ts - start_ts), end="")
print("%-6d %-12.12s %-2s %-16s %-16s %-4s" % (pid, task, ip_s, print("%-6d %-12.12s %-2s %-16s %-16s %-4s" % (pid, task, ip_s,
inet_ntoa(int(saddr_hs, 16)) if ip_s == "4" else "..." + saddr_hs, inet_ntoa(int(saddr_hs, 16)) if ip_s == "4" else "..." + saddr_hs,
inet_ntoa(int(daddr_hs, 16)) if ip_s == "4" else "..." + daddr_hs, inet_ntoa(int(daddr_hs, 16)) if ip_s == "4" else "..." + daddr_hs,
dport_s)) dport_s))
...@@ -5,12 +5,12 @@ This tool traces the kernel function performing active TCP connections ...@@ -5,12 +5,12 @@ This tool traces the kernel function performing active TCP connections
(eg, via a connect() syscall; accept() are passive connections). Some example (eg, via a connect() syscall; accept() are passive connections). Some example
output (IP addresses changed to protect the innocent): output (IP addresses changed to protect the innocent):
# ./tcpconnect # ./tcpconnect
PID COMM IP SADDR DADDR DPORT PID COMM IP SADDR DADDR DPORT
1479 telnet 4 127.0.0.1 127.0.0.1 23 1479 telnet 4 127.0.0.1 127.0.0.1 23
1469 curl 4 10.201.219.236 54.245.105.25 80 1469 curl 4 10.201.219.236 54.245.105.25 80
1469 curl 4 10.201.219.236 54.67.101.145 80 1469 curl 4 10.201.219.236 54.67.101.145 80
11072 ssh 6 ...fe8203ac ...fe82abcd 22 11072 ssh 6 ...fe8203ac ...fe82abcd 22
This output shows four connections, one from a "telnet" process, two from This output shows four connections, one from a "telnet" process, two from
"curl", and one from "ssh". The output details shows the IP version, source "curl", and one from "ssh". The output details shows the IP version, source
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# vfscount Count VFS calls ("vfs_*"). # vfscount Count VFS calls ("vfs_*").
# For Linux, uses BCC, eBPF. See .c file. # For Linux, uses BCC, eBPF. See .c file.
# #
# Written as a basic example of counting functions. # Written as a basic example of counting functions.
# #
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 14-Aug-2015 Brendan Gregg Created this. # 14-Aug-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
from time import sleep from time import sleep
# load BPF program # load BPF program
b = BPF(src_file = "vfscount.c") b = BPF(src_file="vfscount.c")
b.attach_kprobe(event_re="^vfs_.*", fn_name="do_count") b.attach_kprobe(event_re="^vfs_.*", fn_name="do_count")
# header # header
...@@ -23,11 +24,11 @@ print("Tracing... Ctrl-C to end.") ...@@ -23,11 +24,11 @@ print("Tracing... Ctrl-C to end.")
# output # output
try: try:
sleep(99999999) sleep(99999999)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
print("\n%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT")) print("\n%-16s %-26s %8s" % ("ADDR", "FUNC", "COUNT"))
counts = b.get_table("counts") counts = b.get_table("counts")
for k, v in sorted(counts.items(), key=lambda counts: counts[1].value): for k, v in sorted(counts.items(), key=lambda counts: counts[1].value):
print("%-16x %-26s %8d" % (k.ip, b.ksym(k.ip), v.value)) print("%-16x %-26s %8d" % (k.ip, b.ksym(k.ip), v.value))
...@@ -3,7 +3,7 @@ Demonstrations of vfscount, the Linux eBPF/bcc version. ...@@ -3,7 +3,7 @@ Demonstrations of vfscount, the Linux eBPF/bcc version.
This counts VFS calls, by tracing all kernel functions beginning with "vfs_": This counts VFS calls, by tracing all kernel functions beginning with "vfs_":
# ./vfscount # ./vfscount
Tracing... Ctrl-C to end. Tracing... Ctrl-C to end.
^C ^C
ADDR FUNC COUNT ADDR FUNC COUNT
......
#!/usr/bin/python #!/usr/bin/python
# @lint-avoid-python-3-compatibility-imports
# #
# vfsstat Count some VFS calls. # vfsstat Count some VFS calls.
# For Linux, uses BCC, eBPF. See .c file. # For Linux, uses BCC, eBPF. See .c file.
# #
# Written as a basic example of counting multiple events as a stat tool. # Written as a basic example of counting multiple events as a stat tool.
# #
...@@ -10,33 +11,33 @@ ...@@ -10,33 +11,33 @@
# Copyright (c) 2015 Brendan Gregg. # Copyright (c) 2015 Brendan Gregg.
# Licensed under the Apache License, Version 2.0 (the "License") # Licensed under the Apache License, Version 2.0 (the "License")
# #
# 14-Aug-2015 Brendan Gregg Created this. # 14-Aug-2015 Brendan Gregg Created this.
from __future__ import print_function from __future__ import print_function
from bcc import BPF from bcc import BPF
from ctypes import c_ushort, c_int, c_ulonglong from ctypes import c_int
from time import sleep, strftime from time import sleep, strftime
from sys import argv from sys import argv
def usage(): def usage():
print("USAGE: %s [interval [count]]" % argv[0]) print("USAGE: %s [interval [count]]" % argv[0])
exit() exit()
# arguments # arguments
interval = 1 interval = 1
count = -1 count = -1
if len(argv) > 1: if len(argv) > 1:
try: try:
interval = int(argv[1]) interval = int(argv[1])
if interval == 0: if interval == 0:
raise raise
if len(argv) > 2: if len(argv) > 2:
count = int(argv[2]) count = int(argv[2])
except: # also catches -h, --help except: # also catches -h, --help
usage() usage()
# load BPF program # load BPF program
b = BPF(src_file = "vfsstat.c") b = BPF(src_file="vfsstat.c")
b.attach_kprobe(event="vfs_read", fn_name="do_read") b.attach_kprobe(event="vfs_read", fn_name="do_read")
b.attach_kprobe(event="vfs_write", fn_name="do_write") b.attach_kprobe(event="vfs_write", fn_name="do_write")
b.attach_kprobe(event="vfs_fsync", fn_name="do_fsync") b.attach_kprobe(event="vfs_fsync", fn_name="do_fsync")
...@@ -45,40 +46,41 @@ b.attach_kprobe(event="vfs_create", fn_name="do_create") ...@@ -45,40 +46,41 @@ b.attach_kprobe(event="vfs_create", fn_name="do_create")
# stat column labels and indexes # stat column labels and indexes
stat_types = { stat_types = {
"READ" : 1, "READ": 1,
"WRITE" : 2, "WRITE": 2,
"FSYNC" : 3, "FSYNC": 3,
"OPEN" : 4, "OPEN": 4,
"CREATE" : 5 "CREATE": 5
} }
# header # header
print("%-8s " % "TIME", end="") print("%-8s " % "TIME", end="")
for stype in stat_types.keys(): for stype in stat_types.keys():
print(" %8s" % (stype + "/s"), end="") print(" %8s" % (stype + "/s"), end="")
idx = stat_types[stype] idx = stat_types[stype]
print("") print("")
# output # output
i = 0 i = 0
while (1): while (1):
if count > 0: if count > 0:
i += 1 i += 1
if i > count: if i > count:
exit() exit()
try: try:
sleep(interval) sleep(interval)
except KeyboardInterrupt: except KeyboardInterrupt:
pass; exit() pass
exit()
print("%-8s: " % strftime("%H:%M:%S"), end="") print("%-8s: " % strftime("%H:%M:%S"), end="")
# print each statistic as a column # print each statistic as a column
for stype in stat_types.keys(): for stype in stat_types.keys():
idx = stat_types[stype] idx = stat_types[stype]
try: try:
val = b["stats"][c_int(idx)].value / interval val = b["stats"][c_int(idx)].value / interval
print(" %8d" % val, end="") print(" %8d" % val, end="")
except: except:
print(" %8d" % 0, end="") print(" %8d" % 0, end="")
b["stats"].clear() b["stats"].clear()
print("") print("")
...@@ -4,7 +4,7 @@ Demonstrations of vfsstat, the Linux eBPF/bcc version. ...@@ -4,7 +4,7 @@ Demonstrations of vfsstat, the Linux eBPF/bcc version.
This traces some common VFS calls and prints per-second summaries. By default, This traces some common VFS calls and prints per-second summaries. By default,
the output interval is one second: the output interval is one second:
# ./vfsstat # ./vfsstat
TIME READ/s WRITE/s CREATE/s OPEN/s FSYNC/s TIME READ/s WRITE/s CREATE/s OPEN/s FSYNC/s
18:35:32: 231 12 4 98 0 18:35:32: 231 12 4 98 0
18:35:33: 274 13 4 106 0 18:35:33: 274 13 4 106 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment