149 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <errno.h>3#include <inttypes.h>4#include <unistd.h>5#include <stdlib.h>6#include <signal.h>7#include <sys/mman.h>8#include <linux/string.h>9 10#include "tests.h"11#include "util/debug.h"12#include "util/evsel.h"13#include "util/evlist.h"14#include "util/cpumap.h"15#include "util/mmap.h"16#include "util/sample.h"17#include "util/thread_map.h"18#include <perf/evlist.h>19#include <perf/mmap.h>20 21#define NR_LOOPS 1000000022 23/*24 * This test will open software clock events (cpu-clock, task-clock)25 * then check their frequency -> period conversion has no artifact of26 * setting period to 1 forcefully.27 */28static int __test__sw_clock_freq(enum perf_sw_ids clock_id)29{30 int i, err = -1;31 volatile int tmp = 0;32 u64 total_periods = 0;33 int nr_samples = 0;34 char sbuf[STRERR_BUFSIZE];35 union perf_event *event;36 struct evsel *evsel;37 struct evlist *evlist;38 struct perf_event_attr attr = {39 .type = PERF_TYPE_SOFTWARE,40 .config = clock_id,41 .sample_type = PERF_SAMPLE_PERIOD,42 .exclude_kernel = 1,43 .disabled = 1,44 .freq = 1,45 };46 struct perf_cpu_map *cpus = NULL;47 struct perf_thread_map *threads = NULL;48 struct mmap *md;49 50 attr.sample_freq = 500;51 52 evlist = evlist__new();53 if (evlist == NULL) {54 pr_debug("evlist__new\n");55 return -1;56 }57 58 evsel = evsel__new(&attr);59 if (evsel == NULL) {60 pr_debug("evsel__new\n");61 goto out_delete_evlist;62 }63 evlist__add(evlist, evsel);64 65 cpus = perf_cpu_map__new_any_cpu();66 threads = thread_map__new_by_tid(getpid());67 if (!cpus || !threads) {68 err = -ENOMEM;69 pr_debug("Not enough memory to create thread/cpu maps\n");70 goto out_delete_evlist;71 }72 73 perf_evlist__set_maps(&evlist->core, cpus, threads);74 75 if (evlist__open(evlist)) {76 const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate";77 78 err = -errno;79 pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n",80 str_error_r(errno, sbuf, sizeof(sbuf)),81 knob, (u64)attr.sample_freq);82 goto out_delete_evlist;83 }84 85 err = evlist__mmap(evlist, 128);86 if (err < 0) {87 pr_debug("failed to mmap event: %d (%s)\n", errno,88 str_error_r(errno, sbuf, sizeof(sbuf)));89 goto out_delete_evlist;90 }91 92 evlist__enable(evlist);93 94 /* collect samples */95 for (i = 0; i < NR_LOOPS; i++)96 tmp++;97 98 evlist__disable(evlist);99 100 md = &evlist->mmap[0];101 if (perf_mmap__read_init(&md->core) < 0)102 goto out_init;103 104 while ((event = perf_mmap__read_event(&md->core)) != NULL) {105 struct perf_sample sample;106 107 if (event->header.type != PERF_RECORD_SAMPLE)108 goto next_event;109 110 err = evlist__parse_sample(evlist, event, &sample);111 if (err < 0) {112 pr_debug("Error during parse sample\n");113 goto out_delete_evlist;114 }115 116 total_periods += sample.period;117 nr_samples++;118next_event:119 perf_mmap__consume(&md->core);120 }121 perf_mmap__read_done(&md->core);122 123out_init:124 if ((u64) nr_samples == total_periods) {125 pr_debug("All (%d) samples have period value of 1!\n",126 nr_samples);127 err = -1;128 }129 130out_delete_evlist:131 perf_cpu_map__put(cpus);132 perf_thread_map__put(threads);133 evlist__delete(evlist);134 return err;135}136 137static int test__sw_clock_freq(struct test_suite *test __maybe_unused, int subtest __maybe_unused)138{139 int ret;140 141 ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK);142 if (!ret)143 ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK);144 145 return ret;146}147 148DEFINE_SUITE("Software clock events period values", sw_clock_freq);149