Skip to content

Instantly share code, notes, and snippets.

@dave-tucker
Created August 11, 2024 14:43
Show Gist options
  • Save dave-tucker/5b1c5be9f9413a60d96b0758d889fa01 to your computer and use it in GitHub Desktop.
Save dave-tucker/5b1c5be9f9413a60d96b0758d889fa01 to your computer and use it in GitHub Desktop.
Measuring eBPF program overhead per process
# perf script event handlers, generated by perf script -g python
# Licensed under the terms of the GNU GPL License version 2
# The common_* event handler fields are the most useful fields common to
# all events. They don't necessarily correspond to the 'common_*' fields
# in the format files. Those fields not available as handler params can
# be retrieved using Python functions of the form common_*(context).
# See the perf-script-python Documentation for the list of available functions.
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
total_cycles = autodict()
bpf_prog_cycles = autodict()
def process_event(param_dict):
pid = param_dict["sample"]["pid"]
if 'comm' in param_dict:
comm = param_dict["comm"]
else:
comm = "[unknown]"
comm = comm.replace(' ', '_')
cycles = param_dict["sample"]["period"]
if 'callchain' in param_dict and len(param_dict["callchain"]) > 0:
top_of_callstack = param_dict["callchain"][0]
top_of_callstack.setdefault('sym', dict())
top_of_callstack['sym'].setdefault('name', None)
sym = top_of_callstack['sym']['name']
else:
param_dict.setdefault('symbol', None)
param_dict.setdefault('dso', None)
sym = param_dict['symbol']
if sym is None:
sym = "[unknown]"
try:
total_cycles[comm][pid] += cycles
except TypeError:
total_cycles[comm][pid] = cycles
if sym.startswith('bpf_prog'):
try:
bpf_prog_cycles[comm][pid][sym] += cycles
except TypeError:
bpf_prog_cycles[comm][pid][sym] = cycles
def trace_end():
total_ebpf_cycles_per_comm = {}
total_ebpf_cycles_per_prog_per_comm = {}
ebpf_overhead_per_prog_per_comm = {}
ebpf_overhead_per_prog = {}
total_prog_cycles_per_comm = {}
for comm, val in total_cycles.items():
if comm == ":4022959":
print(f"DEBUG 1: comm: {comm}, cycles: {sum([cycles for pid, cycles in val.items()])}")
total_prog_cycles_per_comm[comm] = sum([cycles for pid, cycles in val.items()])
for comm, val in bpf_prog_cycles.items():
if comm not in total_ebpf_cycles_per_prog_per_comm:
total_ebpf_cycles_per_prog_per_comm[comm] = {}
for pid, val in val.items():
for sym, val in val.items():
if comm == ":4022959":
print(f"DEBUG 2: comm: {comm}, sym: {sym}, cycles: {val}")
if sym not in total_ebpf_cycles_per_prog_per_comm[comm]:
total_ebpf_cycles_per_prog_per_comm[comm][sym] = 0
total_ebpf_cycles_per_prog_per_comm[comm][sym] += val
for comm in total_prog_cycles_per_comm:
if comm not in total_ebpf_cycles_per_prog_per_comm:
continue
if total_prog_cycles_per_comm[comm] == total_ebpf_cycles_per_prog_per_comm[comm]:
continue
if comm not in ebpf_overhead_per_prog_per_comm:
ebpf_overhead_per_prog_per_comm[comm] = {}
for prog, cycles in total_ebpf_cycles_per_prog_per_comm[comm].items():
overhead = (cycles / total_prog_cycles_per_comm[comm]) * 100
if overhead != 100:
ebpf_overhead_per_prog_per_comm[comm][prog] = overhead
if prog not in ebpf_overhead_per_prog:
ebpf_overhead_per_prog[prog] = []
ebpf_overhead_per_prog[prog].append(overhead)
for comm in ebpf_overhead_per_prog_per_comm:
ebpf_overhead = ""
for prog, overhead in ebpf_overhead_per_prog_per_comm[comm].items():
ebpf_overhead += f"{prog}: {overhead:.2f}%, "
if ebpf_overhead != "":
print(f"comm: {comm}, {ebpf_overhead}")
print("\n\n")
for prog in ebpf_overhead_per_prog:
minVal = min(ebpf_overhead_per_prog[prog])
maxVal = max(ebpf_overhead_per_prog[prog])
median = sorted(ebpf_overhead_per_prog[prog])[len(ebpf_overhead_per_prog[prog]) // 2]
mean = sum(ebpf_overhead_per_prog[prog]) / len(ebpf_overhead_per_prog[prog])
stdDev = (sum([(overhead - mean) ** 2 for overhead in ebpf_overhead_per_prog[prog]]) / len(ebpf_overhead_per_prog[prog])) ** 0.5
print(f"{prog}")
print(f"\tmin: {minVal:.2f}%")
print(f"\tmax: {maxVal:.2f}%")
print(f"\tmedian: {median:.2f}%")
print(f"\tmean: {mean:.2f}%")
print(f"\tstdDev: {stdDev:.2f}%\n\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment