Commit f41ae861 authored by Sasha Goldshtein's avatar Sasha Goldshtein Committed by 4ast

Tools lint cleanup (#764)

* argdist: linter cleanup

* cpudist: linter cleanup

* execsnoop: linter cleanup

* funclatency: linter cleanup

* gethostlatency: linter cleanup

* hardirqs: linter cleanup

* memleak: linter cleanup

* mountsnoop: linter cleanup

* offcputime: linter cleanup

* softirqs: linter cleanup

* solisten: linter cleanup and u+x mode

* stacksnoop: linter cleanup

* tplist: linter cleanup

* trace: linter cleanup
parent 78a3341c
...@@ -19,7 +19,7 @@ import sys ...@@ -19,7 +19,7 @@ import sys
class Probe(object): class Probe(object):
next_probe_index = 0 next_probe_index = 0
aliases = { "$PID": "bpf_get_current_pid_tgid()" } aliases = {"$PID": "bpf_get_current_pid_tgid()"}
def _substitute_aliases(self, expr): def _substitute_aliases(self, expr):
if expr is None: if expr is None:
...@@ -37,8 +37,8 @@ class Probe(object): ...@@ -37,8 +37,8 @@ class Probe(object):
# supported right now. # supported right now.
index = param.rfind('*') index = param.rfind('*')
index = index if index != -1 else param.rfind(' ') index = index if index != -1 else param.rfind(' ')
param_type = param[0:index+1].strip() param_type = param[0:index + 1].strip()
param_name = param[index+1:].strip() param_name = param[index + 1:].strip()
self.param_types[param_name] = param_type self.param_types[param_name] = param_type
def _generate_entry(self): def _generate_entry(self):
...@@ -65,7 +65,7 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE) ...@@ -65,7 +65,7 @@ int PROBENAME(struct pt_regs *ctx SIGNATURE)
collect += """ collect += """
u64 __time = bpf_ktime_get_ns(); u64 __time = bpf_ktime_get_ns();
%s.update(&pid, &__time); %s.update(&pid, &__time);
""" % param_hash """ % param_hash
else: else:
collect += "%s.update(&pid, &%s);\n" % \ collect += "%s.update(&pid, &%s);\n" % \
(param_hash, pname) (param_hash, pname)
...@@ -88,8 +88,8 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -88,8 +88,8 @@ u64 __time = bpf_ktime_get_ns();
self.param_types["__latency"] = "u64" # nanoseconds self.param_types["__latency"] = "u64" # nanoseconds
for pname in self.args_to_probe: for pname in self.args_to_probe:
if pname not in self.param_types: if pname not in self.param_types:
raise ValueError("$entry(%s): no such param" \ raise ValueError("$entry(%s): no such param" %
% arg) arg)
self.hashname_prefix = "%s_param_" % self.probe_hash_name self.hashname_prefix = "%s_param_" % self.probe_hash_name
text = "" text = ""
...@@ -156,8 +156,8 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -156,8 +156,8 @@ u64 __time = bpf_ktime_get_ns();
if len(parts) > 6: if len(parts) > 6:
self._bail("extraneous ':'-separated parts detected") self._bail("extraneous ':'-separated parts detected")
if parts[0] not in ["r", "p", "t", "u"]: if parts[0] not in ["r", "p", "t", "u"]:
self._bail("probe type must be 'p', 'r', 't', or 'u' " + self._bail("probe type must be 'p', 'r', 't', or 'u'" +
"but got '%s'" % parts[0]) " but got '%s'" % parts[0])
if re.match(r"\w+\(.*\)", parts[2]) is None: if re.match(r"\w+\(.*\)", parts[2]) is None:
self._bail(("function signature '%s' has an invalid " + self._bail(("function signature '%s' has an invalid " +
"format") % parts[2]) "format") % parts[2])
...@@ -263,8 +263,8 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -263,8 +263,8 @@ u64 __time = bpf_ktime_get_ns();
expr = self.exprs[i] expr = self.exprs[i]
if self.probe_type == "u" and expr[0:3] == "arg": if self.probe_type == "u" and expr[0:3] == "arg":
return (" u64 %s = 0;\n" + return (" u64 %s = 0;\n" +
" bpf_usdt_readarg(%s, ctx, &%s);\n") % \ " bpf_usdt_readarg(%s, ctx, &%s);\n") \
(expr, expr[3], expr) % (expr, expr[3], expr)
else: else:
return "" return ""
...@@ -294,7 +294,7 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -294,7 +294,7 @@ u64 __time = bpf_ktime_get_ns();
def _generate_key_assignment(self): def _generate_key_assignment(self):
if self.type == "hist": if self.type == "hist":
return self._generate_usdt_arg_assignment(0) + \ return self._generate_usdt_arg_assignment(0) + \
("%s __key = %s;\n" % \ ("%s __key = %s;\n" %
(self.expr_types[0], self.exprs[0])) (self.expr_types[0], self.exprs[0]))
else: else:
text = "struct %s_key_t __key = {};\n" % \ text = "struct %s_key_t __key = {};\n" % \
...@@ -323,10 +323,11 @@ u64 __time = bpf_ktime_get_ns(); ...@@ -323,10 +323,11 @@ u64 __time = bpf_ktime_get_ns();
program = "" program = ""
probe_text = """ probe_text = """
DATA_DECL DATA_DECL
""" + ( """ + (
"TRACEPOINT_PROBE(%s, %s)" % (self.tp_category, self.tp_event) \ "TRACEPOINT_PROBE(%s, %s)" %
if self.probe_type == "t" \ (self.tp_category, self.tp_event)
else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """ if self.probe_type == "t"
else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
{ {
PID_FILTER PID_FILTER
PREFIX PREFIX
...@@ -353,7 +354,8 @@ DATA_DECL ...@@ -353,7 +354,8 @@ DATA_DECL
# signatures. Other probes force it to (). # signatures. Other probes force it to ().
signature = ", " + self.signature signature = ", " + self.signature
program += probe_text.replace("PROBENAME", self.probe_func_name) program += probe_text.replace("PROBENAME",
self.probe_func_name)
program = program.replace("SIGNATURE", signature) program = program.replace("SIGNATURE", signature)
program = program.replace("PID_FILTER", program = program.replace("PID_FILTER",
self._generate_pid_filter()) self._generate_pid_filter())
...@@ -400,7 +402,8 @@ DATA_DECL ...@@ -400,7 +402,8 @@ DATA_DECL
def attach(self, bpf): def attach(self, bpf):
self.bpf = bpf self.bpf = bpf
if self.probe_type == "u": return; if self.probe_type == "u":
return
if self.is_user: if self.is_user:
self._attach_u() self._attach_u()
else: else:
...@@ -447,7 +450,7 @@ DATA_DECL ...@@ -447,7 +450,7 @@ DATA_DECL
if self.type == "freq": if self.type == "freq":
print(self.label or self.raw_spec) print(self.label or self.raw_spec)
print("\t%-10s %s" % ("COUNT", "EVENT")) print("\t%-10s %s" % ("COUNT", "EVENT"))
sdata = sorted(data.items(), key=lambda kv: kv[1].value) sdata = sorted(data.items(), key=lambda p: p[1].value)
if top is not None: if top is not None:
sdata = sdata[-top:] sdata = sdata[-top:]
for key, value in sdata: for key, value in sdata:
...@@ -461,11 +464,11 @@ DATA_DECL ...@@ -461,11 +464,11 @@ DATA_DECL
self._v2s(key.v0) self._v2s(key.v0)
else: else:
key_str = self._display_key(key) key_str = self._display_key(key)
print("\t%-10s %s" % \ print("\t%-10s %s" %
(str(value.value), key_str)) (str(value.value), key_str))
elif self.type == "hist": elif self.type == "hist":
label = self.label or (self._display_expr(0) label = self.label or (self._display_expr(0)
if not self.is_default_expr else "retval") if not self.is_default_expr else "retval")
data.print_log2_hist(val_type=label) data.print_log2_hist(val_type=label)
if not self.cumulative: if not self.cumulative:
data.clear() data.clear()
...@@ -478,8 +481,8 @@ class Tool(object): ...@@ -478,8 +481,8 @@ class Tool(object):
Probe specifier syntax: Probe specifier syntax:
{p,r,t,u}:{[library],category}:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label] {p,r,t,u}:{[library],category}:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label]
Where: Where:
p,r,t,u -- probe at function entry, function exit, kernel tracepoint, p,r,t,u -- probe at function entry, function exit, kernel
or USDT probe tracepoint, or USDT probe
in exit probes: can use $retval, $entry(param), $latency in exit probes: can use $retval, $entry(param), $latency
library -- the library that contains the function library -- the library that contains the function
(leave empty for kernel functions) (leave empty for kernel functions)
...@@ -506,7 +509,7 @@ argdist -C 'r:c:gets():char*:(char*)$retval#snooped strings' ...@@ -506,7 +509,7 @@ argdist -C 'r:c:gets():char*:(char*)$retval#snooped strings'
argdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte' argdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte'
Print a histogram of nanoseconds per byte from kmalloc allocations Print a histogram of nanoseconds per byte from kmalloc allocations
argdist -C 'p::__kmalloc(size_t size, gfp_t flags):size_t:size:flags&GFP_ATOMIC' argdist -C 'p::__kmalloc(size_t sz, gfp_t flags):size_t:sz:flags&GFP_ATOMIC'
Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC
argdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5 argdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5
...@@ -520,7 +523,8 @@ argdist -p 1005 -H 'r:c:read()' ...@@ -520,7 +523,8 @@ argdist -p 1005 -H 'r:c:read()'
argdist -C 'r::__vfs_read():u32:$PID:$latency > 100000' argdist -C 'r::__vfs_read():u32:$PID:$latency > 100000'
Print frequency of reads by process where the latency was >0.1ms Print frequency of reads by process where the latency was >0.1ms
argdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t:$entry(count):$latency > 1000000' argdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t
$entry(count):$latency > 1000000'
Print a histogram of read sizes that were longer than 1ms Print a histogram of read sizes that were longer than 1ms
argdist -H \\ argdist -H \\
...@@ -569,7 +573,8 @@ argdist -p 2780 -z 120 \\ ...@@ -569,7 +573,8 @@ argdist -p 2780 -z 120 \\
parser.add_argument("-v", "--verbose", action="store_true", parser.add_argument("-v", "--verbose", action="store_true",
help="print resulting BPF program code before executing") help="print resulting BPF program code before executing")
parser.add_argument("-c", "--cumulative", action="store_true", parser.add_argument("-c", "--cumulative", action="store_true",
help="do not clear histograms and freq counts at each interval") help="do not clear histograms and freq counts at " +
"each interval")
parser.add_argument("-T", "--top", type=int, parser.add_argument("-T", "--top", type=int,
help="number of top results to show (not applicable to " + help="number of top results to show (not applicable to " +
"histograms)") "histograms)")
...@@ -610,8 +615,9 @@ struct __string_t { char s[%d]; }; ...@@ -610,8 +615,9 @@ struct __string_t { char s[%d]; };
for probe in self.probes: for probe in self.probes:
bpf_source += probe.generate_text() bpf_source += probe.generate_text()
if self.args.verbose: if self.args.verbose:
for text in [probe.usdt_ctx.get_text() \ for text in [probe.usdt_ctx.get_text()
for probe in self.probes if probe.usdt_ctx]: for probe in self.probes
if probe.usdt_ctx]:
print(text) print(text)
print(bpf_source) print(bpf_source)
usdt_contexts = [probe.usdt_ctx usdt_contexts = [probe.usdt_ctx
......
...@@ -183,4 +183,3 @@ while (1): ...@@ -183,4 +183,3 @@ while (1):
countdown -= 1 countdown -= 1
if exiting or countdown == 0: if exiting or countdown == 0:
exit() exit()
...@@ -88,7 +88,7 @@ int kprobe__sys_execve(struct pt_regs *ctx, struct filename *filename, ...@@ -88,7 +88,7 @@ int kprobe__sys_execve(struct pt_regs *ctx, struct filename *filename,
const char __user *const __user *__argv, const char __user *const __user *__argv,
const char __user *const __user *__envp) const char __user *const __user *__envp)
{ {
// create data here and pass to submit_arg to save space on the stack (#555) // create data here and pass to submit_arg to save stack space (#555)
struct data_t data = {}; struct data_t data = {};
data.pid = bpf_get_current_pid_tgid() >> 32; data.pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&data.comm, sizeof(data.comm)); bpf_get_current_comm(&data.comm, sizeof(data.comm));
...@@ -167,8 +167,8 @@ start_ts = time.time() ...@@ -167,8 +167,8 @@ start_ts = time.time()
argv = defaultdict(list) argv = defaultdict(list)
# TODO: This is best-effort PPID matching. Short-lived processes may exit # TODO: This is best-effort PPID matching. Short-lived processes may exit
# before we get a chance to read the PPID. This should be replaced with fetching # before we get a chance to read the PPID. This should be replaced with
# PPID via C when available (#364). # fetching PPID via C when available (#364).
def get_ppid(pid): def get_ppid(pid):
try: try:
with open("/proc/%d/status" % pid) as status: with open("/proc/%d/status" % pid) as status:
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
# #
# Run "funclatency -h" for full usage. # Run "funclatency -h" for full usage.
# #
# The pattern is a string with optional '*' wildcards, similar to file globbing. # The pattern is a string with optional '*' wildcards, similar to file
# If you'd prefer to use regular expressions, use the -r option. # globbing. If you'd prefer to use regular expressions, use the -r option.
# #
# Currently nested or recursive functions are not supported properly, and # Currently nested or recursive functions are not supported properly, and
# timestamps will be overwritten, creating dubious output. Try to match single # timestamps will be overwritten, creating dubious output. Try to match single
...@@ -202,7 +202,8 @@ if not library: ...@@ -202,7 +202,8 @@ if not library:
matched = b.num_open_kprobes() matched = b.num_open_kprobes()
else: else:
b.attach_uprobe(name=library, sym_re=pattern, fn_name="trace_func_entry") b.attach_uprobe(name=library, sym_re=pattern, fn_name="trace_func_entry")
b.attach_uretprobe(name=library, sym_re=pattern, fn_name="trace_func_return") b.attach_uretprobe(name=library, sym_re=pattern,
fn_name="trace_func_return")
matched = b.num_open_uprobes() matched = b.num_open_uprobes()
if matched == 0: if matched == 0:
......
...@@ -51,7 +51,8 @@ int do_entry(struct pt_regs *ctx) { ...@@ -51,7 +51,8 @@ int do_entry(struct pt_regs *ctx) {
u32 pid = bpf_get_current_pid_tgid(); u32 pid = bpf_get_current_pid_tgid();
if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) { if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
bpf_probe_read(&val.host, sizeof(val.host), (void *)PT_REGS_PARM1(ctx)); bpf_probe_read(&val.host, sizeof(val.host),
(void *)PT_REGS_PARM1(ctx));
val.pid = bpf_get_current_pid_tgid(); val.pid = bpf_get_current_pid_tgid();
val.ts = bpf_ktime_get_ns(); val.ts = bpf_ktime_get_ns();
start.update(&pid, &val); start.update(&pid, &val);
......
...@@ -18,7 +18,7 @@ from bcc import BPF ...@@ -18,7 +18,7 @@ from bcc import BPF
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
### arguments # arguments
examples = """examples: examples = """examples:
./hardirqs # sum hard irq event time ./hardirqs # sum hard irq event time
./hardirqs -d # show hard irq event time as histograms ./hardirqs -d # show hard irq event time as histograms
...@@ -49,7 +49,7 @@ else: ...@@ -49,7 +49,7 @@ else:
label = "usecs" label = "usecs"
debug = 0 debug = 0
### define BPF program # define BPF program
bpf_text = """ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -106,7 +106,7 @@ int trace_completion(struct pt_regs *ctx) ...@@ -106,7 +106,7 @@ int trace_completion(struct pt_regs *ctx)
} }
""" """
### 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)};' +
...@@ -121,7 +121,7 @@ else: ...@@ -121,7 +121,7 @@ else:
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)
# these should really use irq:irq_handler_entry/exit tracepoints: # these should really use irq:irq_handler_entry/exit tracepoints:
...@@ -130,7 +130,7 @@ b.attach_kretprobe(event="handle_irq_event_percpu", fn_name="trace_completion") ...@@ -130,7 +130,7 @@ b.attach_kretprobe(event="handle_irq_event_percpu", fn_name="trace_completion")
print("Tracing hard irq event time... Hit Ctrl-C to end.") print("Tracing hard irq event time... Hit Ctrl-C to end.")
### output # output
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):
......
...@@ -280,11 +280,13 @@ def print_outstanding(): ...@@ -280,11 +280,13 @@ def print_outstanding():
alloc_info[info.stack_id].update(info.size) alloc_info[info.stack_id].update(info.size)
else: else:
stack = list(stack_traces.walk(info.stack_id, decoder)) stack = list(stack_traces.walk(info.stack_id, decoder))
alloc_info[info.stack_id] = Allocation(stack, info.size) alloc_info[info.stack_id] = Allocation(stack,
info.size)
if args.show_allocs: if args.show_allocs:
print("\taddr = %x size = %s" % print("\taddr = %x size = %s" %
(address.value, info.size)) (address.value, info.size))
to_show = sorted(alloc_info.values(), key=lambda a: a.size)[-top_stacks:] to_show = sorted(alloc_info.values(),
key=lambda a: a.size)[-top_stacks:]
for alloc in to_show: for alloc in to_show:
print("\t%d bytes in %d allocations from stack\n\t\t%s" % print("\t%d bytes in %d allocations from stack\n\t\t%s" %
(alloc.size, alloc.count, "\n\t\t".join(alloc.stack))) (alloc.size, alloc.count, "\n\t\t".join(alloc.stack)))
......
...@@ -369,7 +369,8 @@ def print_event(mounts, umounts, cpu, data, size): ...@@ -369,7 +369,8 @@ def print_event(mounts, umounts, cpu, data, size):
event.type == EventType.EVENT_UMOUNT_RET): event.type == EventType.EVENT_UMOUNT_RET):
if event.type == EventType.EVENT_MOUNT_RET: if event.type == EventType.EVENT_MOUNT_RET:
syscall = mounts.pop(event.pid) syscall = mounts.pop(event.pid)
call = 'mount({source}, {target}, {type}, {flags}, {data}) = {retval}'.format( call = ('mount({source}, {target}, {type}, {flags}, {data}) ' +
'= {retval}').format(
source=decode_mount_string(syscall['source']), source=decode_mount_string(syscall['source']),
target=decode_mount_string(syscall['target']), target=decode_mount_string(syscall['target']),
type=decode_mount_string(syscall['type']), type=decode_mount_string(syscall['type']),
......
...@@ -40,8 +40,8 @@ examples = """examples: ...@@ -40,8 +40,8 @@ examples = """examples:
./offcputime # trace off-CPU stack time until Ctrl-C ./offcputime # trace off-CPU stack time until Ctrl-C
./offcputime 5 # trace for 5 seconds only ./offcputime 5 # trace for 5 seconds only
./offcputime -f 5 # 5 seconds, and output in folded format ./offcputime -f 5 # 5 seconds, and output in folded format
./offcputime -m 1000 # trace only events that last more than 1000 usec. ./offcputime -m 1000 # trace only events that last more than 1000 usec
./offcputime -M 10000 # trace only events that last less than 10000 usec. ./offcputime -M 10000 # trace only events that last less than 10000 usec
./offcputime -p 185 # only trace threads for PID 185 ./offcputime -p 185 # only trace threads for PID 185
./offcputime -t 188 # only trace thread 188 ./offcputime -t 188 # only trace thread 188
./offcputime -u # only trace user threads (no kernel) ./offcputime -u # only trace user threads (no kernel)
...@@ -82,10 +82,12 @@ parser.add_argument("duration", nargs="?", default=99999999, ...@@ -82,10 +82,12 @@ parser.add_argument("duration", nargs="?", default=99999999,
help="duration of trace, in seconds") help="duration of trace, in seconds")
parser.add_argument("-m", "--min-block-time", default=1, parser.add_argument("-m", "--min-block-time", default=1,
type=positive_nonzero_int, type=positive_nonzero_int,
help="the amount of time in microseconds over which we store traces (default 1)") help="the amount of time in microseconds over which we " +
parser.add_argument("-M", "--max-block-time", default=(1<<64)-1, "store traces (default 1)")
parser.add_argument("-M", "--max-block-time", default=(1 << 64) - 1,
type=positive_nonzero_int, type=positive_nonzero_int,
help="the amount of time in microseconds under which we store traces (default U64_MAX)") help="the amount of time in microseconds under which we " +
"store traces (default U64_MAX)")
args = parser.parse_args() args = parser.parse_args()
if args.pid and args.tgid: if args.pid and args.tgid:
parser.error("specify only one of -p and -t") parser.error("specify only one of -p and -t")
...@@ -198,13 +200,14 @@ else: ...@@ -198,13 +200,14 @@ else:
bpf_text = bpf_text.replace('USER_STACK_GET', user_stack_get) bpf_text = bpf_text.replace('USER_STACK_GET', user_stack_get)
bpf_text = bpf_text.replace('KERNEL_STACK_GET', kernel_stack_get) bpf_text = bpf_text.replace('KERNEL_STACK_GET', kernel_stack_get)
need_delimiter = args.delimited and not (args.kernel_stacks_only or args.user_stacks_only) need_delimiter = args.delimited and not (args.kernel_stacks_only or
args.user_stacks_only)
# check for an edge case; the code below will handle this case correctly # check for an edge case; the code below will handle this case correctly
# but ultimately nothing will be displayed # but ultimately nothing will be displayed
if args.kernel_threads_only and args.user_stacks_only: if args.kernel_threads_only and args.user_stacks_only:
print("ERROR: Displaying user stacks for kernel threads " \ print("ERROR: Displaying user stacks for kernel threads " +
"doesn't make sense.", file=stderr) "doesn't make sense.", file=stderr)
exit(1) exit(1)
# initialize BPF # initialize BPF
...@@ -240,8 +243,8 @@ stack_traces = b.get_table("stack_traces") ...@@ -240,8 +243,8 @@ stack_traces = b.get_table("stack_traces")
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):
# handle get_stackid erorrs # handle get_stackid erorrs
if (not args.user_stacks_only and k.kernel_stack_id < 0) or \ if (not args.user_stacks_only and k.kernel_stack_id < 0) or \
(not args.kernel_stacks_only and k.user_stack_id < 0 and \ (not args.kernel_stacks_only and k.user_stack_id < 0 and
k.user_stack_id != -errno.EFAULT): k.user_stack_id != -errno.EFAULT):
missing_stacks += 1 missing_stacks += 1
# check for an ENOMEM error # check for an ENOMEM error
if k.kernel_stack_id == -errno.ENOMEM or \ if k.kernel_stack_id == -errno.ENOMEM or \
......
...@@ -16,7 +16,7 @@ from bcc import BPF ...@@ -16,7 +16,7 @@ from bcc import BPF
from time import sleep, strftime from time import sleep, strftime
import argparse import argparse
### arguments # arguments
examples = """examples: examples = """examples:
./softirqs # sum soft irq event time ./softirqs # sum soft irq event time
./softirqs -d # show soft irq event time as histograms ./softirqs -d # show soft irq event time as histograms
...@@ -47,7 +47,7 @@ else: ...@@ -47,7 +47,7 @@ else:
label = "usecs" label = "usecs"
debug = 0 debug = 0
### define BPF program # define BPF program
bpf_text = """ bpf_text = """
#include <uapi/linux/ptrace.h> #include <uapi/linux/ptrace.h>
...@@ -92,7 +92,7 @@ int trace_completion(struct pt_regs *ctx) ...@@ -92,7 +92,7 @@ int trace_completion(struct pt_regs *ctx)
} }
""" """
### 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)};' +
...@@ -105,22 +105,22 @@ else: ...@@ -105,22 +105,22 @@ else:
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)
# this should really use irq:softirq_entry/exit tracepoints; for now the # this should really use irq:softirq_entry/exit tracepoints; for now the
# soft irq functions are individually traced (search your kernel for # soft irq functions are individually traced (search your kernel for
# open_softirq() calls, and adjust the following list as needed). # open_softirq() calls, and adjust the following list as needed).
for softirqfunc in ("blk_iopoll_softirq", "blk_done_softirq", 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.")
### output # output
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):
......
#!/usr/bin/env python #!/usr/bin/env python
# #
# solisten Trace TCP listen events # solisten Trace TCP listen events
# For Linux, uses BCC, eBPF. Embedded C. # For Linux, uses BCC, eBPF. Embedded C.
# #
# USAGE: solisten.py [-h] [-p PID] [--show-netns] # USAGE: solisten.py [-h] [-p PID] [--show-netns]
# #
...@@ -28,8 +28,8 @@ import ctypes as ct ...@@ -28,8 +28,8 @@ import ctypes as ct
examples = """Examples: examples = """Examples:
./solisten.py # Stream socket listen ./solisten.py # Stream socket listen
./solisten.py -p 1234 # Stream socket listen for specified PID only ./solisten.py -p 1234 # Stream socket listen for specified PID only
./solisten.py --netns 4242 # Stream socket listen for specified network namespace ID only ./solisten.py --netns 4242 # " for the specified network namespace ID only
./solisten.py --show-netns # Show network namespace ID. Probably usefull if you run containers ./solisten.py --show-netns # Show network ns ID (useful for containers)
""" """
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
...@@ -45,7 +45,7 @@ parser.add_argument("-n", "--netns", default=0, type=int, ...@@ -45,7 +45,7 @@ parser.add_argument("-n", "--netns", default=0, type=int,
# BPF Program # BPF Program
bpf_text = """ bpf_text = """
#include <net/sock.h> #include <net/sock.h>
#include <net/inet_sock.h> #include <net/inet_sock.h>
#include <net/net_namespace.h> #include <net/net_namespace.h>
...@@ -77,7 +77,8 @@ int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog) ...@@ -77,7 +77,8 @@ int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog)
.backlog = backlog, .backlog = backlog,
}; };
// Get process comm. Needs LLVM >= 3.7.1 see https://github.com/iovisor/bcc/issues/393 // Get process comm. Needs LLVM >= 3.7.1
// see https://github.com/iovisor/bcc/issues/393
bpf_get_current_comm(evt.task, TASK_COMM_LEN); bpf_get_current_comm(evt.task, TASK_COMM_LEN);
// Get socket IP family // Get socket IP family
...@@ -107,7 +108,8 @@ int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog) ...@@ -107,7 +108,8 @@ int kprobe__inet_listen(struct pt_regs *ctx, struct socket *sock, int backlog)
bpf_probe_read(evt.laddr, sizeof(u32), &(inet->inet_rcv_saddr)); bpf_probe_read(evt.laddr, sizeof(u32), &(inet->inet_rcv_saddr));
evt.laddr[0] = be32_to_cpu(evt.laddr[0]); evt.laddr[0] = be32_to_cpu(evt.laddr[0]);
} else if (family == AF_INET6) { } else if (family == AF_INET6) {
bpf_probe_read(evt.laddr, sizeof(evt.laddr), sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); bpf_probe_read(evt.laddr, sizeof(evt.laddr),
sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32);
evt.laddr[0] = be64_to_cpu(evt.laddr[0]); evt.laddr[0] = be64_to_cpu(evt.laddr[0]);
evt.laddr[1] = be64_to_cpu(evt.laddr[1]); evt.laddr[1] = be64_to_cpu(evt.laddr[1]);
} }
...@@ -157,7 +159,8 @@ def event_printer(show_netns): ...@@ -157,7 +159,8 @@ def event_printer(show_netns):
protocol += "v4" protocol += "v4"
address = netaddr.IPAddress(event.laddr[0]) address = netaddr.IPAddress(event.laddr[0])
elif proto_type == socket.AF_INET6: elif proto_type == socket.AF_INET6:
address = netaddr.IPAddress(event.laddr[0]<<64 | event.laddr[1], version=6) address = netaddr.IPAddress(event.laddr[0] << 64 | event.laddr[1],
version=6)
protocol += "v6" protocol += "v6"
# Display # Display
...@@ -195,11 +198,12 @@ if __name__ == "__main__": ...@@ -195,11 +198,12 @@ if __name__ == "__main__":
# Print headers # Print headers
if args.show_netns: if args.show_netns:
print("%-6s %-12s %-12s %-6s %-8s %-5s %-39s" % ("PID", "COMM", "NETNS", "PROTO", "BACKLOG", "PORT", "ADDR")) print("%-6s %-12s %-12s %-6s %-8s %-5s %-39s" %
("PID", "COMM", "NETNS", "PROTO", "BACKLOG", "PORT", "ADDR"))
else: else:
print("%-6s %-12s %-6s %-8s %-5s %-39s" % ("PID", "COMM", "PROTO", "BACKLOG", "PORT", "ADDR")) print("%-6s %-12s %-6s %-8s %-5s %-39s" %
("PID", "COMM", "PROTO", "BACKLOG", "PORT", "ADDR"))
# Read events # Read events
while 1: while 1:
b.kprobe_poll() b.kprobe_poll()
...@@ -114,8 +114,8 @@ def print_event(cpu, data, size): ...@@ -114,8 +114,8 @@ def print_event(cpu, data, size):
ts = time.time() - start_ts ts = time.time() - start_ts
if verbose: if verbose:
print("%-18.9f %-12.12s %-6d %-3d %s" % (ts, event.comm, event.pid, cpu, print("%-18.9f %-12.12s %-6d %-3d %s" %
function)) (ts, event.comm, event.pid, cpu, function))
else: else:
print("%-18.9f %s" % (ts, function)) print("%-18.9f %s" % (ts, function))
......
...@@ -18,22 +18,23 @@ from bcc import USDT ...@@ -18,22 +18,23 @@ from bcc import USDT
trace_root = "/sys/kernel/debug/tracing" trace_root = "/sys/kernel/debug/tracing"
event_root = os.path.join(trace_root, "events") event_root = os.path.join(trace_root, "events")
parser = argparse.ArgumentParser(description= parser = argparse.ArgumentParser(
"Display kernel tracepoints or USDT probes and their formats.", description="Display kernel tracepoints or USDT probes " +
formatter_class=argparse.RawDescriptionHelpFormatter) "and their formats.",
parser.add_argument("-p", "--pid", type=int, default=None, help= formatter_class=argparse.RawDescriptionHelpFormatter)
"List USDT probes in the specified process") parser.add_argument("-p", "--pid", type=int, default=None,
parser.add_argument("-l", "--lib", default="", help= help="List USDT probes in the specified process")
"List USDT probes in the specified library or executable") parser.add_argument("-l", "--lib", default="",
parser.add_argument("-v", dest="verbosity", action="count", help= help="List USDT probes in the specified library or executable")
"Increase verbosity level (print variables, arguments, etc.)") parser.add_argument("-v", dest="verbosity", action="count",
parser.add_argument(dest="filter", nargs="?", help= help="Increase verbosity level (print variables, arguments, etc.)")
"A filter that specifies which probes/tracepoints to print") parser.add_argument(dest="filter", nargs="?",
help="A filter that specifies which probes/tracepoints to print")
args = parser.parse_args() args = parser.parse_args()
def print_tpoint_format(category, event): def print_tpoint_format(category, event):
fmt = open(os.path.join(event_root, category, event, "format") fmt = open(os.path.join(event_root, category, event, "format")) \
).readlines() .readlines()
for line in fmt: for line in fmt:
match = re.search(r'field:([^;]*);', line) match = re.search(r'field:([^;]*);', line)
if match is None: if match is None:
...@@ -81,7 +82,8 @@ def print_usdt_details(probe): ...@@ -81,7 +82,8 @@ def print_usdt_details(probe):
print(" %d location(s)" % probe.num_locations) print(" %d location(s)" % probe.num_locations)
print(" %d argument(s)" % probe.num_arguments) print(" %d argument(s)" % probe.num_arguments)
else: else:
print("%s %s:%s" % (probe.bin_path, probe.provider, probe.name)) print("%s %s:%s" %
(probe.bin_path, probe.provider, probe.name))
def print_usdt(pid, lib): def print_usdt(pid, lib):
reader = USDT(path=lib, pid=pid) reader = USDT(path=lib, pid=pid)
...@@ -103,4 +105,3 @@ if __name__ == "__main__": ...@@ -103,4 +105,3 @@ if __name__ == "__main__":
except: except:
if sys.exc_info()[0] is not SystemExit: if sys.exc_info()[0] is not SystemExit:
print(sys.exc_info()[1]) print(sys.exc_info()[1])
This diff is collapsed.
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