13989bbf9SLeo Yan // SPDX-License-Identifier: GPL-2.0 23989bbf9SLeo Yan #include <errno.h> 33989bbf9SLeo Yan #include <inttypes.h> 43989bbf9SLeo Yan #include <limits.h> 53989bbf9SLeo Yan #include <stdbool.h> 63989bbf9SLeo Yan #include <stdio.h> 73989bbf9SLeo Yan #include <unistd.h> 83989bbf9SLeo Yan #include <linux/types.h> 93989bbf9SLeo Yan #include <sys/prctl.h> 103989bbf9SLeo Yan #include <perf/cpumap.h> 113989bbf9SLeo Yan #include <perf/evlist.h> 123989bbf9SLeo Yan #include <perf/mmap.h> 133989bbf9SLeo Yan 143989bbf9SLeo Yan #include "debug.h" 153989bbf9SLeo Yan #include "parse-events.h" 163989bbf9SLeo Yan #include "evlist.h" 173989bbf9SLeo Yan #include "evsel.h" 183989bbf9SLeo Yan #include "thread_map.h" 193989bbf9SLeo Yan #include "record.h" 203989bbf9SLeo Yan #include "tsc.h" 213989bbf9SLeo Yan #include "mmap.h" 223989bbf9SLeo Yan #include "tests.h" 23d9da6f70SJin Yao #include "pmu.h" 24de3d5fd8SJin Yao #include "pmu-hybrid.h" 253989bbf9SLeo Yan 26e74dd9cbSIan Rogers /* 27e74dd9cbSIan Rogers * Except x86_64/i386 and Arm64, other archs don't support TSC in perf. Just 28e74dd9cbSIan Rogers * enable the test for x86_64/i386 and Arm64 archs. 29e74dd9cbSIan Rogers */ 30e74dd9cbSIan Rogers #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) 31e74dd9cbSIan Rogers #define TSC_IS_SUPPORTED 1 32e74dd9cbSIan Rogers #else 33e74dd9cbSIan Rogers #define TSC_IS_SUPPORTED 0 34e74dd9cbSIan Rogers #endif 35e74dd9cbSIan Rogers 363989bbf9SLeo Yan #define CHECK__(x) { \ 373989bbf9SLeo Yan while ((x) < 0) { \ 383989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 393989bbf9SLeo Yan goto out_err; \ 403989bbf9SLeo Yan } \ 413989bbf9SLeo Yan } 423989bbf9SLeo Yan 433989bbf9SLeo Yan #define CHECK_NOT_NULL__(x) { \ 443989bbf9SLeo Yan while ((x) == NULL) { \ 453989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 463989bbf9SLeo Yan goto out_err; \ 473989bbf9SLeo Yan } \ 483989bbf9SLeo Yan } 493989bbf9SLeo Yan 50*290fa68bSChengdong Li static int test__tsc_is_supported(struct test_suite *test __maybe_unused, 51*290fa68bSChengdong Li int subtest __maybe_unused) 52*290fa68bSChengdong Li { 53*290fa68bSChengdong Li if (!TSC_IS_SUPPORTED) { 54*290fa68bSChengdong Li pr_debug("Test not supported on this architecture\n"); 55*290fa68bSChengdong Li return TEST_SKIP; 56*290fa68bSChengdong Li } 57*290fa68bSChengdong Li 58*290fa68bSChengdong Li return TEST_OK; 59*290fa68bSChengdong Li } 60*290fa68bSChengdong Li 613989bbf9SLeo Yan /** 623989bbf9SLeo Yan * test__perf_time_to_tsc - test converting perf time to TSC. 633989bbf9SLeo Yan * 643989bbf9SLeo Yan * This function implements a test that checks that the conversion of perf time 653989bbf9SLeo Yan * to and from TSC is consistent with the order of events. If the test passes 663989bbf9SLeo Yan * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 673989bbf9SLeo Yan * supported then then the test passes but " (not supported)" is printed. 683989bbf9SLeo Yan */ 6933f44bfdSIan Rogers static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 703989bbf9SLeo Yan { 713989bbf9SLeo Yan struct record_opts opts = { 723989bbf9SLeo Yan .mmap_pages = UINT_MAX, 733989bbf9SLeo Yan .user_freq = UINT_MAX, 743989bbf9SLeo Yan .user_interval = ULLONG_MAX, 753989bbf9SLeo Yan .target = { 763989bbf9SLeo Yan .uses_mmap = true, 773989bbf9SLeo Yan }, 783989bbf9SLeo Yan .sample_time = true, 793989bbf9SLeo Yan }; 803989bbf9SLeo Yan struct perf_thread_map *threads = NULL; 813989bbf9SLeo Yan struct perf_cpu_map *cpus = NULL; 823989bbf9SLeo Yan struct evlist *evlist = NULL; 833989bbf9SLeo Yan struct evsel *evsel = NULL; 84*290fa68bSChengdong Li int err = TEST_FAIL, ret, i; 853989bbf9SLeo Yan const char *comm1, *comm2; 863989bbf9SLeo Yan struct perf_tsc_conversion tc; 873989bbf9SLeo Yan struct perf_event_mmap_page *pc; 883989bbf9SLeo Yan union perf_event *event; 893989bbf9SLeo Yan u64 test_tsc, comm1_tsc, comm2_tsc; 903989bbf9SLeo Yan u64 test_time, comm1_time = 0, comm2_time = 0; 913989bbf9SLeo Yan struct mmap *md; 923989bbf9SLeo Yan 93e74dd9cbSIan Rogers 943989bbf9SLeo Yan threads = thread_map__new(-1, getpid(), UINT_MAX); 953989bbf9SLeo Yan CHECK_NOT_NULL__(threads); 963989bbf9SLeo Yan 973989bbf9SLeo Yan cpus = perf_cpu_map__new(NULL); 983989bbf9SLeo Yan CHECK_NOT_NULL__(cpus); 993989bbf9SLeo Yan 1003989bbf9SLeo Yan evlist = evlist__new(); 1013989bbf9SLeo Yan CHECK_NOT_NULL__(evlist); 1023989bbf9SLeo Yan 1033989bbf9SLeo Yan perf_evlist__set_maps(&evlist->core, cpus, threads); 1043989bbf9SLeo Yan 1053989bbf9SLeo Yan CHECK__(parse_events(evlist, "cycles:u", NULL)); 1063989bbf9SLeo Yan 10778e1bc25SArnaldo Carvalho de Melo evlist__config(evlist, &opts, NULL); 1083989bbf9SLeo Yan 1093989bbf9SLeo Yan evsel = evlist__first(evlist); 1103989bbf9SLeo Yan 1113989bbf9SLeo Yan evsel->core.attr.comm = 1; 1123989bbf9SLeo Yan evsel->core.attr.disabled = 1; 1133989bbf9SLeo Yan evsel->core.attr.enable_on_exec = 0; 1143989bbf9SLeo Yan 115d9da6f70SJin Yao /* 116d9da6f70SJin Yao * For hybrid "cycles:u", it creates two events. 117d9da6f70SJin Yao * Init the second evsel here. 118d9da6f70SJin Yao */ 119de3d5fd8SJin Yao if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) { 120d9da6f70SJin Yao evsel = evsel__next(evsel); 121d9da6f70SJin Yao evsel->core.attr.comm = 1; 122d9da6f70SJin Yao evsel->core.attr.disabled = 1; 123d9da6f70SJin Yao evsel->core.attr.enable_on_exec = 0; 124d9da6f70SJin Yao } 125d9da6f70SJin Yao 1263989bbf9SLeo Yan CHECK__(evlist__open(evlist)); 1273989bbf9SLeo Yan 1283989bbf9SLeo Yan CHECK__(evlist__mmap(evlist, UINT_MAX)); 1293989bbf9SLeo Yan 1303989bbf9SLeo Yan pc = evlist->mmap[0].core.base; 1313989bbf9SLeo Yan ret = perf_read_tsc_conversion(pc, &tc); 1323989bbf9SLeo Yan if (ret) { 1333989bbf9SLeo Yan if (ret == -EOPNOTSUPP) { 134*290fa68bSChengdong Li pr_debug("perf_read_tsc_conversion is not supported in current kernel\n"); 135*290fa68bSChengdong Li err = TEST_SKIP; 1363989bbf9SLeo Yan } 1373989bbf9SLeo Yan goto out_err; 1383989bbf9SLeo Yan } 1393989bbf9SLeo Yan 1403989bbf9SLeo Yan evlist__enable(evlist); 1413989bbf9SLeo Yan 1423989bbf9SLeo Yan comm1 = "Test COMM 1"; 1433989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); 1443989bbf9SLeo Yan 1453989bbf9SLeo Yan test_tsc = rdtsc(); 1463989bbf9SLeo Yan 1473989bbf9SLeo Yan comm2 = "Test COMM 2"; 1483989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); 1493989bbf9SLeo Yan 1503989bbf9SLeo Yan evlist__disable(evlist); 1513989bbf9SLeo Yan 1523989bbf9SLeo Yan for (i = 0; i < evlist->core.nr_mmaps; i++) { 1533989bbf9SLeo Yan md = &evlist->mmap[i]; 1543989bbf9SLeo Yan if (perf_mmap__read_init(&md->core) < 0) 1553989bbf9SLeo Yan continue; 1563989bbf9SLeo Yan 1573989bbf9SLeo Yan while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1583989bbf9SLeo Yan struct perf_sample sample; 1593989bbf9SLeo Yan 1603989bbf9SLeo Yan if (event->header.type != PERF_RECORD_COMM || 1613989bbf9SLeo Yan (pid_t)event->comm.pid != getpid() || 1623989bbf9SLeo Yan (pid_t)event->comm.tid != getpid()) 1633989bbf9SLeo Yan goto next_event; 1643989bbf9SLeo Yan 1653989bbf9SLeo Yan if (strcmp(event->comm.comm, comm1) == 0) { 1663989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1673989bbf9SLeo Yan comm1_time = sample.time; 1683989bbf9SLeo Yan } 1693989bbf9SLeo Yan if (strcmp(event->comm.comm, comm2) == 0) { 1703989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1713989bbf9SLeo Yan comm2_time = sample.time; 1723989bbf9SLeo Yan } 1733989bbf9SLeo Yan next_event: 1743989bbf9SLeo Yan perf_mmap__consume(&md->core); 1753989bbf9SLeo Yan } 1763989bbf9SLeo Yan perf_mmap__read_done(&md->core); 1773989bbf9SLeo Yan } 1783989bbf9SLeo Yan 1793989bbf9SLeo Yan if (!comm1_time || !comm2_time) 1803989bbf9SLeo Yan goto out_err; 1813989bbf9SLeo Yan 1823989bbf9SLeo Yan test_time = tsc_to_perf_time(test_tsc, &tc); 1833989bbf9SLeo Yan comm1_tsc = perf_time_to_tsc(comm1_time, &tc); 1843989bbf9SLeo Yan comm2_tsc = perf_time_to_tsc(comm2_time, &tc); 1853989bbf9SLeo Yan 1863989bbf9SLeo Yan pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n", 1873989bbf9SLeo Yan comm1_time, comm1_tsc); 1883989bbf9SLeo Yan pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n", 1893989bbf9SLeo Yan test_time, test_tsc); 1903989bbf9SLeo Yan pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n", 1913989bbf9SLeo Yan comm2_time, comm2_tsc); 1923989bbf9SLeo Yan 1933989bbf9SLeo Yan if (test_time <= comm1_time || 1943989bbf9SLeo Yan test_time >= comm2_time) 1953989bbf9SLeo Yan goto out_err; 1963989bbf9SLeo Yan 1973989bbf9SLeo Yan if (test_tsc <= comm1_tsc || 1983989bbf9SLeo Yan test_tsc >= comm2_tsc) 1993989bbf9SLeo Yan goto out_err; 2003989bbf9SLeo Yan 201*290fa68bSChengdong Li err = TEST_OK; 2023989bbf9SLeo Yan 2033989bbf9SLeo Yan out_err: 2043989bbf9SLeo Yan evlist__delete(evlist); 205846580c2SNamhyung Kim perf_cpu_map__put(cpus); 206846580c2SNamhyung Kim perf_thread_map__put(threads); 2073989bbf9SLeo Yan return err; 2083989bbf9SLeo Yan } 209248dd9b5SLeo Yan 210*290fa68bSChengdong Li static struct test_case time_to_tsc_tests[] = { 211*290fa68bSChengdong Li TEST_CASE_REASON("TSC support", tsc_is_supported, 212*290fa68bSChengdong Li "This architecture does not support"), 213*290fa68bSChengdong Li TEST_CASE_REASON("Perf time to TSC", perf_time_to_tsc, 214*290fa68bSChengdong Li "perf_read_tsc_conversion is not supported"), 215*290fa68bSChengdong Li { .name = NULL, } 216*290fa68bSChengdong Li }; 217*290fa68bSChengdong Li 218*290fa68bSChengdong Li struct test_suite suite__perf_time_to_tsc = { 219*290fa68bSChengdong Li .desc = "Convert perf time to TSC", 220*290fa68bSChengdong Li .test_cases = time_to_tsc_tests, 221*290fa68bSChengdong Li }; 222