1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <unistd.h> 4 #include <inttypes.h> 5 #include <sys/prctl.h> 6 7 #include "parse-events.h" 8 #include "evlist.h" 9 #include "evsel.h" 10 #include "thread_map.h" 11 #include "cpumap.h" 12 #include "tests.h" 13 14 #include "../arch/x86/util/tsc.h" 15 16 #define CHECK__(x) { \ 17 while ((x) < 0) { \ 18 pr_debug(#x " failed!\n"); \ 19 goto out_err; \ 20 } \ 21 } 22 23 #define CHECK_NOT_NULL__(x) { \ 24 while ((x) == NULL) { \ 25 pr_debug(#x " failed!\n"); \ 26 goto out_err; \ 27 } \ 28 } 29 30 static u64 rdtsc(void) 31 { 32 unsigned int low, high; 33 34 asm volatile("rdtsc" : "=a" (low), "=d" (high)); 35 36 return low | ((u64)high) << 32; 37 } 38 39 /** 40 * test__perf_time_to_tsc - test converting perf time to TSC. 41 * 42 * This function implements a test that checks that the conversion of perf time 43 * to and from TSC is consistent with the order of events. If the test passes 44 * %0 is returned, otherwise %-1 is returned. If TSC conversion is not 45 * supported then then the test passes but " (not supported)" is printed. 46 */ 47 int test__perf_time_to_tsc(void) 48 { 49 struct perf_record_opts opts = { 50 .mmap_pages = UINT_MAX, 51 .user_freq = UINT_MAX, 52 .user_interval = ULLONG_MAX, 53 .freq = 4000, 54 .target = { 55 .uses_mmap = true, 56 }, 57 .sample_time = true, 58 }; 59 struct thread_map *threads = NULL; 60 struct cpu_map *cpus = NULL; 61 struct perf_evlist *evlist = NULL; 62 struct perf_evsel *evsel = NULL; 63 int err = -1, ret, i; 64 const char *comm1, *comm2; 65 struct perf_tsc_conversion tc; 66 struct perf_event_mmap_page *pc; 67 union perf_event *event; 68 u64 test_tsc, comm1_tsc, comm2_tsc; 69 u64 test_time, comm1_time = 0, comm2_time = 0; 70 71 threads = thread_map__new(-1, getpid(), UINT_MAX); 72 CHECK_NOT_NULL__(threads); 73 74 cpus = cpu_map__new(NULL); 75 CHECK_NOT_NULL__(cpus); 76 77 evlist = perf_evlist__new(); 78 CHECK_NOT_NULL__(evlist); 79 80 perf_evlist__set_maps(evlist, cpus, threads); 81 82 CHECK__(parse_events(evlist, "cycles:u")); 83 84 perf_evlist__config(evlist, &opts); 85 86 evsel = perf_evlist__first(evlist); 87 88 evsel->attr.comm = 1; 89 evsel->attr.disabled = 1; 90 evsel->attr.enable_on_exec = 0; 91 92 CHECK__(perf_evlist__open(evlist)); 93 94 CHECK__(perf_evlist__mmap(evlist, UINT_MAX, false)); 95 96 pc = evlist->mmap[0].base; 97 ret = perf_read_tsc_conversion(pc, &tc); 98 if (ret) { 99 if (ret == -EOPNOTSUPP) { 100 fprintf(stderr, " (not supported)"); 101 return 0; 102 } 103 goto out_err; 104 } 105 106 perf_evlist__enable(evlist); 107 108 comm1 = "Test COMM 1"; 109 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm1, 0, 0, 0)); 110 111 test_tsc = rdtsc(); 112 113 comm2 = "Test COMM 2"; 114 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm2, 0, 0, 0)); 115 116 perf_evlist__disable(evlist); 117 118 for (i = 0; i < evlist->nr_mmaps; i++) { 119 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { 120 struct perf_sample sample; 121 122 if (event->header.type != PERF_RECORD_COMM || 123 (pid_t)event->comm.pid != getpid() || 124 (pid_t)event->comm.tid != getpid()) 125 goto next_event; 126 127 if (strcmp(event->comm.comm, comm1) == 0) { 128 CHECK__(perf_evsel__parse_sample(evsel, event, 129 &sample)); 130 comm1_time = sample.time; 131 } 132 if (strcmp(event->comm.comm, comm2) == 0) { 133 CHECK__(perf_evsel__parse_sample(evsel, event, 134 &sample)); 135 comm2_time = sample.time; 136 } 137 next_event: 138 perf_evlist__mmap_consume(evlist, i); 139 } 140 } 141 142 if (!comm1_time || !comm2_time) 143 goto out_err; 144 145 test_time = tsc_to_perf_time(test_tsc, &tc); 146 comm1_tsc = perf_time_to_tsc(comm1_time, &tc); 147 comm2_tsc = perf_time_to_tsc(comm2_time, &tc); 148 149 pr_debug("1st event perf time %"PRIu64" tsc %"PRIu64"\n", 150 comm1_time, comm1_tsc); 151 pr_debug("rdtsc time %"PRIu64" tsc %"PRIu64"\n", 152 test_time, test_tsc); 153 pr_debug("2nd event perf time %"PRIu64" tsc %"PRIu64"\n", 154 comm2_time, comm2_tsc); 155 156 if (test_time <= comm1_time || 157 test_time >= comm2_time) 158 goto out_err; 159 160 if (test_tsc <= comm1_tsc || 161 test_tsc >= comm2_tsc) 162 goto out_err; 163 164 err = 0; 165 166 out_err: 167 if (evlist) { 168 perf_evlist__disable(evlist); 169 perf_evlist__munmap(evlist); 170 perf_evlist__close(evlist); 171 perf_evlist__delete(evlist); 172 } 173 if (cpus) 174 cpu_map__delete(cpus); 175 if (threads) 176 thread_map__delete(threads); 177 178 return err; 179 } 180