1 // SPDX-License-Identifier: GPL-2.0
6 #include <linux/perf_event.h>
11 #include <sys/ioctl.h>
12 #include <sys/resource.h>
14 #include <sys/types.h>
22 #define SAMPLE_PERIOD 0x7fffffffffffffffULL
24 static void check_on_cpu(int cpu
, struct perf_event_attr
*attr
)
26 struct bpf_perf_event_value value2
;
27 int pmu_fd
, error
= 0;
31 /* Move to target CPU */
34 assert(sched_setaffinity(0, sizeof(set
), &set
) == 0);
35 /* Open perf event and attach to the perf_event_array */
36 pmu_fd
= sys_perf_event_open(attr
, -1/*pid*/, cpu
/*cpu*/, -1/*group_fd*/, 0);
38 fprintf(stderr
, "sys_perf_event_open failed on CPU %d\n", cpu
);
42 assert(bpf_map_update_elem(map_fd
[0], &cpu
, &pmu_fd
, BPF_ANY
) == 0);
43 assert(ioctl(pmu_fd
, PERF_EVENT_IOC_ENABLE
, 0) == 0);
44 /* Trigger the kprobe */
45 bpf_map_get_next_key(map_fd
[1], &cpu
, NULL
);
47 if (bpf_map_lookup_elem(map_fd
[1], &cpu
, &value
)) {
48 fprintf(stderr
, "Value missing for CPU %d\n", cpu
);
52 fprintf(stderr
, "CPU %d: %llu\n", cpu
, value
);
54 /* The above bpf_map_lookup_elem should trigger the second kprobe */
55 if (bpf_map_lookup_elem(map_fd
[2], &cpu
, &value2
)) {
56 fprintf(stderr
, "Value2 missing for CPU %d\n", cpu
);
60 fprintf(stderr
, "CPU %d: counter: %llu, enabled: %llu, running: %llu\n", cpu
,
61 value2
.counter
, value2
.enabled
, value2
.running
);
65 assert(bpf_map_delete_elem(map_fd
[0], &cpu
) == 0 || error
);
66 assert(ioctl(pmu_fd
, PERF_EVENT_IOC_DISABLE
, 0) == 0 || error
);
67 assert(close(pmu_fd
) == 0 || error
);
68 assert(bpf_map_delete_elem(map_fd
[1], &cpu
) == 0 || error
);
72 static void test_perf_event_array(struct perf_event_attr
*attr
,
75 int i
, status
, nr_cpus
= sysconf(_SC_NPROCESSORS_CONF
);
79 printf("Test reading %s counters\n", name
);
81 for (i
= 0; i
< nr_cpus
; i
++) {
85 check_on_cpu(i
, attr
);
90 for (i
= 0; i
< nr_cpus
; i
++) {
91 assert(waitpid(pid
[i
], &status
, 0) == pid
[i
]);
96 printf("Test: %s FAILED\n", name
);
99 static void test_bpf_perf_event(void)
101 struct perf_event_attr attr_cycles
= {
103 .sample_period
= SAMPLE_PERIOD
,
105 .type
= PERF_TYPE_HARDWARE
,
108 .config
= PERF_COUNT_HW_CPU_CYCLES
,
110 struct perf_event_attr attr_clock
= {
112 .sample_period
= SAMPLE_PERIOD
,
114 .type
= PERF_TYPE_SOFTWARE
,
117 .config
= PERF_COUNT_SW_CPU_CLOCK
,
119 struct perf_event_attr attr_raw
= {
121 .sample_period
= SAMPLE_PERIOD
,
123 .type
= PERF_TYPE_RAW
,
126 /* Intel Instruction Retired */
129 struct perf_event_attr attr_l1d_load
= {
131 .sample_period
= SAMPLE_PERIOD
,
133 .type
= PERF_TYPE_HW_CACHE
,
137 PERF_COUNT_HW_CACHE_L1D
|
138 (PERF_COUNT_HW_CACHE_OP_READ
<< 8) |
139 (PERF_COUNT_HW_CACHE_RESULT_ACCESS
<< 16),
141 struct perf_event_attr attr_llc_miss
= {
143 .sample_period
= SAMPLE_PERIOD
,
145 .type
= PERF_TYPE_HW_CACHE
,
149 PERF_COUNT_HW_CACHE_LL
|
150 (PERF_COUNT_HW_CACHE_OP_READ
<< 8) |
151 (PERF_COUNT_HW_CACHE_RESULT_MISS
<< 16),
153 struct perf_event_attr attr_msr_tsc
= {
157 /* From /sys/bus/event_source/devices/msr/ */
164 test_perf_event_array(&attr_cycles
, "HARDWARE-cycles");
165 test_perf_event_array(&attr_clock
, "SOFTWARE-clock");
166 test_perf_event_array(&attr_raw
, "RAW-instruction-retired");
167 test_perf_event_array(&attr_l1d_load
, "HW_CACHE-L1D-load");
169 /* below tests may fail in qemu */
170 test_perf_event_array(&attr_llc_miss
, "HW_CACHE-LLC-miss");
171 test_perf_event_array(&attr_msr_tsc
, "Dynamic-msr-tsc");
174 int main(int argc
, char **argv
)
176 struct rlimit r
= {RLIM_INFINITY
, RLIM_INFINITY
};
179 snprintf(filename
, sizeof(filename
), "%s_kern.o", argv
[0]);
181 setrlimit(RLIMIT_MEMLOCK
, &r
);
182 if (load_bpf_file(filename
)) {
183 printf("%s", bpf_log_buf
);
187 test_bpf_perf_event();