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" 23*9823147dSArnaldo Carvalho de Melo #include "util/sample.h" 243989bbf9SLeo Yan 25e74dd9cbSIan Rogers /* 26e74dd9cbSIan Rogers * Except x86_64/i386 and Arm64, other archs don't support TSC in perf. Just 27e74dd9cbSIan Rogers * enable the test for x86_64/i386 and Arm64 archs. 28e74dd9cbSIan Rogers */ 29e74dd9cbSIan Rogers #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) 30e74dd9cbSIan Rogers #define TSC_IS_SUPPORTED 1 31e74dd9cbSIan Rogers #else 32e74dd9cbSIan Rogers #define TSC_IS_SUPPORTED 0 33e74dd9cbSIan Rogers #endif 34e74dd9cbSIan Rogers 353989bbf9SLeo Yan #define CHECK__(x) { \ 363989bbf9SLeo Yan while ((x) < 0) { \ 373989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 383989bbf9SLeo Yan goto out_err; \ 393989bbf9SLeo Yan } \ 403989bbf9SLeo Yan } 413989bbf9SLeo Yan 423989bbf9SLeo Yan #define CHECK_NOT_NULL__(x) { \ 433989bbf9SLeo Yan while ((x) == NULL) { \ 443989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 453989bbf9SLeo Yan goto out_err; \ 463989bbf9SLeo Yan } \ 473989bbf9SLeo Yan } 483989bbf9SLeo Yan 49290fa68bSChengdong Li static int test__tsc_is_supported(struct test_suite *test __maybe_unused, 50290fa68bSChengdong Li int subtest __maybe_unused) 51290fa68bSChengdong Li { 52290fa68bSChengdong Li if (!TSC_IS_SUPPORTED) { 53290fa68bSChengdong Li pr_debug("Test not supported on this architecture\n"); 54290fa68bSChengdong Li return TEST_SKIP; 55290fa68bSChengdong Li } 56290fa68bSChengdong Li 57290fa68bSChengdong Li return TEST_OK; 58290fa68bSChengdong Li } 59290fa68bSChengdong Li 603989bbf9SLeo Yan /** 613989bbf9SLeo Yan * test__perf_time_to_tsc - test converting perf time to TSC. 623989bbf9SLeo Yan * 633989bbf9SLeo Yan * This function implements a test that checks that the conversion of perf time 643989bbf9SLeo Yan * to and from TSC is consistent with the order of events. If the test passes 653989bbf9SLeo Yan * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 66f3c96becSshaomin Deng * supported then the test passes but " (not supported)" is printed. 673989bbf9SLeo Yan */ 6833f44bfdSIan Rogers static int test__perf_time_to_tsc(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 693989bbf9SLeo Yan { 703989bbf9SLeo Yan struct record_opts opts = { 713989bbf9SLeo Yan .mmap_pages = UINT_MAX, 723989bbf9SLeo Yan .user_freq = UINT_MAX, 733989bbf9SLeo Yan .user_interval = ULLONG_MAX, 743989bbf9SLeo Yan .target = { 753989bbf9SLeo Yan .uses_mmap = true, 763989bbf9SLeo Yan }, 773989bbf9SLeo Yan .sample_time = true, 783989bbf9SLeo Yan }; 793989bbf9SLeo Yan struct perf_thread_map *threads = NULL; 803989bbf9SLeo Yan struct perf_cpu_map *cpus = NULL; 813989bbf9SLeo Yan struct evlist *evlist = NULL; 823989bbf9SLeo Yan struct evsel *evsel = NULL; 83290fa68bSChengdong Li int err = TEST_FAIL, ret, i; 843989bbf9SLeo Yan const char *comm1, *comm2; 853989bbf9SLeo Yan struct perf_tsc_conversion tc; 863989bbf9SLeo Yan struct perf_event_mmap_page *pc; 873989bbf9SLeo Yan union perf_event *event; 883989bbf9SLeo Yan u64 test_tsc, comm1_tsc, comm2_tsc; 893989bbf9SLeo Yan u64 test_time, comm1_time = 0, comm2_time = 0; 903989bbf9SLeo Yan struct mmap *md; 913989bbf9SLeo Yan 92e74dd9cbSIan Rogers 933989bbf9SLeo Yan threads = thread_map__new(-1, getpid(), UINT_MAX); 943989bbf9SLeo Yan CHECK_NOT_NULL__(threads); 953989bbf9SLeo Yan 963989bbf9SLeo Yan cpus = perf_cpu_map__new(NULL); 973989bbf9SLeo Yan CHECK_NOT_NULL__(cpus); 983989bbf9SLeo Yan 993989bbf9SLeo Yan evlist = evlist__new(); 1003989bbf9SLeo Yan CHECK_NOT_NULL__(evlist); 1013989bbf9SLeo Yan 1023989bbf9SLeo Yan perf_evlist__set_maps(&evlist->core, cpus, threads); 1033989bbf9SLeo Yan 104806731a9SAdrian Hunter CHECK__(parse_event(evlist, "cycles:u")); 1053989bbf9SLeo Yan 10678e1bc25SArnaldo Carvalho de Melo evlist__config(evlist, &opts, NULL); 1073989bbf9SLeo Yan 108deb44a62SAdrian Hunter /* For hybrid "cycles:u", it creates two events */ 109deb44a62SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 110d9da6f70SJin Yao evsel->core.attr.comm = 1; 111d9da6f70SJin Yao evsel->core.attr.disabled = 1; 112d9da6f70SJin Yao evsel->core.attr.enable_on_exec = 0; 113d9da6f70SJin Yao } 114d9da6f70SJin Yao 115498c7a54SAdrian Hunter ret = evlist__open(evlist); 116498c7a54SAdrian Hunter if (ret < 0) { 117498c7a54SAdrian Hunter if (ret == -ENOENT) 1185bb017d4SThomas Richter err = TEST_SKIP; 119498c7a54SAdrian Hunter else 120498c7a54SAdrian Hunter pr_debug("evlist__open() failed\n"); 1215bb017d4SThomas Richter goto out_err; 1225bb017d4SThomas Richter } 1233989bbf9SLeo Yan 1243989bbf9SLeo Yan CHECK__(evlist__mmap(evlist, UINT_MAX)); 1253989bbf9SLeo Yan 1263989bbf9SLeo Yan pc = evlist->mmap[0].core.base; 1273989bbf9SLeo Yan ret = perf_read_tsc_conversion(pc, &tc); 1283989bbf9SLeo Yan if (ret) { 1293989bbf9SLeo Yan if (ret == -EOPNOTSUPP) { 130290fa68bSChengdong Li pr_debug("perf_read_tsc_conversion is not supported in current kernel\n"); 131290fa68bSChengdong Li err = TEST_SKIP; 1323989bbf9SLeo Yan } 1333989bbf9SLeo Yan goto out_err; 1343989bbf9SLeo Yan } 1353989bbf9SLeo Yan 1363989bbf9SLeo Yan evlist__enable(evlist); 1373989bbf9SLeo Yan 1383989bbf9SLeo Yan comm1 = "Test COMM 1"; 1393989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); 1403989bbf9SLeo Yan 1413989bbf9SLeo Yan test_tsc = rdtsc(); 1423989bbf9SLeo Yan 1433989bbf9SLeo Yan comm2 = "Test COMM 2"; 1443989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); 1453989bbf9SLeo Yan 1463989bbf9SLeo Yan evlist__disable(evlist); 1473989bbf9SLeo Yan 1483989bbf9SLeo Yan for (i = 0; i < evlist->core.nr_mmaps; i++) { 1493989bbf9SLeo Yan md = &evlist->mmap[i]; 1503989bbf9SLeo Yan if (perf_mmap__read_init(&md->core) < 0) 1513989bbf9SLeo Yan continue; 1523989bbf9SLeo Yan 1533989bbf9SLeo Yan while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1543989bbf9SLeo Yan struct perf_sample sample; 1553989bbf9SLeo Yan 1563989bbf9SLeo Yan if (event->header.type != PERF_RECORD_COMM || 1573989bbf9SLeo Yan (pid_t)event->comm.pid != getpid() || 1583989bbf9SLeo Yan (pid_t)event->comm.tid != getpid()) 1593989bbf9SLeo Yan goto next_event; 1603989bbf9SLeo Yan 1613989bbf9SLeo Yan if (strcmp(event->comm.comm, comm1) == 0) { 162deb44a62SAdrian Hunter CHECK_NOT_NULL__(evsel = evlist__event2evsel(evlist, event)); 1633989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1643989bbf9SLeo Yan comm1_time = sample.time; 1653989bbf9SLeo Yan } 1663989bbf9SLeo Yan if (strcmp(event->comm.comm, comm2) == 0) { 167deb44a62SAdrian Hunter CHECK_NOT_NULL__(evsel = evlist__event2evsel(evlist, event)); 1683989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1693989bbf9SLeo Yan comm2_time = sample.time; 1703989bbf9SLeo Yan } 1713989bbf9SLeo Yan next_event: 1723989bbf9SLeo Yan perf_mmap__consume(&md->core); 1733989bbf9SLeo Yan } 1743989bbf9SLeo Yan perf_mmap__read_done(&md->core); 1753989bbf9SLeo Yan } 1763989bbf9SLeo Yan 1773989bbf9SLeo Yan if (!comm1_time || !comm2_time) 1783989bbf9SLeo Yan goto out_err; 1793989bbf9SLeo Yan 1803989bbf9SLeo Yan test_time = tsc_to_perf_time(test_tsc, &tc); 1813989bbf9SLeo Yan comm1_tsc = perf_time_to_tsc(comm1_time, &tc); 1823989bbf9SLeo Yan comm2_tsc = perf_time_to_tsc(comm2_time, &tc); 1833989bbf9SLeo Yan 1843989bbf9SLeo Yan pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n", 1853989bbf9SLeo Yan comm1_time, comm1_tsc); 1863989bbf9SLeo Yan pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n", 1873989bbf9SLeo Yan test_time, test_tsc); 1883989bbf9SLeo Yan pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n", 1893989bbf9SLeo Yan comm2_time, comm2_tsc); 1903989bbf9SLeo Yan 1913989bbf9SLeo Yan if (test_time <= comm1_time || 1923989bbf9SLeo Yan test_time >= comm2_time) 1933989bbf9SLeo Yan goto out_err; 1943989bbf9SLeo Yan 1953989bbf9SLeo Yan if (test_tsc <= comm1_tsc || 1963989bbf9SLeo Yan test_tsc >= comm2_tsc) 1973989bbf9SLeo Yan goto out_err; 1983989bbf9SLeo Yan 199290fa68bSChengdong Li err = TEST_OK; 2003989bbf9SLeo Yan 2013989bbf9SLeo Yan out_err: 2023989bbf9SLeo Yan evlist__delete(evlist); 203846580c2SNamhyung Kim perf_cpu_map__put(cpus); 204846580c2SNamhyung Kim perf_thread_map__put(threads); 2053989bbf9SLeo Yan return err; 2063989bbf9SLeo Yan } 207248dd9b5SLeo Yan 208290fa68bSChengdong Li static struct test_case time_to_tsc_tests[] = { 209290fa68bSChengdong Li TEST_CASE_REASON("TSC support", tsc_is_supported, 210290fa68bSChengdong Li "This architecture does not support"), 211290fa68bSChengdong Li TEST_CASE_REASON("Perf time to TSC", perf_time_to_tsc, 212290fa68bSChengdong Li "perf_read_tsc_conversion is not supported"), 213290fa68bSChengdong Li { .name = NULL, } 214290fa68bSChengdong Li }; 215290fa68bSChengdong Li 216290fa68bSChengdong Li struct test_suite suite__perf_time_to_tsc = { 217290fa68bSChengdong Li .desc = "Convert perf time to TSC", 218290fa68bSChengdong Li .test_cases = time_to_tsc_tests, 219290fa68bSChengdong Li }; 220