18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <errno.h> 38c2ecf20Sopenharmony_ci#include <inttypes.h> 48c2ecf20Sopenharmony_ci#include <unistd.h> 58c2ecf20Sopenharmony_ci#include <stdlib.h> 68c2ecf20Sopenharmony_ci#include <signal.h> 78c2ecf20Sopenharmony_ci#include <sys/mman.h> 88c2ecf20Sopenharmony_ci#include <linux/string.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "tests.h" 118c2ecf20Sopenharmony_ci#include "util/debug.h" 128c2ecf20Sopenharmony_ci#include "util/evsel.h" 138c2ecf20Sopenharmony_ci#include "util/evlist.h" 148c2ecf20Sopenharmony_ci#include "util/cpumap.h" 158c2ecf20Sopenharmony_ci#include "util/mmap.h" 168c2ecf20Sopenharmony_ci#include "util/thread_map.h" 178c2ecf20Sopenharmony_ci#include <perf/evlist.h> 188c2ecf20Sopenharmony_ci#include <perf/mmap.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define NR_LOOPS 10000000 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * This test will open software clock events (cpu-clock, task-clock) 248c2ecf20Sopenharmony_ci * then check their frequency -> period conversion has no artifact of 258c2ecf20Sopenharmony_ci * setting period to 1 forcefully. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistatic int __test__sw_clock_freq(enum perf_sw_ids clock_id) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int i, err = -1; 308c2ecf20Sopenharmony_ci volatile int tmp = 0; 318c2ecf20Sopenharmony_ci u64 total_periods = 0; 328c2ecf20Sopenharmony_ci int nr_samples = 0; 338c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 348c2ecf20Sopenharmony_ci union perf_event *event; 358c2ecf20Sopenharmony_ci struct evsel *evsel; 368c2ecf20Sopenharmony_ci struct evlist *evlist; 378c2ecf20Sopenharmony_ci struct perf_event_attr attr = { 388c2ecf20Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 398c2ecf20Sopenharmony_ci .config = clock_id, 408c2ecf20Sopenharmony_ci .sample_type = PERF_SAMPLE_PERIOD, 418c2ecf20Sopenharmony_ci .exclude_kernel = 1, 428c2ecf20Sopenharmony_ci .disabled = 1, 438c2ecf20Sopenharmony_ci .freq = 1, 448c2ecf20Sopenharmony_ci }; 458c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus; 468c2ecf20Sopenharmony_ci struct perf_thread_map *threads; 478c2ecf20Sopenharmony_ci struct mmap *md; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci attr.sample_freq = 500; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci evlist = evlist__new(); 528c2ecf20Sopenharmony_ci if (evlist == NULL) { 538c2ecf20Sopenharmony_ci pr_debug("evlist__new\n"); 548c2ecf20Sopenharmony_ci return -1; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci evsel = evsel__new(&attr); 588c2ecf20Sopenharmony_ci if (evsel == NULL) { 598c2ecf20Sopenharmony_ci pr_debug("evsel__new\n"); 608c2ecf20Sopenharmony_ci goto out_delete_evlist; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci evlist__add(evlist, evsel); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci cpus = perf_cpu_map__dummy_new(); 658c2ecf20Sopenharmony_ci threads = thread_map__new_by_tid(getpid()); 668c2ecf20Sopenharmony_ci if (!cpus || !threads) { 678c2ecf20Sopenharmony_ci err = -ENOMEM; 688c2ecf20Sopenharmony_ci pr_debug("Not enough memory to create thread/cpu maps\n"); 698c2ecf20Sopenharmony_ci goto out_free_maps; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci perf_evlist__set_maps(&evlist->core, cpus, threads); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci cpus = NULL; 758c2ecf20Sopenharmony_ci threads = NULL; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (evlist__open(evlist)) { 788c2ecf20Sopenharmony_ci const char *knob = "/proc/sys/kernel/perf_event_max_sample_rate"; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci err = -errno; 818c2ecf20Sopenharmony_ci pr_debug("Couldn't open evlist: %s\nHint: check %s, using %" PRIu64 " in this test.\n", 828c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf)), 838c2ecf20Sopenharmony_ci knob, (u64)attr.sample_freq); 848c2ecf20Sopenharmony_ci goto out_delete_evlist; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci err = evlist__mmap(evlist, 128); 888c2ecf20Sopenharmony_ci if (err < 0) { 898c2ecf20Sopenharmony_ci pr_debug("failed to mmap event: %d (%s)\n", errno, 908c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 918c2ecf20Sopenharmony_ci goto out_delete_evlist; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci evlist__enable(evlist); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* collect samples */ 978c2ecf20Sopenharmony_ci for (i = 0; i < NR_LOOPS; i++) 988c2ecf20Sopenharmony_ci tmp++; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci evlist__disable(evlist); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci md = &evlist->mmap[0]; 1038c2ecf20Sopenharmony_ci if (perf_mmap__read_init(&md->core) < 0) 1048c2ecf20Sopenharmony_ci goto out_init; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1078c2ecf20Sopenharmony_ci struct perf_sample sample; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (event->header.type != PERF_RECORD_SAMPLE) 1108c2ecf20Sopenharmony_ci goto next_event; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci err = perf_evlist__parse_sample(evlist, event, &sample); 1138c2ecf20Sopenharmony_ci if (err < 0) { 1148c2ecf20Sopenharmony_ci pr_debug("Error during parse sample\n"); 1158c2ecf20Sopenharmony_ci goto out_delete_evlist; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci total_periods += sample.period; 1198c2ecf20Sopenharmony_ci nr_samples++; 1208c2ecf20Sopenharmony_cinext_event: 1218c2ecf20Sopenharmony_ci perf_mmap__consume(&md->core); 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci perf_mmap__read_done(&md->core); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ciout_init: 1268c2ecf20Sopenharmony_ci if ((u64) nr_samples == total_periods) { 1278c2ecf20Sopenharmony_ci pr_debug("All (%d) samples have period value of 1!\n", 1288c2ecf20Sopenharmony_ci nr_samples); 1298c2ecf20Sopenharmony_ci err = -1; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciout_free_maps: 1338c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 1348c2ecf20Sopenharmony_ci perf_thread_map__put(threads); 1358c2ecf20Sopenharmony_ciout_delete_evlist: 1368c2ecf20Sopenharmony_ci evlist__delete(evlist); 1378c2ecf20Sopenharmony_ci return err; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciint test__sw_clock_freq(struct test *test __maybe_unused, int subtest __maybe_unused) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci int ret; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ret = __test__sw_clock_freq(PERF_COUNT_SW_CPU_CLOCK); 1458c2ecf20Sopenharmony_ci if (!ret) 1468c2ecf20Sopenharmony_ci ret = __test__sw_clock_freq(PERF_COUNT_SW_TASK_CLOCK); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci} 150