1 // SPDX-License-Identifier: GPL-2.0
6 #include <linux/perf_event.h>
10 #include <sys/ioctl.h>
11 #include <sys/resource.h>
13 #include <sys/types.h>
18 #include <bpf/libbpf.h>
21 #define SAMPLE_PERIOD 0x7fffffffffffffffULL
23 /* counters, values, values2 */
26 static void check_on_cpu(int cpu
, struct perf_event_attr
*attr
)
28 struct bpf_perf_event_value value2
;
29 int pmu_fd
, error
= 0;
33 /* Move to target CPU */
36 assert(sched_setaffinity(0, sizeof(set
), &set
) == 0);
37 /* Open perf event and attach to the perf_event_array */
38 pmu_fd
= sys_perf_event_open(attr
, -1/*pid*/, cpu
/*cpu*/, -1/*group_fd*/, 0);
40 fprintf(stderr
, "sys_perf_event_open failed on CPU %d\n", cpu
);
44 assert(bpf_map_update_elem(map_fd
[0], &cpu
, &pmu_fd
, BPF_ANY
) == 0);
45 assert(ioctl(pmu_fd
, PERF_EVENT_IOC_ENABLE
, 0) == 0);
46 /* Trigger the kprobe */
47 bpf_map_get_next_key(map_fd
[1], &cpu
, NULL
);
49 if (bpf_map_lookup_elem(map_fd
[1], &cpu
, &value
)) {
50 fprintf(stderr
, "Value missing for CPU %d\n", cpu
);
54 fprintf(stderr
, "CPU %d: %llu\n", cpu
, value
);
56 /* The above bpf_map_lookup_elem should trigger the second kprobe */
57 if (bpf_map_lookup_elem(map_fd
[2], &cpu
, &value2
)) {
58 fprintf(stderr
, "Value2 missing for CPU %d\n", cpu
);
62 fprintf(stderr
, "CPU %d: counter: %llu, enabled: %llu, running: %llu\n", cpu
,
63 value2
.counter
, value2
.enabled
, value2
.running
);
67 assert(bpf_map_delete_elem(map_fd
[0], &cpu
) == 0 || error
);
68 assert(ioctl(pmu_fd
, PERF_EVENT_IOC_DISABLE
, 0) == 0 || error
);
69 assert(close(pmu_fd
) == 0 || error
);
70 assert(bpf_map_delete_elem(map_fd
[1], &cpu
) == 0 || error
);
74 static void test_perf_event_array(struct perf_event_attr
*attr
,
77 int i
, status
, nr_cpus
= sysconf(_SC_NPROCESSORS_CONF
);
81 printf("Test reading %s counters\n", name
);
83 for (i
= 0; i
< nr_cpus
; i
++) {
87 check_on_cpu(i
, attr
);
92 for (i
= 0; i
< nr_cpus
; i
++) {
93 assert(waitpid(pid
[i
], &status
, 0) == pid
[i
]);
98 printf("Test: %s FAILED\n", name
);
101 static void test_bpf_perf_event(void)
103 struct perf_event_attr attr_cycles
= {
105 .sample_period
= SAMPLE_PERIOD
,
107 .type
= PERF_TYPE_HARDWARE
,
110 .config
= PERF_COUNT_HW_CPU_CYCLES
,
112 struct perf_event_attr attr_clock
= {
114 .sample_period
= SAMPLE_PERIOD
,
116 .type
= PERF_TYPE_SOFTWARE
,
119 .config
= PERF_COUNT_SW_CPU_CLOCK
,
121 struct perf_event_attr attr_raw
= {
123 .sample_period
= SAMPLE_PERIOD
,
125 .type
= PERF_TYPE_RAW
,
128 /* Intel Instruction Retired */
131 struct perf_event_attr attr_l1d_load
= {
133 .sample_period
= SAMPLE_PERIOD
,
135 .type
= PERF_TYPE_HW_CACHE
,
139 PERF_COUNT_HW_CACHE_L1D
|
140 (PERF_COUNT_HW_CACHE_OP_READ
<< 8) |
141 (PERF_COUNT_HW_CACHE_RESULT_ACCESS
<< 16),
143 struct perf_event_attr attr_llc_miss
= {
145 .sample_period
= SAMPLE_PERIOD
,
147 .type
= PERF_TYPE_HW_CACHE
,
151 PERF_COUNT_HW_CACHE_LL
|
152 (PERF_COUNT_HW_CACHE_OP_READ
<< 8) |
153 (PERF_COUNT_HW_CACHE_RESULT_MISS
<< 16),
155 struct perf_event_attr attr_msr_tsc
= {
159 /* From /sys/bus/event_source/devices/msr/ */
166 test_perf_event_array(&attr_cycles
, "HARDWARE-cycles");
167 test_perf_event_array(&attr_clock
, "SOFTWARE-clock");
168 test_perf_event_array(&attr_raw
, "RAW-instruction-retired");
169 test_perf_event_array(&attr_l1d_load
, "HW_CACHE-L1D-load");
171 /* below tests may fail in qemu */
172 test_perf_event_array(&attr_llc_miss
, "HW_CACHE-LLC-miss");
173 test_perf_event_array(&attr_msr_tsc
, "Dynamic-msr-tsc");
176 int main(int argc
, char **argv
)
178 struct bpf_link
*links
[2];
179 struct bpf_program
*prog
;
180 struct bpf_object
*obj
;
184 snprintf(filename
, sizeof(filename
), "%s_kern.o", argv
[0]);
185 obj
= bpf_object__open_file(filename
, NULL
);
186 if (libbpf_get_error(obj
)) {
187 fprintf(stderr
, "ERROR: opening BPF object file failed\n");
191 /* load BPF program */
192 if (bpf_object__load(obj
)) {
193 fprintf(stderr
, "ERROR: loading BPF object file failed\n");
197 map_fd
[0] = bpf_object__find_map_fd_by_name(obj
, "counters");
198 map_fd
[1] = bpf_object__find_map_fd_by_name(obj
, "values");
199 map_fd
[2] = bpf_object__find_map_fd_by_name(obj
, "values2");
200 if (map_fd
[0] < 0 || map_fd
[1] < 0 || map_fd
[2] < 0) {
201 fprintf(stderr
, "ERROR: finding a map in obj file failed\n");
205 bpf_object__for_each_program(prog
, obj
) {
206 links
[i
] = bpf_program__attach(prog
);
207 if (libbpf_get_error(links
[i
])) {
208 fprintf(stderr
, "ERROR: bpf_program__attach failed\n");
215 test_bpf_perf_event();
218 for (i
--; i
>= 0; i
--)
219 bpf_link__destroy(links
[i
]);
221 bpf_object__close(obj
);