1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET) 3 #include <sched.h> 4 #include <stdio.h> 5 #include <stdarg.h> 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <linux/perf_event.h> 9 #include <linux/limits.h> 10 #include <sys/types.h> 11 #include <sys/wait.h> 12 #include <sys/prctl.h> 13 #include <perf/cpumap.h> 14 #include <perf/threadmap.h> 15 #include <perf/evlist.h> 16 #include <perf/evsel.h> 17 #include <perf/mmap.h> 18 #include <perf/event.h> 19 #include <internal/tests.h> 20 #include <api/fs/fs.h> 21 #include "tests.h" 22 #include <internal/evsel.h> 23 24 static int libperf_print(enum libperf_print_level level, 25 const char *fmt, va_list ap) 26 { 27 return vfprintf(stderr, fmt, ap); 28 } 29 30 static int test_stat_cpu(void) 31 { 32 struct perf_cpu_map *cpus; 33 struct perf_evlist *evlist; 34 struct perf_evsel *evsel, *leader; 35 struct perf_event_attr attr1 = { 36 .type = PERF_TYPE_SOFTWARE, 37 .config = PERF_COUNT_SW_CPU_CLOCK, 38 }; 39 struct perf_event_attr attr2 = { 40 .type = PERF_TYPE_SOFTWARE, 41 .config = PERF_COUNT_SW_TASK_CLOCK, 42 }; 43 int err, idx; 44 45 cpus = perf_cpu_map__new(NULL); 46 __T("failed to create cpus", cpus); 47 48 evlist = perf_evlist__new(); 49 __T("failed to create evlist", evlist); 50 51 evsel = leader = perf_evsel__new(&attr1); 52 __T("failed to create evsel1", evsel); 53 54 perf_evlist__add(evlist, evsel); 55 56 evsel = perf_evsel__new(&attr2); 57 __T("failed to create evsel2", evsel); 58 59 perf_evlist__add(evlist, evsel); 60 61 perf_evlist__set_leader(evlist); 62 __T("failed to set leader", leader->leader == leader); 63 __T("failed to set leader", evsel->leader == leader); 64 65 perf_evlist__set_maps(evlist, cpus, NULL); 66 67 err = perf_evlist__open(evlist); 68 __T("failed to open evsel", err == 0); 69 70 perf_evlist__for_each_evsel(evlist, evsel) { 71 cpus = perf_evsel__cpus(evsel); 72 73 for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) { 74 struct perf_counts_values counts = { .val = 0 }; 75 76 perf_evsel__read(evsel, idx, 0, &counts); 77 __T("failed to read value for evsel", counts.val != 0); 78 } 79 } 80 81 perf_evlist__close(evlist); 82 perf_evlist__delete(evlist); 83 84 perf_cpu_map__put(cpus); 85 return 0; 86 } 87 88 static int test_stat_thread(void) 89 { 90 struct perf_counts_values counts = { .val = 0 }; 91 struct perf_thread_map *threads; 92 struct perf_evlist *evlist; 93 struct perf_evsel *evsel, *leader; 94 struct perf_event_attr attr1 = { 95 .type = PERF_TYPE_SOFTWARE, 96 .config = PERF_COUNT_SW_CPU_CLOCK, 97 }; 98 struct perf_event_attr attr2 = { 99 .type = PERF_TYPE_SOFTWARE, 100 .config = PERF_COUNT_SW_TASK_CLOCK, 101 }; 102 int err; 103 104 threads = perf_thread_map__new_dummy(); 105 __T("failed to create threads", threads); 106 107 perf_thread_map__set_pid(threads, 0, 0); 108 109 evlist = perf_evlist__new(); 110 __T("failed to create evlist", evlist); 111 112 evsel = leader = perf_evsel__new(&attr1); 113 __T("failed to create evsel1", evsel); 114 115 perf_evlist__add(evlist, evsel); 116 117 evsel = perf_evsel__new(&attr2); 118 __T("failed to create evsel2", evsel); 119 120 perf_evlist__add(evlist, evsel); 121 122 perf_evlist__set_leader(evlist); 123 __T("failed to set leader", leader->leader == leader); 124 __T("failed to set leader", evsel->leader == leader); 125 126 perf_evlist__set_maps(evlist, NULL, threads); 127 128 err = perf_evlist__open(evlist); 129 __T("failed to open evsel", err == 0); 130 131 perf_evlist__for_each_evsel(evlist, evsel) { 132 perf_evsel__read(evsel, 0, 0, &counts); 133 __T("failed to read value for evsel", counts.val != 0); 134 } 135 136 perf_evlist__close(evlist); 137 perf_evlist__delete(evlist); 138 139 perf_thread_map__put(threads); 140 return 0; 141 } 142 143 static int test_stat_thread_enable(void) 144 { 145 struct perf_counts_values counts = { .val = 0 }; 146 struct perf_thread_map *threads; 147 struct perf_evlist *evlist; 148 struct perf_evsel *evsel, *leader; 149 struct perf_event_attr attr1 = { 150 .type = PERF_TYPE_SOFTWARE, 151 .config = PERF_COUNT_SW_CPU_CLOCK, 152 .disabled = 1, 153 }; 154 struct perf_event_attr attr2 = { 155 .type = PERF_TYPE_SOFTWARE, 156 .config = PERF_COUNT_SW_TASK_CLOCK, 157 .disabled = 1, 158 }; 159 int err; 160 161 threads = perf_thread_map__new_dummy(); 162 __T("failed to create threads", threads); 163 164 perf_thread_map__set_pid(threads, 0, 0); 165 166 evlist = perf_evlist__new(); 167 __T("failed to create evlist", evlist); 168 169 evsel = leader = perf_evsel__new(&attr1); 170 __T("failed to create evsel1", evsel); 171 172 perf_evlist__add(evlist, evsel); 173 174 evsel = perf_evsel__new(&attr2); 175 __T("failed to create evsel2", evsel); 176 177 perf_evlist__add(evlist, evsel); 178 179 perf_evlist__set_leader(evlist); 180 __T("failed to set leader", leader->leader == leader); 181 __T("failed to set leader", evsel->leader == leader); 182 183 perf_evlist__set_maps(evlist, NULL, threads); 184 185 err = perf_evlist__open(evlist); 186 __T("failed to open evsel", err == 0); 187 188 perf_evlist__for_each_evsel(evlist, evsel) { 189 perf_evsel__read(evsel, 0, 0, &counts); 190 __T("failed to read value for evsel", counts.val == 0); 191 } 192 193 perf_evlist__enable(evlist); 194 195 perf_evlist__for_each_evsel(evlist, evsel) { 196 perf_evsel__read(evsel, 0, 0, &counts); 197 __T("failed to read value for evsel", counts.val != 0); 198 } 199 200 perf_evlist__disable(evlist); 201 202 perf_evlist__close(evlist); 203 perf_evlist__delete(evlist); 204 205 perf_thread_map__put(threads); 206 return 0; 207 } 208 209 static int test_mmap_thread(void) 210 { 211 struct perf_evlist *evlist; 212 struct perf_evsel *evsel; 213 struct perf_mmap *map; 214 struct perf_cpu_map *cpus; 215 struct perf_thread_map *threads; 216 struct perf_event_attr attr = { 217 .type = PERF_TYPE_TRACEPOINT, 218 .sample_period = 1, 219 .wakeup_watermark = 1, 220 .disabled = 1, 221 }; 222 char path[PATH_MAX]; 223 int id, err, pid, go_pipe[2]; 224 union perf_event *event; 225 int count = 0; 226 227 snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", 228 sysfs__mountpoint()); 229 230 if (filename__read_int(path, &id)) { 231 tests_failed++; 232 fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); 233 return -1; 234 } 235 236 attr.config = id; 237 238 err = pipe(go_pipe); 239 __T("failed to create pipe", err == 0); 240 241 fflush(NULL); 242 243 pid = fork(); 244 if (!pid) { 245 int i; 246 char bf; 247 248 read(go_pipe[0], &bf, 1); 249 250 /* Generate 100 prctl calls. */ 251 for (i = 0; i < 100; i++) 252 prctl(0, 0, 0, 0, 0); 253 254 exit(0); 255 } 256 257 threads = perf_thread_map__new_dummy(); 258 __T("failed to create threads", threads); 259 260 cpus = perf_cpu_map__dummy_new(); 261 __T("failed to create cpus", cpus); 262 263 perf_thread_map__set_pid(threads, 0, pid); 264 265 evlist = perf_evlist__new(); 266 __T("failed to create evlist", evlist); 267 268 evsel = perf_evsel__new(&attr); 269 __T("failed to create evsel1", evsel); 270 __T("failed to set leader", evsel->leader == evsel); 271 272 perf_evlist__add(evlist, evsel); 273 274 perf_evlist__set_maps(evlist, cpus, threads); 275 276 err = perf_evlist__open(evlist); 277 __T("failed to open evlist", err == 0); 278 279 err = perf_evlist__mmap(evlist, 4); 280 __T("failed to mmap evlist", err == 0); 281 282 perf_evlist__enable(evlist); 283 284 /* kick the child and wait for it to finish */ 285 write(go_pipe[1], "A", 1); 286 waitpid(pid, NULL, 0); 287 288 /* 289 * There's no need to call perf_evlist__disable, 290 * monitored process is dead now. 291 */ 292 293 perf_evlist__for_each_mmap(evlist, map, false) { 294 if (perf_mmap__read_init(map) < 0) 295 continue; 296 297 while ((event = perf_mmap__read_event(map)) != NULL) { 298 count++; 299 perf_mmap__consume(map); 300 } 301 302 perf_mmap__read_done(map); 303 } 304 305 /* calls perf_evlist__munmap/perf_evlist__close */ 306 perf_evlist__delete(evlist); 307 308 perf_thread_map__put(threads); 309 perf_cpu_map__put(cpus); 310 311 /* 312 * The generated prctl calls should match the 313 * number of events in the buffer. 314 */ 315 __T("failed count", count == 100); 316 317 return 0; 318 } 319 320 static int test_mmap_cpus(void) 321 { 322 struct perf_evlist *evlist; 323 struct perf_evsel *evsel; 324 struct perf_mmap *map; 325 struct perf_cpu_map *cpus; 326 struct perf_event_attr attr = { 327 .type = PERF_TYPE_TRACEPOINT, 328 .sample_period = 1, 329 .wakeup_watermark = 1, 330 .disabled = 1, 331 }; 332 cpu_set_t saved_mask; 333 char path[PATH_MAX]; 334 int id, err, cpu, tmp; 335 union perf_event *event; 336 int count = 0; 337 338 snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", 339 sysfs__mountpoint()); 340 341 if (filename__read_int(path, &id)) { 342 fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); 343 return -1; 344 } 345 346 attr.config = id; 347 348 cpus = perf_cpu_map__new(NULL); 349 __T("failed to create cpus", cpus); 350 351 evlist = perf_evlist__new(); 352 __T("failed to create evlist", evlist); 353 354 evsel = perf_evsel__new(&attr); 355 __T("failed to create evsel1", evsel); 356 __T("failed to set leader", evsel->leader == evsel); 357 358 perf_evlist__add(evlist, evsel); 359 360 perf_evlist__set_maps(evlist, cpus, NULL); 361 362 err = perf_evlist__open(evlist); 363 __T("failed to open evlist", err == 0); 364 365 err = perf_evlist__mmap(evlist, 4); 366 __T("failed to mmap evlist", err == 0); 367 368 perf_evlist__enable(evlist); 369 370 err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask); 371 __T("sched_getaffinity failed", err == 0); 372 373 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { 374 cpu_set_t mask; 375 376 CPU_ZERO(&mask); 377 CPU_SET(cpu, &mask); 378 379 err = sched_setaffinity(0, sizeof(mask), &mask); 380 __T("sched_setaffinity failed", err == 0); 381 382 prctl(0, 0, 0, 0, 0); 383 } 384 385 err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask); 386 __T("sched_setaffinity failed", err == 0); 387 388 perf_evlist__disable(evlist); 389 390 perf_evlist__for_each_mmap(evlist, map, false) { 391 if (perf_mmap__read_init(map) < 0) 392 continue; 393 394 while ((event = perf_mmap__read_event(map)) != NULL) { 395 count++; 396 perf_mmap__consume(map); 397 } 398 399 perf_mmap__read_done(map); 400 } 401 402 /* calls perf_evlist__munmap/perf_evlist__close */ 403 perf_evlist__delete(evlist); 404 405 /* 406 * The generated prctl events should match the 407 * number of cpus or be bigger (we are system-wide). 408 */ 409 __T("failed count", count >= perf_cpu_map__nr(cpus)); 410 411 perf_cpu_map__put(cpus); 412 413 return 0; 414 } 415 416 int test_evlist(int argc, char **argv) 417 { 418 __T_START; 419 420 libperf_init(libperf_print); 421 422 test_stat_cpu(); 423 test_stat_thread(); 424 test_stat_thread_enable(); 425 test_mmap_thread(); 426 test_mmap_cpus(); 427 428 __T_END; 429 return tests_failed == 0 ? 0 : -1; 430 } 431