18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <errno.h> 38c2ecf20Sopenharmony_ci#include <inttypes.h> 48c2ecf20Sopenharmony_ci#include <limits.h> 58c2ecf20Sopenharmony_ci#include <stdbool.h> 68c2ecf20Sopenharmony_ci#include <stdio.h> 78c2ecf20Sopenharmony_ci#include <unistd.h> 88c2ecf20Sopenharmony_ci#include <linux/types.h> 98c2ecf20Sopenharmony_ci#include <sys/prctl.h> 108c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 118c2ecf20Sopenharmony_ci#include <perf/evlist.h> 128c2ecf20Sopenharmony_ci#include <perf/mmap.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "debug.h" 158c2ecf20Sopenharmony_ci#include "parse-events.h" 168c2ecf20Sopenharmony_ci#include "evlist.h" 178c2ecf20Sopenharmony_ci#include "evsel.h" 188c2ecf20Sopenharmony_ci#include "thread_map.h" 198c2ecf20Sopenharmony_ci#include "record.h" 208c2ecf20Sopenharmony_ci#include "tsc.h" 218c2ecf20Sopenharmony_ci#include "util/mmap.h" 228c2ecf20Sopenharmony_ci#include "tests/tests.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "arch-tests.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define CHECK__(x) { \ 278c2ecf20Sopenharmony_ci while ((x) < 0) { \ 288c2ecf20Sopenharmony_ci pr_debug(#x " failed!\n"); \ 298c2ecf20Sopenharmony_ci goto out_err; \ 308c2ecf20Sopenharmony_ci } \ 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define CHECK_NOT_NULL__(x) { \ 348c2ecf20Sopenharmony_ci while ((x) == NULL) { \ 358c2ecf20Sopenharmony_ci pr_debug(#x " failed!\n"); \ 368c2ecf20Sopenharmony_ci goto out_err; \ 378c2ecf20Sopenharmony_ci } \ 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * test__perf_time_to_tsc - test converting perf time to TSC. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * This function implements a test that checks that the conversion of perf time 448c2ecf20Sopenharmony_ci * to and from TSC is consistent with the order of events. If the test passes 458c2ecf20Sopenharmony_ci * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 468c2ecf20Sopenharmony_ci * supported then then the test passes but " (not supported)" is printed. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ciint test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe_unused) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct record_opts opts = { 518c2ecf20Sopenharmony_ci .mmap_pages = UINT_MAX, 528c2ecf20Sopenharmony_ci .user_freq = UINT_MAX, 538c2ecf20Sopenharmony_ci .user_interval = ULLONG_MAX, 548c2ecf20Sopenharmony_ci .target = { 558c2ecf20Sopenharmony_ci .uses_mmap = true, 568c2ecf20Sopenharmony_ci }, 578c2ecf20Sopenharmony_ci .sample_time = true, 588c2ecf20Sopenharmony_ci }; 598c2ecf20Sopenharmony_ci struct perf_thread_map *threads = NULL; 608c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus = NULL; 618c2ecf20Sopenharmony_ci struct evlist *evlist = NULL; 628c2ecf20Sopenharmony_ci struct evsel *evsel = NULL; 638c2ecf20Sopenharmony_ci int err = -1, ret, i; 648c2ecf20Sopenharmony_ci const char *comm1, *comm2; 658c2ecf20Sopenharmony_ci struct perf_tsc_conversion tc; 668c2ecf20Sopenharmony_ci struct perf_event_mmap_page *pc; 678c2ecf20Sopenharmony_ci union perf_event *event; 688c2ecf20Sopenharmony_ci u64 test_tsc, comm1_tsc, comm2_tsc; 698c2ecf20Sopenharmony_ci u64 test_time, comm1_time = 0, comm2_time = 0; 708c2ecf20Sopenharmony_ci struct mmap *md; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci threads = thread_map__new(-1, getpid(), UINT_MAX); 738c2ecf20Sopenharmony_ci CHECK_NOT_NULL__(threads); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci cpus = perf_cpu_map__new(NULL); 768c2ecf20Sopenharmony_ci CHECK_NOT_NULL__(cpus); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci evlist = evlist__new(); 798c2ecf20Sopenharmony_ci CHECK_NOT_NULL__(evlist); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci perf_evlist__set_maps(&evlist->core, cpus, threads); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci CHECK__(parse_events(evlist, "cycles:u", NULL)); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci perf_evlist__config(evlist, &opts, NULL); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci evsel = evlist__first(evlist); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci evsel->core.attr.comm = 1; 908c2ecf20Sopenharmony_ci evsel->core.attr.disabled = 1; 918c2ecf20Sopenharmony_ci evsel->core.attr.enable_on_exec = 0; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci CHECK__(evlist__open(evlist)); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci CHECK__(evlist__mmap(evlist, UINT_MAX)); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci pc = evlist->mmap[0].core.base; 988c2ecf20Sopenharmony_ci ret = perf_read_tsc_conversion(pc, &tc); 998c2ecf20Sopenharmony_ci if (ret) { 1008c2ecf20Sopenharmony_ci if (ret == -EOPNOTSUPP) { 1018c2ecf20Sopenharmony_ci fprintf(stderr, " (not supported)"); 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci goto out_err; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci evlist__enable(evlist); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci comm1 = "Test COMM 1"; 1108c2ecf20Sopenharmony_ci CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci test_tsc = rdtsc(); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci comm2 = "Test COMM 2"; 1158c2ecf20Sopenharmony_ci CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci evlist__disable(evlist); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci for (i = 0; i < evlist->core.nr_mmaps; i++) { 1208c2ecf20Sopenharmony_ci md = &evlist->mmap[i]; 1218c2ecf20Sopenharmony_ci if (perf_mmap__read_init(&md->core) < 0) 1228c2ecf20Sopenharmony_ci continue; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1258c2ecf20Sopenharmony_ci struct perf_sample sample; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (event->header.type != PERF_RECORD_COMM || 1288c2ecf20Sopenharmony_ci (pid_t)event->comm.pid != getpid() || 1298c2ecf20Sopenharmony_ci (pid_t)event->comm.tid != getpid()) 1308c2ecf20Sopenharmony_ci goto next_event; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (strcmp(event->comm.comm, comm1) == 0) { 1338c2ecf20Sopenharmony_ci CHECK__(evsel__parse_sample(evsel, event, &sample)); 1348c2ecf20Sopenharmony_ci comm1_time = sample.time; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci if (strcmp(event->comm.comm, comm2) == 0) { 1378c2ecf20Sopenharmony_ci CHECK__(evsel__parse_sample(evsel, event, &sample)); 1388c2ecf20Sopenharmony_ci comm2_time = sample.time; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_cinext_event: 1418c2ecf20Sopenharmony_ci perf_mmap__consume(&md->core); 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci perf_mmap__read_done(&md->core); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!comm1_time || !comm2_time) 1478c2ecf20Sopenharmony_ci goto out_err; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci test_time = tsc_to_perf_time(test_tsc, &tc); 1508c2ecf20Sopenharmony_ci comm1_tsc = perf_time_to_tsc(comm1_time, &tc); 1518c2ecf20Sopenharmony_ci comm2_tsc = perf_time_to_tsc(comm2_time, &tc); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n", 1548c2ecf20Sopenharmony_ci comm1_time, comm1_tsc); 1558c2ecf20Sopenharmony_ci pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n", 1568c2ecf20Sopenharmony_ci test_time, test_tsc); 1578c2ecf20Sopenharmony_ci pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n", 1588c2ecf20Sopenharmony_ci comm2_time, comm2_tsc); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (test_time <= comm1_time || 1618c2ecf20Sopenharmony_ci test_time >= comm2_time) 1628c2ecf20Sopenharmony_ci goto out_err; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (test_tsc <= comm1_tsc || 1658c2ecf20Sopenharmony_ci test_tsc >= comm2_tsc) 1668c2ecf20Sopenharmony_ci goto out_err; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci err = 0; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciout_err: 1718c2ecf20Sopenharmony_ci evlist__delete(evlist); 1728c2ecf20Sopenharmony_ci return err; 1738c2ecf20Sopenharmony_ci} 174