| #!/usr/bin/python |
| # |
| # An example usage of stack_build_id |
| # Most of the code here is borrowed from tools/profile.py |
| # |
| # Steps for using this code |
| # 1) Start ping program in one terminal eg invocation: ping google.com -i0.001 |
| # 2) Change the path of libc specified in b.add_module() below |
| # 3) Invoke the script as 'python stack_buildid_example.py' |
| # 4) o/p of the tool is as shown below |
| # python example/tracing/stack_buildid_example.py |
| # sendto |
| # - ping (5232) |
| # 2 |
| # |
| # REQUIRES: Linux 4.17+ (BPF_BUILD_ID support) |
| # Licensed under the Apache License, Version 2.0 (the "License") |
| # 03-Jan-2019 Vijay Nag |
| |
| from __future__ import print_function |
| from bcc import BPF, PerfType, PerfSWConfig |
| from sys import stderr |
| from time import sleep |
| import argparse |
| import signal |
| import os |
| import subprocess |
| import errno |
| import multiprocessing |
| import ctypes as ct |
| |
| def Get_libc_path(): |
| # A small helper function that returns full path |
| # of libc in the system |
| cmd = 'cat /proc/self/maps | grep libc | awk \'{print $6}\' | uniq' |
| output = subprocess.check_output(cmd, shell=True) |
| if not isinstance(output, str): |
| output = output.decode() |
| return output.split('\n')[0] |
| |
| bpf_text = """ |
| #include <uapi/linux/ptrace.h> |
| #include <uapi/linux/bpf_perf_event.h> |
| #include <linux/sched.h> |
| |
| struct key_t { |
| u32 pid; |
| int user_stack_id; |
| char name[TASK_COMM_LEN]; |
| }; |
| BPF_HASH(counts, struct key_t); |
| BPF_STACK_TRACE_BUILDID(stack_traces, 128); |
| |
| int do_perf_event(struct bpf_perf_event_data *ctx) { |
| u32 pid = bpf_get_current_pid_tgid() >> 32; |
| |
| // create map key |
| struct key_t key = {.pid = pid}; |
| bpf_get_current_comm(&key.name, sizeof(key.name)); |
| |
| key.user_stack_id = stack_traces.get_stackid(&ctx->regs, BPF_F_USER_STACK); |
| |
| if (key.user_stack_id >= 0) { |
| counts.increment(key); |
| } |
| return 0; |
| } |
| """ |
| |
| b = BPF(text=bpf_text) |
| b.attach_perf_event(ev_type=PerfType.SOFTWARE, |
| ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_perf_event", |
| sample_period=0, sample_freq=49, cpu=0) |
| |
| # Add the list of libraries/executables to the build sym cache for sym resolution |
| # Change the libc path if it is different on a different machine. |
| # libc.so and ping are added here so that any symbols pertaining to |
| # libc or ping are resolved. More executables/libraries can be added here. |
| b.add_module(Get_libc_path()) |
| b.add_module("/usr/sbin/sshd") |
| b.add_module("/bin/ping") |
| counts = b.get_table("counts") |
| stack_traces = b.get_table("stack_traces") |
| duration = 2 |
| |
| def signal_handler(signal, frame): |
| print() |
| |
| try: |
| sleep(duration) |
| except KeyboardInterrupt: |
| # as cleanup can take some time, trap Ctrl-C: |
| signal.signal(signal.SIGINT, signal.SIG_IGN) |
| |
| user_stack=[] |
| for k,v in sorted(counts.items(), key=lambda counts: counts[1].value): |
| user_stack = [] if k.user_stack_id < 0 else \ |
| stack_traces.walk(k.user_stack_id) |
| |
| user_stack=list(user_stack) |
| for addr in user_stack: |
| print(" %s" % b.sym(addr, k.pid).decode('utf-8', 'replace')) |
| print(" %-16s %s (%d)" % ("-", k.name.decode('utf-8', 'replace'), k.pid)) |
| print(" %d\n" % v.value) |
| |