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" 24*de3d5fd8SJin Yao #include "pmu-hybrid.h" 253989bbf9SLeo Yan 263989bbf9SLeo Yan #define CHECK__(x) { \ 273989bbf9SLeo Yan while ((x) < 0) { \ 283989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 293989bbf9SLeo Yan goto out_err; \ 303989bbf9SLeo Yan } \ 313989bbf9SLeo Yan } 323989bbf9SLeo Yan 333989bbf9SLeo Yan #define CHECK_NOT_NULL__(x) { \ 343989bbf9SLeo Yan while ((x) == NULL) { \ 353989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 363989bbf9SLeo Yan goto out_err; \ 373989bbf9SLeo Yan } \ 383989bbf9SLeo Yan } 393989bbf9SLeo Yan 403989bbf9SLeo Yan /** 413989bbf9SLeo Yan * test__perf_time_to_tsc - test converting perf time to TSC. 423989bbf9SLeo Yan * 433989bbf9SLeo Yan * This function implements a test that checks that the conversion of perf time 443989bbf9SLeo Yan * to and from TSC is consistent with the order of events. If the test passes 453989bbf9SLeo Yan * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 463989bbf9SLeo Yan * supported then then the test passes but " (not supported)" is printed. 473989bbf9SLeo Yan */ 483989bbf9SLeo Yan int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe_unused) 493989bbf9SLeo Yan { 503989bbf9SLeo Yan struct record_opts opts = { 513989bbf9SLeo Yan .mmap_pages = UINT_MAX, 523989bbf9SLeo Yan .user_freq = UINT_MAX, 533989bbf9SLeo Yan .user_interval = ULLONG_MAX, 543989bbf9SLeo Yan .target = { 553989bbf9SLeo Yan .uses_mmap = true, 563989bbf9SLeo Yan }, 573989bbf9SLeo Yan .sample_time = true, 583989bbf9SLeo Yan }; 593989bbf9SLeo Yan struct perf_thread_map *threads = NULL; 603989bbf9SLeo Yan struct perf_cpu_map *cpus = NULL; 613989bbf9SLeo Yan struct evlist *evlist = NULL; 623989bbf9SLeo Yan struct evsel *evsel = NULL; 633989bbf9SLeo Yan int err = -1, ret, i; 643989bbf9SLeo Yan const char *comm1, *comm2; 653989bbf9SLeo Yan struct perf_tsc_conversion tc; 663989bbf9SLeo Yan struct perf_event_mmap_page *pc; 673989bbf9SLeo Yan union perf_event *event; 683989bbf9SLeo Yan u64 test_tsc, comm1_tsc, comm2_tsc; 693989bbf9SLeo Yan u64 test_time, comm1_time = 0, comm2_time = 0; 703989bbf9SLeo Yan struct mmap *md; 713989bbf9SLeo Yan 723989bbf9SLeo Yan threads = thread_map__new(-1, getpid(), UINT_MAX); 733989bbf9SLeo Yan CHECK_NOT_NULL__(threads); 743989bbf9SLeo Yan 753989bbf9SLeo Yan cpus = perf_cpu_map__new(NULL); 763989bbf9SLeo Yan CHECK_NOT_NULL__(cpus); 773989bbf9SLeo Yan 783989bbf9SLeo Yan evlist = evlist__new(); 793989bbf9SLeo Yan CHECK_NOT_NULL__(evlist); 803989bbf9SLeo Yan 813989bbf9SLeo Yan perf_evlist__set_maps(&evlist->core, cpus, threads); 823989bbf9SLeo Yan 833989bbf9SLeo Yan CHECK__(parse_events(evlist, "cycles:u", NULL)); 843989bbf9SLeo Yan 8578e1bc25SArnaldo Carvalho de Melo evlist__config(evlist, &opts, NULL); 863989bbf9SLeo Yan 873989bbf9SLeo Yan evsel = evlist__first(evlist); 883989bbf9SLeo Yan 893989bbf9SLeo Yan evsel->core.attr.comm = 1; 903989bbf9SLeo Yan evsel->core.attr.disabled = 1; 913989bbf9SLeo Yan evsel->core.attr.enable_on_exec = 0; 923989bbf9SLeo Yan 93d9da6f70SJin Yao /* 94d9da6f70SJin Yao * For hybrid "cycles:u", it creates two events. 95d9da6f70SJin Yao * Init the second evsel here. 96d9da6f70SJin Yao */ 97*de3d5fd8SJin Yao if (perf_pmu__has_hybrid() && perf_pmu__hybrid_mounted("cpu_atom")) { 98d9da6f70SJin Yao evsel = evsel__next(evsel); 99d9da6f70SJin Yao evsel->core.attr.comm = 1; 100d9da6f70SJin Yao evsel->core.attr.disabled = 1; 101d9da6f70SJin Yao evsel->core.attr.enable_on_exec = 0; 102d9da6f70SJin Yao } 103d9da6f70SJin Yao 1043989bbf9SLeo Yan CHECK__(evlist__open(evlist)); 1053989bbf9SLeo Yan 1063989bbf9SLeo Yan CHECK__(evlist__mmap(evlist, UINT_MAX)); 1073989bbf9SLeo Yan 1083989bbf9SLeo Yan pc = evlist->mmap[0].core.base; 1093989bbf9SLeo Yan ret = perf_read_tsc_conversion(pc, &tc); 1103989bbf9SLeo Yan if (ret) { 1113989bbf9SLeo Yan if (ret == -EOPNOTSUPP) { 1123989bbf9SLeo Yan fprintf(stderr, " (not supported)"); 1133989bbf9SLeo Yan return 0; 1143989bbf9SLeo Yan } 1153989bbf9SLeo Yan goto out_err; 1163989bbf9SLeo Yan } 1173989bbf9SLeo Yan 1183989bbf9SLeo Yan evlist__enable(evlist); 1193989bbf9SLeo Yan 1203989bbf9SLeo Yan comm1 = "Test COMM 1"; 1213989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); 1223989bbf9SLeo Yan 1233989bbf9SLeo Yan test_tsc = rdtsc(); 1243989bbf9SLeo Yan 1253989bbf9SLeo Yan comm2 = "Test COMM 2"; 1263989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); 1273989bbf9SLeo Yan 1283989bbf9SLeo Yan evlist__disable(evlist); 1293989bbf9SLeo Yan 1303989bbf9SLeo Yan for (i = 0; i < evlist->core.nr_mmaps; i++) { 1313989bbf9SLeo Yan md = &evlist->mmap[i]; 1323989bbf9SLeo Yan if (perf_mmap__read_init(&md->core) < 0) 1333989bbf9SLeo Yan continue; 1343989bbf9SLeo Yan 1353989bbf9SLeo Yan while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1363989bbf9SLeo Yan struct perf_sample sample; 1373989bbf9SLeo Yan 1383989bbf9SLeo Yan if (event->header.type != PERF_RECORD_COMM || 1393989bbf9SLeo Yan (pid_t)event->comm.pid != getpid() || 1403989bbf9SLeo Yan (pid_t)event->comm.tid != getpid()) 1413989bbf9SLeo Yan goto next_event; 1423989bbf9SLeo Yan 1433989bbf9SLeo Yan if (strcmp(event->comm.comm, comm1) == 0) { 1443989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1453989bbf9SLeo Yan comm1_time = sample.time; 1463989bbf9SLeo Yan } 1473989bbf9SLeo Yan if (strcmp(event->comm.comm, comm2) == 0) { 1483989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1493989bbf9SLeo Yan comm2_time = sample.time; 1503989bbf9SLeo Yan } 1513989bbf9SLeo Yan next_event: 1523989bbf9SLeo Yan perf_mmap__consume(&md->core); 1533989bbf9SLeo Yan } 1543989bbf9SLeo Yan perf_mmap__read_done(&md->core); 1553989bbf9SLeo Yan } 1563989bbf9SLeo Yan 1573989bbf9SLeo Yan if (!comm1_time || !comm2_time) 1583989bbf9SLeo Yan goto out_err; 1593989bbf9SLeo Yan 1603989bbf9SLeo Yan test_time = tsc_to_perf_time(test_tsc, &tc); 1613989bbf9SLeo Yan comm1_tsc = perf_time_to_tsc(comm1_time, &tc); 1623989bbf9SLeo Yan comm2_tsc = perf_time_to_tsc(comm2_time, &tc); 1633989bbf9SLeo Yan 1643989bbf9SLeo Yan pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n", 1653989bbf9SLeo Yan comm1_time, comm1_tsc); 1663989bbf9SLeo Yan pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n", 1673989bbf9SLeo Yan test_time, test_tsc); 1683989bbf9SLeo Yan pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n", 1693989bbf9SLeo Yan comm2_time, comm2_tsc); 1703989bbf9SLeo Yan 1713989bbf9SLeo Yan if (test_time <= comm1_time || 1723989bbf9SLeo Yan test_time >= comm2_time) 1733989bbf9SLeo Yan goto out_err; 1743989bbf9SLeo Yan 1753989bbf9SLeo Yan if (test_tsc <= comm1_tsc || 1763989bbf9SLeo Yan test_tsc >= comm2_tsc) 1773989bbf9SLeo Yan goto out_err; 1783989bbf9SLeo Yan 1793989bbf9SLeo Yan err = 0; 1803989bbf9SLeo Yan 1813989bbf9SLeo Yan out_err: 1823989bbf9SLeo Yan evlist__delete(evlist); 183846580c2SNamhyung Kim perf_cpu_map__put(cpus); 184846580c2SNamhyung Kim perf_thread_map__put(threads); 1853989bbf9SLeo Yan return err; 1863989bbf9SLeo Yan } 187248dd9b5SLeo Yan 188248dd9b5SLeo Yan bool test__tsc_is_supported(void) 189248dd9b5SLeo Yan { 190248dd9b5SLeo Yan /* 191248dd9b5SLeo Yan * Except x86_64/i386 and Arm64, other archs don't support TSC in perf. 192248dd9b5SLeo Yan * Just enable the test for x86_64/i386 and Arm64 archs. 193248dd9b5SLeo Yan */ 194248dd9b5SLeo Yan #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) 195248dd9b5SLeo Yan return true; 196248dd9b5SLeo Yan #else 197248dd9b5SLeo Yan return false; 198248dd9b5SLeo Yan #endif 199248dd9b5SLeo Yan } 200