Add python interface for attach_perf_event_raw to bcc.
The bpf_attach_perf_event_raw API provide flexibility to use
advanced features of perf events with BPF. Presently, this
API is available to use in BPF programs via C and C++ interface.
Patch enables support to use in python interface.
Patch also adds testcase under 'tests/python' which uses
the newly added python interface 'attach_perf_event_raw'.
Signed-off-by: Athira Rajeev <atrajeev@linux.vnet.ibm.com>
sample_period, sample_freq, pid, i, group_fd)
self.open_perf_events[(ev_type, ev_config)] = res
+ def _attach_perf_event_raw(self, progfd, attr, pid, cpu, group_fd):
+ res = lib.bpf_attach_perf_event_raw(progfd, ct.byref(attr), pid,
+ cpu, group_fd, 0)
+ if res < 0:
+ raise Exception("Failed to attach BPF to perf raw event")
+ return res
+
+ def attach_perf_event_raw(self, attr=-1, fn_name=b"", pid=-1, cpu=-1, group_fd=-1):
+ fn_name = _assert_is_bytes(fn_name)
+ fn = self.load_func(fn_name, BPF.PERF_EVENT)
+ res = {}
+ if cpu >= 0:
+ res[cpu] = self._attach_perf_event_raw(fn.fd, attr,
+ pid, cpu, group_fd)
+ else:
+ for i in get_online_cpus():
+ res[i] = self._attach_perf_event_raw(fn.fd, attr,
+ pid, i, group_fd)
+ self.open_perf_events[(attr.type, attr.config)] = res
+
def detach_perf_event(self, ev_type=-1, ev_config=-1):
try:
fds = self.open_perf_events[(ev_type, ev_config)]
lib = ct.CDLL("libbcc.so.0", use_errno=True)
+# needed for perf_event_attr() ctype
+from .perf import Perf
+
# keep in sync with bcc_common.h
lib.bpf_module_create_b.restype = ct.c_void_p
lib.bpf_module_create_b.argtypes = [ct.c_char_p, ct.c_char_p, ct.c_uint,
lib.bpf_attach_perf_event.argtype = [ct.c_int, ct.c_uint, ct.c_uint, ct.c_ulonglong, ct.c_ulonglong,
ct.c_int, ct.c_int, ct.c_int]
+lib.bpf_attach_perf_event_raw.restype = ct.c_int
+lib.bpf_attach_perf_event_raw.argtype = [Perf.perf_event_attr(), ct.c_uint, ct.c_uint, ct.c_uint, ct.c_uint]
+
lib.bpf_close_perf_event_fd.restype = ct.c_int
lib.bpf_close_perf_event_fd.argtype = [ct.c_int]
--- /dev/null
+#!/usr/bin/env python
+# Copyright 2021, Athira Rajeev, IBM Corp.
+# Licensed under the Apache License, Version 2.0 (the "License")
+
+import bcc
+import os
+import time
+import unittest
+from bcc import BPF, PerfType, PerfHWConfig
+from bcc import Perf
+from time import sleep
+
+class TestPerfAttachRaw(unittest.TestCase):
+ def test_attach_raw_event(self):
+ bpf_text="""
+#include <linux/perf_event.h>
+struct key_t {
+ int cpu;
+ int pid;
+ char name[100];
+};
+
+static inline __attribute__((always_inline)) void get_key(struct key_t* key) {
+ key->cpu = bpf_get_smp_processor_id();
+ key->pid = bpf_get_current_pid_tgid();
+ bpf_get_current_comm(&(key->name), sizeof(key->name));
+}
+
+int on_sample_hit(struct bpf_perf_event_data *ctx) {
+ struct key_t key = {};
+ get_key(&key);
+ u64 addr = 0;
+ struct bpf_perf_event_data_kern *kctx;
+ struct perf_sample_data *data;
+
+ kctx = (struct bpf_perf_event_data_kern *)ctx;
+ bpf_probe_read(&data, sizeof(struct perf_sample_data*), &(kctx->data));
+ if (data)
+ bpf_probe_read(&addr, sizeof(u64), &(data->addr));
+
+ bpf_trace_printk("Hit a sample with pid: %ld, comm: %s, addr: 0x%llx\\n", key.pid, key.name, addr);
+ return 0;
+}
+
+"""
+
+ b = BPF(text=bpf_text)
+ try:
+ event_attr = Perf.perf_event_attr()
+ event_attr.type = Perf.PERF_TYPE_HARDWARE
+ event_attr.config = PerfHWConfig.CACHE_MISSES
+ event_attr.sample_period = 1000000
+ event_attr.sample_type = 0x8 # PERF_SAMPLE_ADDR
+ event_attr.exclude_kernel = 1
+ b.attach_perf_event_raw(attr=event_attr, fn_name="on_sample_hit", pid=-1, cpu=-1)
+ except Exception:
+ print("Failed to attach to a raw event. Please check the event attr used")
+ exit()
+
+ print("Running for 4 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.")
+ sleep(4)
+
+if __name__ == "__main__":
+ unittest.main()