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" 233989bbf9SLeo Yan 243989bbf9SLeo Yan #define CHECK__(x) { \ 253989bbf9SLeo Yan while ((x) < 0) { \ 263989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 273989bbf9SLeo Yan goto out_err; \ 283989bbf9SLeo Yan } \ 293989bbf9SLeo Yan } 303989bbf9SLeo Yan 313989bbf9SLeo Yan #define CHECK_NOT_NULL__(x) { \ 323989bbf9SLeo Yan while ((x) == NULL) { \ 333989bbf9SLeo Yan pr_debug(#x " failed!\n"); \ 343989bbf9SLeo Yan goto out_err; \ 353989bbf9SLeo Yan } \ 363989bbf9SLeo Yan } 373989bbf9SLeo Yan 383989bbf9SLeo Yan /** 393989bbf9SLeo Yan * test__perf_time_to_tsc - test converting perf time to TSC. 403989bbf9SLeo Yan * 413989bbf9SLeo Yan * This function implements a test that checks that the conversion of perf time 423989bbf9SLeo Yan * to and from TSC is consistent with the order of events. If the test passes 433989bbf9SLeo Yan * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 443989bbf9SLeo Yan * supported then then the test passes but " (not supported)" is printed. 453989bbf9SLeo Yan */ 463989bbf9SLeo Yan int test__perf_time_to_tsc(struct test *test __maybe_unused, int subtest __maybe_unused) 473989bbf9SLeo Yan { 483989bbf9SLeo Yan struct record_opts opts = { 493989bbf9SLeo Yan .mmap_pages = UINT_MAX, 503989bbf9SLeo Yan .user_freq = UINT_MAX, 513989bbf9SLeo Yan .user_interval = ULLONG_MAX, 523989bbf9SLeo Yan .target = { 533989bbf9SLeo Yan .uses_mmap = true, 543989bbf9SLeo Yan }, 553989bbf9SLeo Yan .sample_time = true, 563989bbf9SLeo Yan }; 573989bbf9SLeo Yan struct perf_thread_map *threads = NULL; 583989bbf9SLeo Yan struct perf_cpu_map *cpus = NULL; 593989bbf9SLeo Yan struct evlist *evlist = NULL; 603989bbf9SLeo Yan struct evsel *evsel = NULL; 613989bbf9SLeo Yan int err = -1, ret, i; 623989bbf9SLeo Yan const char *comm1, *comm2; 633989bbf9SLeo Yan struct perf_tsc_conversion tc; 643989bbf9SLeo Yan struct perf_event_mmap_page *pc; 653989bbf9SLeo Yan union perf_event *event; 663989bbf9SLeo Yan u64 test_tsc, comm1_tsc, comm2_tsc; 673989bbf9SLeo Yan u64 test_time, comm1_time = 0, comm2_time = 0; 683989bbf9SLeo Yan struct mmap *md; 693989bbf9SLeo Yan 703989bbf9SLeo Yan threads = thread_map__new(-1, getpid(), UINT_MAX); 713989bbf9SLeo Yan CHECK_NOT_NULL__(threads); 723989bbf9SLeo Yan 733989bbf9SLeo Yan cpus = perf_cpu_map__new(NULL); 743989bbf9SLeo Yan CHECK_NOT_NULL__(cpus); 753989bbf9SLeo Yan 763989bbf9SLeo Yan evlist = evlist__new(); 773989bbf9SLeo Yan CHECK_NOT_NULL__(evlist); 783989bbf9SLeo Yan 793989bbf9SLeo Yan perf_evlist__set_maps(&evlist->core, cpus, threads); 803989bbf9SLeo Yan 813989bbf9SLeo Yan CHECK__(parse_events(evlist, "cycles:u", NULL)); 823989bbf9SLeo Yan 83*78e1bc25SArnaldo Carvalho de Melo evlist__config(evlist, &opts, NULL); 843989bbf9SLeo Yan 853989bbf9SLeo Yan evsel = evlist__first(evlist); 863989bbf9SLeo Yan 873989bbf9SLeo Yan evsel->core.attr.comm = 1; 883989bbf9SLeo Yan evsel->core.attr.disabled = 1; 893989bbf9SLeo Yan evsel->core.attr.enable_on_exec = 0; 903989bbf9SLeo Yan 913989bbf9SLeo Yan CHECK__(evlist__open(evlist)); 923989bbf9SLeo Yan 933989bbf9SLeo Yan CHECK__(evlist__mmap(evlist, UINT_MAX)); 943989bbf9SLeo Yan 953989bbf9SLeo Yan pc = evlist->mmap[0].core.base; 963989bbf9SLeo Yan ret = perf_read_tsc_conversion(pc, &tc); 973989bbf9SLeo Yan if (ret) { 983989bbf9SLeo Yan if (ret == -EOPNOTSUPP) { 993989bbf9SLeo Yan fprintf(stderr, " (not supported)"); 1003989bbf9SLeo Yan return 0; 1013989bbf9SLeo Yan } 1023989bbf9SLeo Yan goto out_err; 1033989bbf9SLeo Yan } 1043989bbf9SLeo Yan 1053989bbf9SLeo Yan evlist__enable(evlist); 1063989bbf9SLeo Yan 1073989bbf9SLeo Yan comm1 = "Test COMM 1"; 1083989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); 1093989bbf9SLeo Yan 1103989bbf9SLeo Yan test_tsc = rdtsc(); 1113989bbf9SLeo Yan 1123989bbf9SLeo Yan comm2 = "Test COMM 2"; 1133989bbf9SLeo Yan CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); 1143989bbf9SLeo Yan 1153989bbf9SLeo Yan evlist__disable(evlist); 1163989bbf9SLeo Yan 1173989bbf9SLeo Yan for (i = 0; i < evlist->core.nr_mmaps; i++) { 1183989bbf9SLeo Yan md = &evlist->mmap[i]; 1193989bbf9SLeo Yan if (perf_mmap__read_init(&md->core) < 0) 1203989bbf9SLeo Yan continue; 1213989bbf9SLeo Yan 1223989bbf9SLeo Yan while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1233989bbf9SLeo Yan struct perf_sample sample; 1243989bbf9SLeo Yan 1253989bbf9SLeo Yan if (event->header.type != PERF_RECORD_COMM || 1263989bbf9SLeo Yan (pid_t)event->comm.pid != getpid() || 1273989bbf9SLeo Yan (pid_t)event->comm.tid != getpid()) 1283989bbf9SLeo Yan goto next_event; 1293989bbf9SLeo Yan 1303989bbf9SLeo Yan if (strcmp(event->comm.comm, comm1) == 0) { 1313989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1323989bbf9SLeo Yan comm1_time = sample.time; 1333989bbf9SLeo Yan } 1343989bbf9SLeo Yan if (strcmp(event->comm.comm, comm2) == 0) { 1353989bbf9SLeo Yan CHECK__(evsel__parse_sample(evsel, event, &sample)); 1363989bbf9SLeo Yan comm2_time = sample.time; 1373989bbf9SLeo Yan } 1383989bbf9SLeo Yan next_event: 1393989bbf9SLeo Yan perf_mmap__consume(&md->core); 1403989bbf9SLeo Yan } 1413989bbf9SLeo Yan perf_mmap__read_done(&md->core); 1423989bbf9SLeo Yan } 1433989bbf9SLeo Yan 1443989bbf9SLeo Yan if (!comm1_time || !comm2_time) 1453989bbf9SLeo Yan goto out_err; 1463989bbf9SLeo Yan 1473989bbf9SLeo Yan test_time = tsc_to_perf_time(test_tsc, &tc); 1483989bbf9SLeo Yan comm1_tsc = perf_time_to_tsc(comm1_time, &tc); 1493989bbf9SLeo Yan comm2_tsc = perf_time_to_tsc(comm2_time, &tc); 1503989bbf9SLeo Yan 1513989bbf9SLeo Yan pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n", 1523989bbf9SLeo Yan comm1_time, comm1_tsc); 1533989bbf9SLeo Yan pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n", 1543989bbf9SLeo Yan test_time, test_tsc); 1553989bbf9SLeo Yan pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n", 1563989bbf9SLeo Yan comm2_time, comm2_tsc); 1573989bbf9SLeo Yan 1583989bbf9SLeo Yan if (test_time <= comm1_time || 1593989bbf9SLeo Yan test_time >= comm2_time) 1603989bbf9SLeo Yan goto out_err; 1613989bbf9SLeo Yan 1623989bbf9SLeo Yan if (test_tsc <= comm1_tsc || 1633989bbf9SLeo Yan test_tsc >= comm2_tsc) 1643989bbf9SLeo Yan goto out_err; 1653989bbf9SLeo Yan 1663989bbf9SLeo Yan err = 0; 1673989bbf9SLeo Yan 1683989bbf9SLeo Yan out_err: 1693989bbf9SLeo Yan evlist__delete(evlist); 1703989bbf9SLeo Yan return err; 1713989bbf9SLeo Yan } 172248dd9b5SLeo Yan 173248dd9b5SLeo Yan bool test__tsc_is_supported(void) 174248dd9b5SLeo Yan { 175248dd9b5SLeo Yan /* 176248dd9b5SLeo Yan * Except x86_64/i386 and Arm64, other archs don't support TSC in perf. 177248dd9b5SLeo Yan * Just enable the test for x86_64/i386 and Arm64 archs. 178248dd9b5SLeo Yan */ 179248dd9b5SLeo Yan #if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) 180248dd9b5SLeo Yan return true; 181248dd9b5SLeo Yan #else 182248dd9b5SLeo Yan return false; 183248dd9b5SLeo Yan #endif 184248dd9b5SLeo Yan } 185