File: test_attach_perf_event.py

package info (click to toggle)
bpfcc 0.31.0%2Bds-7
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 27,208 kB
  • sloc: ansic: 758,058; python: 40,671; cpp: 25,637; sh: 780; makefile: 279
file content (159 lines) | stat: -rwxr-xr-x 5,598 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#!/usr/bin/env python3
# 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=b"""
#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=b"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=b"""
#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=b"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=b"""
#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=b"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()