bcc/python: Add x86 and sw test to test_attach_perf_event.py
authorDave Marchevsky <davemarchevsky@fb.com>
Thu, 19 Aug 2021 00:06:00 +0000 (17:06 -0700)
committeryonghong-song <ys114321@gmail.com>
Thu, 19 Aug 2021 17:24:22 +0000 (10:24 -0700)
Since the current test can't run on github actions since there's no HW
perf counter access, add a test using software page faults perf
event, which might work.

Also, rename the current HW test in there to highlight that it'll work
for PowerPC, and add a similar test for x86.

tests/python/test_attach_perf_event.py

index d0cea06..a843b57 100755 (executable)
@@ -6,7 +6,7 @@ import bcc
 import os
 import time
 import unittest
-from bcc import BPF, PerfType, PerfHWConfig, PerfEventSampleFormat
+from bcc import BPF, PerfType, PerfHWConfig, PerfSWConfig, PerfEventSampleFormat
 from bcc import Perf
 from time import sleep
 from utils import kernel_version_ge, mayFail
@@ -14,7 +14,8 @@ 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(self):
+    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 {
@@ -41,7 +42,7 @@ int on_sample_hit(struct bpf_perf_event_data *ctx) {
     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);
+    bpf_trace_printk("test_attach_raw_event_powerpc: pid: %ld, comm: %s, addr: 0x%llx\\n", key.pid, key.name, addr);
     return 0;
 }
 
@@ -63,5 +64,96 @@ int on_sample_hit(struct bpf_perf_event_data *ctx) {
         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()