Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET)
0003 #include <inttypes.h>
0004 #include <sched.h>
0005 #include <stdio.h>
0006 #include <stdarg.h>
0007 #include <unistd.h>
0008 #include <stdlib.h>
0009 #include <linux/perf_event.h>
0010 #include <linux/limits.h>
0011 #include <sys/types.h>
0012 #include <sys/wait.h>
0013 #include <sys/prctl.h>
0014 #include <perf/cpumap.h>
0015 #include <perf/threadmap.h>
0016 #include <perf/evlist.h>
0017 #include <perf/evsel.h>
0018 #include <perf/mmap.h>
0019 #include <perf/event.h>
0020 #include <internal/tests.h>
0021 #include <api/fs/fs.h>
0022 #include "tests.h"
0023 #include <internal/evsel.h>
0024 
0025 #define EVENT_NUM 15
0026 #define WAIT_COUNT 100000000UL
0027 
0028 static int libperf_print(enum libperf_print_level level,
0029              const char *fmt, va_list ap)
0030 {
0031     return vfprintf(stderr, fmt, ap);
0032 }
0033 
0034 static int test_stat_cpu(void)
0035 {
0036     struct perf_cpu_map *cpus;
0037     struct perf_evlist *evlist;
0038     struct perf_evsel *evsel, *leader;
0039     struct perf_event_attr attr1 = {
0040         .type   = PERF_TYPE_SOFTWARE,
0041         .config = PERF_COUNT_SW_CPU_CLOCK,
0042     };
0043     struct perf_event_attr attr2 = {
0044         .type   = PERF_TYPE_SOFTWARE,
0045         .config = PERF_COUNT_SW_TASK_CLOCK,
0046     };
0047     int err, idx;
0048 
0049     cpus = perf_cpu_map__new(NULL);
0050     __T("failed to create cpus", cpus);
0051 
0052     evlist = perf_evlist__new();
0053     __T("failed to create evlist", evlist);
0054 
0055     evsel = leader = perf_evsel__new(&attr1);
0056     __T("failed to create evsel1", evsel);
0057 
0058     perf_evlist__add(evlist, evsel);
0059 
0060     evsel = perf_evsel__new(&attr2);
0061     __T("failed to create evsel2", evsel);
0062 
0063     perf_evlist__add(evlist, evsel);
0064 
0065     perf_evlist__set_leader(evlist);
0066     __T("failed to set leader", leader->leader == leader);
0067     __T("failed to set leader", evsel->leader  == leader);
0068 
0069     perf_evlist__set_maps(evlist, cpus, NULL);
0070 
0071     err = perf_evlist__open(evlist);
0072     __T("failed to open evlist", err == 0);
0073 
0074     perf_evlist__for_each_evsel(evlist, evsel) {
0075         cpus = perf_evsel__cpus(evsel);
0076 
0077         for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) {
0078             struct perf_counts_values counts = { .val = 0 };
0079 
0080             perf_evsel__read(evsel, idx, 0, &counts);
0081             __T("failed to read value for evsel", counts.val != 0);
0082         }
0083     }
0084 
0085     perf_evlist__close(evlist);
0086     perf_evlist__delete(evlist);
0087 
0088     perf_cpu_map__put(cpus);
0089     return 0;
0090 }
0091 
0092 static int test_stat_thread(void)
0093 {
0094     struct perf_counts_values counts = { .val = 0 };
0095     struct perf_thread_map *threads;
0096     struct perf_evlist *evlist;
0097     struct perf_evsel *evsel, *leader;
0098     struct perf_event_attr attr1 = {
0099         .type   = PERF_TYPE_SOFTWARE,
0100         .config = PERF_COUNT_SW_CPU_CLOCK,
0101     };
0102     struct perf_event_attr attr2 = {
0103         .type   = PERF_TYPE_SOFTWARE,
0104         .config = PERF_COUNT_SW_TASK_CLOCK,
0105     };
0106     int err;
0107 
0108     threads = perf_thread_map__new_dummy();
0109     __T("failed to create threads", threads);
0110 
0111     perf_thread_map__set_pid(threads, 0, 0);
0112 
0113     evlist = perf_evlist__new();
0114     __T("failed to create evlist", evlist);
0115 
0116     evsel = leader = perf_evsel__new(&attr1);
0117     __T("failed to create evsel1", evsel);
0118 
0119     perf_evlist__add(evlist, evsel);
0120 
0121     evsel = perf_evsel__new(&attr2);
0122     __T("failed to create evsel2", evsel);
0123 
0124     perf_evlist__add(evlist, evsel);
0125 
0126     perf_evlist__set_leader(evlist);
0127     __T("failed to set leader", leader->leader == leader);
0128     __T("failed to set leader", evsel->leader  == leader);
0129 
0130     perf_evlist__set_maps(evlist, NULL, threads);
0131 
0132     err = perf_evlist__open(evlist);
0133     __T("failed to open evlist", err == 0);
0134 
0135     perf_evlist__for_each_evsel(evlist, evsel) {
0136         perf_evsel__read(evsel, 0, 0, &counts);
0137         __T("failed to read value for evsel", counts.val != 0);
0138     }
0139 
0140     perf_evlist__close(evlist);
0141     perf_evlist__delete(evlist);
0142 
0143     perf_thread_map__put(threads);
0144     return 0;
0145 }
0146 
0147 static int test_stat_thread_enable(void)
0148 {
0149     struct perf_counts_values counts = { .val = 0 };
0150     struct perf_thread_map *threads;
0151     struct perf_evlist *evlist;
0152     struct perf_evsel *evsel, *leader;
0153     struct perf_event_attr attr1 = {
0154         .type     = PERF_TYPE_SOFTWARE,
0155         .config   = PERF_COUNT_SW_CPU_CLOCK,
0156         .disabled = 1,
0157     };
0158     struct perf_event_attr attr2 = {
0159         .type     = PERF_TYPE_SOFTWARE,
0160         .config   = PERF_COUNT_SW_TASK_CLOCK,
0161         .disabled = 1,
0162     };
0163     int err;
0164 
0165     threads = perf_thread_map__new_dummy();
0166     __T("failed to create threads", threads);
0167 
0168     perf_thread_map__set_pid(threads, 0, 0);
0169 
0170     evlist = perf_evlist__new();
0171     __T("failed to create evlist", evlist);
0172 
0173     evsel = leader = perf_evsel__new(&attr1);
0174     __T("failed to create evsel1", evsel);
0175 
0176     perf_evlist__add(evlist, evsel);
0177 
0178     evsel = perf_evsel__new(&attr2);
0179     __T("failed to create evsel2", evsel);
0180 
0181     perf_evlist__add(evlist, evsel);
0182 
0183     perf_evlist__set_leader(evlist);
0184     __T("failed to set leader", leader->leader == leader);
0185     __T("failed to set leader", evsel->leader  == leader);
0186 
0187     perf_evlist__set_maps(evlist, NULL, threads);
0188 
0189     err = perf_evlist__open(evlist);
0190     __T("failed to open evlist", err == 0);
0191 
0192     perf_evlist__for_each_evsel(evlist, evsel) {
0193         perf_evsel__read(evsel, 0, 0, &counts);
0194         __T("failed to read value for evsel", counts.val == 0);
0195     }
0196 
0197     perf_evlist__enable(evlist);
0198 
0199     perf_evlist__for_each_evsel(evlist, evsel) {
0200         perf_evsel__read(evsel, 0, 0, &counts);
0201         __T("failed to read value for evsel", counts.val != 0);
0202     }
0203 
0204     perf_evlist__disable(evlist);
0205 
0206     perf_evlist__close(evlist);
0207     perf_evlist__delete(evlist);
0208 
0209     perf_thread_map__put(threads);
0210     return 0;
0211 }
0212 
0213 static int test_mmap_thread(void)
0214 {
0215     struct perf_evlist *evlist;
0216     struct perf_evsel *evsel;
0217     struct perf_mmap *map;
0218     struct perf_cpu_map *cpus;
0219     struct perf_thread_map *threads;
0220     struct perf_event_attr attr = {
0221         .type             = PERF_TYPE_TRACEPOINT,
0222         .sample_period    = 1,
0223         .wakeup_watermark = 1,
0224         .disabled         = 1,
0225     };
0226     char path[PATH_MAX];
0227     int id, err, pid, go_pipe[2];
0228     union perf_event *event;
0229     int count = 0;
0230 
0231     snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
0232          sysfs__mountpoint());
0233 
0234     if (filename__read_int(path, &id)) {
0235         tests_failed++;
0236         fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
0237         return -1;
0238     }
0239 
0240     attr.config = id;
0241 
0242     err = pipe(go_pipe);
0243     __T("failed to create pipe", err == 0);
0244 
0245     fflush(NULL);
0246 
0247     pid = fork();
0248     if (!pid) {
0249         int i;
0250         char bf;
0251 
0252         read(go_pipe[0], &bf, 1);
0253 
0254         /* Generate 100 prctl calls. */
0255         for (i = 0; i < 100; i++)
0256             prctl(0, 0, 0, 0, 0);
0257 
0258         exit(0);
0259     }
0260 
0261     threads = perf_thread_map__new_dummy();
0262     __T("failed to create threads", threads);
0263 
0264     cpus = perf_cpu_map__dummy_new();
0265     __T("failed to create cpus", cpus);
0266 
0267     perf_thread_map__set_pid(threads, 0, pid);
0268 
0269     evlist = perf_evlist__new();
0270     __T("failed to create evlist", evlist);
0271 
0272     evsel = perf_evsel__new(&attr);
0273     __T("failed to create evsel1", evsel);
0274     __T("failed to set leader", evsel->leader == evsel);
0275 
0276     perf_evlist__add(evlist, evsel);
0277 
0278     perf_evlist__set_maps(evlist, cpus, threads);
0279 
0280     err = perf_evlist__open(evlist);
0281     __T("failed to open evlist", err == 0);
0282 
0283     err = perf_evlist__mmap(evlist, 4);
0284     __T("failed to mmap evlist", err == 0);
0285 
0286     perf_evlist__enable(evlist);
0287 
0288     /* kick the child and wait for it to finish */
0289     write(go_pipe[1], "A", 1);
0290     waitpid(pid, NULL, 0);
0291 
0292     /*
0293      * There's no need to call perf_evlist__disable,
0294      * monitored process is dead now.
0295      */
0296 
0297     perf_evlist__for_each_mmap(evlist, map, false) {
0298         if (perf_mmap__read_init(map) < 0)
0299             continue;
0300 
0301         while ((event = perf_mmap__read_event(map)) != NULL) {
0302             count++;
0303             perf_mmap__consume(map);
0304         }
0305 
0306         perf_mmap__read_done(map);
0307     }
0308 
0309     /* calls perf_evlist__munmap/perf_evlist__close */
0310     perf_evlist__delete(evlist);
0311 
0312     perf_thread_map__put(threads);
0313     perf_cpu_map__put(cpus);
0314 
0315     /*
0316      * The generated prctl calls should match the
0317      * number of events in the buffer.
0318      */
0319     __T("failed count", count == 100);
0320 
0321     return 0;
0322 }
0323 
0324 static int test_mmap_cpus(void)
0325 {
0326     struct perf_evlist *evlist;
0327     struct perf_evsel *evsel;
0328     struct perf_mmap *map;
0329     struct perf_cpu_map *cpus;
0330     struct perf_event_attr attr = {
0331         .type             = PERF_TYPE_TRACEPOINT,
0332         .sample_period    = 1,
0333         .wakeup_watermark = 1,
0334         .disabled         = 1,
0335     };
0336     cpu_set_t saved_mask;
0337     char path[PATH_MAX];
0338     int id, err, tmp;
0339     struct perf_cpu cpu;
0340     union perf_event *event;
0341     int count = 0;
0342 
0343     snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id",
0344          sysfs__mountpoint());
0345 
0346     if (filename__read_int(path, &id)) {
0347         fprintf(stderr, "error: failed to get tracepoint id: %s\n", path);
0348         return -1;
0349     }
0350 
0351     attr.config = id;
0352 
0353     cpus = perf_cpu_map__new(NULL);
0354     __T("failed to create cpus", cpus);
0355 
0356     evlist = perf_evlist__new();
0357     __T("failed to create evlist", evlist);
0358 
0359     evsel = perf_evsel__new(&attr);
0360     __T("failed to create evsel1", evsel);
0361     __T("failed to set leader", evsel->leader == evsel);
0362 
0363     perf_evlist__add(evlist, evsel);
0364 
0365     perf_evlist__set_maps(evlist, cpus, NULL);
0366 
0367     err = perf_evlist__open(evlist);
0368     __T("failed to open evlist", err == 0);
0369 
0370     err = perf_evlist__mmap(evlist, 4);
0371     __T("failed to mmap evlist", err == 0);
0372 
0373     perf_evlist__enable(evlist);
0374 
0375     err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask);
0376     __T("sched_getaffinity failed", err == 0);
0377 
0378     perf_cpu_map__for_each_cpu(cpu, tmp, cpus) {
0379         cpu_set_t mask;
0380 
0381         CPU_ZERO(&mask);
0382         CPU_SET(cpu.cpu, &mask);
0383 
0384         err = sched_setaffinity(0, sizeof(mask), &mask);
0385         __T("sched_setaffinity failed", err == 0);
0386 
0387         prctl(0, 0, 0, 0, 0);
0388     }
0389 
0390     err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask);
0391     __T("sched_setaffinity failed", err == 0);
0392 
0393     perf_evlist__disable(evlist);
0394 
0395     perf_evlist__for_each_mmap(evlist, map, false) {
0396         if (perf_mmap__read_init(map) < 0)
0397             continue;
0398 
0399         while ((event = perf_mmap__read_event(map)) != NULL) {
0400             count++;
0401             perf_mmap__consume(map);
0402         }
0403 
0404         perf_mmap__read_done(map);
0405     }
0406 
0407     /* calls perf_evlist__munmap/perf_evlist__close */
0408     perf_evlist__delete(evlist);
0409 
0410     /*
0411      * The generated prctl events should match the
0412      * number of cpus or be bigger (we are system-wide).
0413      */
0414     __T("failed count", count >= perf_cpu_map__nr(cpus));
0415 
0416     perf_cpu_map__put(cpus);
0417 
0418     return 0;
0419 }
0420 
0421 static double display_error(long long average,
0422                 long long high,
0423                 long long low,
0424                 long long expected)
0425 {
0426     double error;
0427 
0428     error = (((double)average - expected) / expected) * 100.0;
0429 
0430     __T_VERBOSE("   Expected: %lld\n", expected);
0431     __T_VERBOSE("   High: %lld   Low:  %lld   Average:  %lld\n",
0432             high, low, average);
0433 
0434     __T_VERBOSE("   Average Error = %.2f%%\n", error);
0435 
0436     return error;
0437 }
0438 
0439 static int test_stat_multiplexing(void)
0440 {
0441     struct perf_counts_values expected_counts = { .val = 0 };
0442     struct perf_counts_values counts[EVENT_NUM] = {{ .val = 0 },};
0443     struct perf_thread_map *threads;
0444     struct perf_evlist *evlist;
0445     struct perf_evsel *evsel;
0446     struct perf_event_attr attr = {
0447         .type        = PERF_TYPE_HARDWARE,
0448         .config      = PERF_COUNT_HW_INSTRUCTIONS,
0449         .read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
0450                    PERF_FORMAT_TOTAL_TIME_RUNNING,
0451         .disabled    = 1,
0452     };
0453     int err, i, nonzero = 0;
0454     unsigned long count;
0455     long long max = 0, min = 0, avg = 0;
0456     double error = 0.0;
0457     s8 scaled = 0;
0458 
0459     /* read for non-multiplexing event count */
0460     threads = perf_thread_map__new_dummy();
0461     __T("failed to create threads", threads);
0462 
0463     perf_thread_map__set_pid(threads, 0, 0);
0464 
0465     evsel = perf_evsel__new(&attr);
0466     __T("failed to create evsel", evsel);
0467 
0468     err = perf_evsel__open(evsel, NULL, threads);
0469     __T("failed to open evsel", err == 0);
0470 
0471     err = perf_evsel__enable(evsel);
0472     __T("failed to enable evsel", err == 0);
0473 
0474     /* wait loop */
0475     count = WAIT_COUNT;
0476     while (count--)
0477         ;
0478 
0479     perf_evsel__read(evsel, 0, 0, &expected_counts);
0480     __T("failed to read value for evsel", expected_counts.val != 0);
0481     __T("failed to read non-multiplexing event count",
0482         expected_counts.ena == expected_counts.run);
0483 
0484     err = perf_evsel__disable(evsel);
0485     __T("failed to enable evsel", err == 0);
0486 
0487     perf_evsel__close(evsel);
0488     perf_evsel__delete(evsel);
0489 
0490     perf_thread_map__put(threads);
0491 
0492     /* read for multiplexing event count */
0493     threads = perf_thread_map__new_dummy();
0494     __T("failed to create threads", threads);
0495 
0496     perf_thread_map__set_pid(threads, 0, 0);
0497 
0498     evlist = perf_evlist__new();
0499     __T("failed to create evlist", evlist);
0500 
0501     for (i = 0; i < EVENT_NUM; i++) {
0502         evsel = perf_evsel__new(&attr);
0503         __T("failed to create evsel", evsel);
0504 
0505         perf_evlist__add(evlist, evsel);
0506     }
0507     perf_evlist__set_maps(evlist, NULL, threads);
0508 
0509     err = perf_evlist__open(evlist);
0510     __T("failed to open evlist", err == 0);
0511 
0512     perf_evlist__enable(evlist);
0513 
0514     /* wait loop */
0515     count = WAIT_COUNT;
0516     while (count--)
0517         ;
0518 
0519     i = 0;
0520     perf_evlist__for_each_evsel(evlist, evsel) {
0521         perf_evsel__read(evsel, 0, 0, &counts[i]);
0522         __T("failed to read value for evsel", counts[i].val != 0);
0523         i++;
0524     }
0525 
0526     perf_evlist__disable(evlist);
0527 
0528     min = counts[0].val;
0529     for (i = 0; i < EVENT_NUM; i++) {
0530         __T_VERBOSE("Event %2d -- Raw count = %" PRIu64 ", run = %" PRIu64 ", enable = %" PRIu64 "\n",
0531                 i, counts[i].val, counts[i].run, counts[i].ena);
0532 
0533         perf_counts_values__scale(&counts[i], true, &scaled);
0534         if (scaled == 1) {
0535             __T_VERBOSE("\t Scaled count = %" PRIu64 " (%.2lf%%, %" PRIu64 "/%" PRIu64 ")\n",
0536                     counts[i].val,
0537                     (double)counts[i].run / (double)counts[i].ena * 100.0,
0538                     counts[i].run, counts[i].ena);
0539         } else if (scaled == -1) {
0540             __T_VERBOSE("\t Not Running\n");
0541         } else {
0542             __T_VERBOSE("\t Not Scaling\n");
0543         }
0544 
0545         if (counts[i].val > max)
0546             max = counts[i].val;
0547 
0548         if (counts[i].val < min)
0549             min = counts[i].val;
0550 
0551         avg += counts[i].val;
0552 
0553         if (counts[i].val != 0)
0554             nonzero++;
0555     }
0556 
0557     if (nonzero != 0)
0558         avg = avg / nonzero;
0559     else
0560         avg = 0;
0561 
0562     error = display_error(avg, max, min, expected_counts.val);
0563 
0564     __T("Error out of range!", ((error <= 1.0) && (error >= -1.0)));
0565 
0566     perf_evlist__close(evlist);
0567     perf_evlist__delete(evlist);
0568 
0569     perf_thread_map__put(threads);
0570 
0571     return 0;
0572 }
0573 
0574 int test_evlist(int argc, char **argv)
0575 {
0576     __T_START;
0577 
0578     libperf_init(libperf_print);
0579 
0580     test_stat_cpu();
0581     test_stat_thread();
0582     test_stat_thread_enable();
0583     test_mmap_thread();
0584     test_mmap_cpus();
0585     test_stat_multiplexing();
0586 
0587     __T_END;
0588     return tests_failed == 0 ? 0 : -1;
0589 }