1#!/usr/bin/env python3 2# Copyright 2021, Athira Rajeev, IBM Corp. 3# Licensed under the Apache License, Version 2.0 (the "License") 4 5import bcc 6import os 7import time 8import unittest 9from bcc import BPF, PerfType, PerfHWConfig, PerfSWConfig, PerfEventSampleFormat 10from bcc import Perf 11from time import sleep 12from utils import kernel_version_ge, mayFail 13 14class TestPerfAttachRaw(unittest.TestCase): 15 @mayFail("This fails on github actions environment, hw perf events are not supported") 16 @unittest.skipUnless(kernel_version_ge(4,9), "requires kernel >= 4.9") 17 def test_attach_raw_event_powerpc(self): 18 # on PowerPC, 'addr' is always written to; for x86 see _x86 version of test 19 bpf_text=b""" 20#include <linux/perf_event.h> 21struct key_t { 22 int cpu; 23 int pid; 24 char name[100]; 25}; 26 27static inline __attribute__((always_inline)) void get_key(struct key_t* key) { 28 key->cpu = bpf_get_smp_processor_id(); 29 key->pid = bpf_get_current_pid_tgid(); 30 bpf_get_current_comm(&(key->name), sizeof(key->name)); 31} 32 33int on_sample_hit(struct bpf_perf_event_data *ctx) { 34 struct key_t key = {}; 35 get_key(&key); 36 u64 addr = 0; 37 struct bpf_perf_event_data_kern *kctx; 38 struct perf_sample_data *data; 39 40 kctx = (struct bpf_perf_event_data_kern *)ctx; 41 bpf_probe_read(&data, sizeof(struct perf_sample_data*), &(kctx->data)); 42 if (data) 43 bpf_probe_read(&addr, sizeof(u64), &(data->addr)); 44 45 bpf_trace_printk("test_attach_raw_event_powerpc: pid: %ld, comm: %s, addr: 0x%llx\\n", key.pid, key.name, addr); 46 return 0; 47} 48 49""" 50 51 b = BPF(text=bpf_text) 52 try: 53 event_attr = Perf.perf_event_attr() 54 event_attr.type = Perf.PERF_TYPE_HARDWARE 55 event_attr.config = PerfHWConfig.CACHE_MISSES 56 event_attr.sample_period = 1000000 57 event_attr.sample_type = PerfEventSampleFormat.ADDR 58 event_attr.exclude_kernel = 1 59 b.attach_perf_event_raw(attr=event_attr, fn_name=b"on_sample_hit", pid=-1, cpu=-1) 60 except Exception: 61 print("Failed to attach to a raw event. Please check the event attr used") 62 exit() 63 64 print("Running for 2 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.") 65 sleep(2) 66 67 @mayFail("This fails on github actions environment, hw perf events are not supported") 68 @unittest.skipUnless(kernel_version_ge(4,17), "bpf_perf_event_data->addr requires kernel >= 4.17") 69 def test_attach_raw_event_x86(self): 70 # on x86, need to set precise_ip in order for perf_events to write to 'addr' 71 bpf_text=b""" 72#include <linux/perf_event.h> 73struct key_t { 74 int cpu; 75 int pid; 76 char name[100]; 77}; 78 79static inline __attribute__((always_inline)) void get_key(struct key_t* key) { 80 key->cpu = bpf_get_smp_processor_id(); 81 key->pid = bpf_get_current_pid_tgid(); 82 bpf_get_current_comm(&(key->name), sizeof(key->name)); 83} 84 85int on_sample_hit(struct bpf_perf_event_data *ctx) { 86 struct key_t key = {}; 87 get_key(&key); 88 u64 addr = ctx->addr; 89 90 bpf_trace_printk("test_attach_raw_event_x86: pid: %ld, comm: %s, addr: 0x%llx\\n", key.pid, key.name, addr); 91 return 0; 92} 93 94""" 95 96 b = BPF(text=bpf_text) 97 try: 98 event_attr = Perf.perf_event_attr() 99 event_attr.type = Perf.PERF_TYPE_HARDWARE 100 event_attr.config = PerfHWConfig.CPU_CYCLES 101 event_attr.sample_period = 1000000 102 event_attr.sample_type = PerfEventSampleFormat.ADDR 103 event_attr.exclude_kernel = 1 104 event_attr.precise_ip = 2 105 b.attach_perf_event_raw(attr=event_attr, fn_name=b"on_sample_hit", pid=-1, cpu=-1) 106 except Exception: 107 print("Failed to attach to a raw event. Please check the event attr used") 108 exit() 109 110 print("Running for 1 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.") 111 sleep(1) 112 113 114 # SW perf events should work on GH actions, so expect this to succeed 115 @unittest.skipUnless(kernel_version_ge(4,17), "bpf_perf_event_data->addr requires kernel >= 4.17") 116 def test_attach_raw_sw_event(self): 117 bpf_text=b""" 118#include <linux/perf_event.h> 119struct key_t { 120 int cpu; 121 int pid; 122 char name[100]; 123}; 124 125static inline __attribute__((always_inline)) void get_key(struct key_t* key) { 126 key->cpu = bpf_get_smp_processor_id(); 127 key->pid = bpf_get_current_pid_tgid(); 128 bpf_get_current_comm(&(key->name), sizeof(key->name)); 129} 130 131int on_sample_hit(struct bpf_perf_event_data *ctx) { 132 struct key_t key = {}; 133 get_key(&key); 134 u64 addr = ctx->addr; 135 136 bpf_trace_printk("test_attach_raw_sw_event: pid: %ld, comm: %s, addr: 0x%llx\\n", key.pid, key.name, addr); 137 return 0; 138} 139 140""" 141 142 b = BPF(text=bpf_text) 143 try: 144 event_attr = Perf.perf_event_attr() 145 event_attr.type = Perf.PERF_TYPE_SOFTWARE 146 event_attr.config = PerfSWConfig.PAGE_FAULTS 147 event_attr.sample_period = 100 148 event_attr.sample_type = PerfEventSampleFormat.ADDR 149 event_attr.exclude_kernel = 1 150 b.attach_perf_event_raw(attr=event_attr, fn_name=b"on_sample_hit", pid=-1, cpu=-1) 151 except Exception: 152 print("Failed to attach to a raw event. Please check the event attr used") 153 exit() 154 155 print("Running for 1 seconds or hit Ctrl-C to end. Check trace file for samples information written by bpf_trace_printk.") 156 sleep(1) 157 158if __name__ == "__main__": 159 unittest.main() 160