| #!/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, PerfSWConfig, PerfEventSampleFormat | |
| from bcc import Perf | |
| from time import sleep | |
| from utils import kernel_version_ge, mayFail | |
| class TestPerfAttachRaw(unittest.TestCase): | |
| @mayFail("This fails on github actions environment, hw perf events are not supported") | |
| @unittest.skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9") | |
| def test_attach_raw_event_powerpc(self): | |
| # on PowerPC, 'addr' is always written to; for x86 see _x86 version of test | |
| 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("test_attach_raw_event_powerpc: 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 = PerfEventSampleFormat.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 2 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.") | |
| sleep(2) | |
| @mayFail("This fails on github actions environment, hw perf events are not supported") | |
| @unittest.skipUnless(kernel_version_ge(4,17), "bpf_perf_event_data->addr requires kernel >= 4.17") | |
| def test_attach_raw_event_x86(self): | |
| # on x86, need to set precise_ip in order for perf_events to write to 'addr' | |
| 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 = ctx->addr; | |
| bpf_trace_printk("test_attach_raw_event_x86: 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.CPU_CYCLES | |
| event_attr.sample_period = 1000000 | |
| event_attr.sample_type = PerfEventSampleFormat.ADDR | |
| event_attr.exclude_kernel = 1 | |
| event_attr.precise_ip = 2 | |
| 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 1 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.") | |
| sleep(1) | |
| # SW perf events should work on GH actions, so expect this to succeed | |
| @unittest.skipUnless(kernel_version_ge(4,17), "bpf_perf_event_data->addr requires kernel >= 4.17") | |
| def test_attach_raw_sw_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 = ctx->addr; | |
| bpf_trace_printk("test_attach_raw_sw_event: 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_SOFTWARE | |
| event_attr.config = PerfSWConfig.PAGE_FAULTS | |
| event_attr.sample_period = 100 | |
| event_attr.sample_type = PerfEventSampleFormat.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 1 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.") | |
| sleep(1) | |
| if __name__ == "__main__": | |
| unittest.main() |