Loading...
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 | // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <inttypes.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <sys/mman.h> #include <linux/string.h> #include "tests.h" #include "util/debug.h" #include "util/evsel.h" #include "util/evlist.h" #include "util/cpumap.h" #include "util/mmap.h" #include "util/sample.h" #include "util/thread_map.h" #include <perf/evlist.h> #include <perf/mmap.h> #define NR_LOOPS 10000000 /* * This test will open software clock events (cpu-clock, task-clock) * then check their frequency -> period conversion has no artifact of * setting period to 1 forcefully. */ static int __test__sw_clock_freq(enum perf_sw_ids clock_id) { int i, err = -1; volatile int tmp = 0; u64 total_periods = 0; int nr_samples = 0; char sbuf[STRERR_BUFSIZE]; union perf_event *event; struct evsel *evsel; struct evlist *evlist; struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = clock_id, .sample_type = PERF_SAMPLE_PERIOD, .exclude_kernel = 1, .disabled = 1, .freq = 1, }; struct perf_cpu_map *cpus = NULL; struct perf_thread_map *threads = NULL; struct mmap *md; attr.sample_freq = 500; evlist = evlist__new(); if (evlist == NULL) { pr_debug("evlist__new\n"); return -1; } evsel = evsel__new(&attr); if (evsel == NULL) { pr_debug("evsel__new\n"); goto out_delete_evlist; } evlist__add(evlist, evsel); cpus = perf_cpu_map__new_any_cpu(); threads = thread_map__new_by_tid(getpid()); if (!cpus || !threads) { err = -ENOMEM; pr_debug("Not enough memory to create thread/cpu maps\n"); goto out_delete_evlist; } perf_evlist__set_maps(&evlist->core, cpus, threads); if (evlist__open(evlist)) { const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate"; err = -errno; pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", str_error_r(errno, sbuf, sizeof(sbuf)), knob, (u64)attr.sample_freq); goto out_delete_evlist; } err = evlist__mmap(evlist, 128); if (err < 0) { pr_debug("failed to mmap event: %d (%s)\n", errno, str_error_r(errno, sbuf, sizeof(sbuf))); goto out_delete_evlist; } evlist__enable(evlist); /* collect samples */ for (i = 0; i < NR_LOOPS; i++) tmp++; evlist__disable(evlist); md = &evlist->mmap[0]; if (perf_mmap__read_init(&md->core) < 0) goto out_init; while ((event = perf_mmap__read_event(&md->core)) != NULL) { struct perf_sample sample; if (event->header.type != PERF_RECORD_SAMPLE) goto next_event; err = evlist__parse_sample(evlist, event, &sample); if (err < 0) { pr_debug("Error during parse sample\n"); goto out_delete_evlist; } total_periods += sample.period; nr_samples++; next_event: perf_mmap__consume(&md->core); } perf_mmap__read_done(&md->core); out_init: if ((u64) nr_samples == total_periods) { pr_debug("All (%d) samples have period value of 1!\n", nr_samples); err = -1; } out_delete_evlist: perf_cpu_map__put(cpus); perf_thread_map__put(threads); evlist__delete(evlist); return err; } static int test__sw_clock_freq(struct test_suite *test __maybe_unused, int subtest __maybe_unused) { int ret; ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK); if (!ret) ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK); return ret; } DEFINE_SUITE("Software clock events period values", sw_clock_freq); |