xref: /aosp_15_r20/external/bcc/tests/python/test_attach_perf_event.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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