1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdarg.h> 3 #include <stdio.h> 4 #include <linux/perf_event.h> 5 #include <perf/cpumap.h> 6 #include <perf/threadmap.h> 7 #include <perf/evsel.h> 8 #include <internal/tests.h> 9 #include "tests.h" 10 11 static int libperf_print(enum libperf_print_level level, 12 const char *fmt, va_list ap) 13 { 14 return vfprintf(stderr, fmt, ap); 15 } 16 17 static int test_stat_cpu(void) 18 { 19 struct perf_cpu_map *cpus; 20 struct perf_evsel *evsel; 21 struct perf_event_attr attr = { 22 .type = PERF_TYPE_SOFTWARE, 23 .config = PERF_COUNT_SW_CPU_CLOCK, 24 }; 25 int err, idx; 26 27 cpus = perf_cpu_map__new(NULL); 28 __T("failed to create cpus", cpus); 29 30 evsel = perf_evsel__new(&attr); 31 __T("failed to create evsel", evsel); 32 33 err = perf_evsel__open(evsel, cpus, NULL); 34 __T("failed to open evsel", err == 0); 35 36 for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) { 37 struct perf_counts_values counts = { .val = 0 }; 38 39 perf_evsel__read(evsel, idx, 0, &counts); 40 __T("failed to read value for evsel", counts.val != 0); 41 } 42 43 perf_evsel__close(evsel); 44 perf_evsel__delete(evsel); 45 46 perf_cpu_map__put(cpus); 47 return 0; 48 } 49 50 static int test_stat_thread(void) 51 { 52 struct perf_counts_values counts = { .val = 0 }; 53 struct perf_thread_map *threads; 54 struct perf_evsel *evsel; 55 struct perf_event_attr attr = { 56 .type = PERF_TYPE_SOFTWARE, 57 .config = PERF_COUNT_SW_TASK_CLOCK, 58 }; 59 int err; 60 61 threads = perf_thread_map__new_dummy(); 62 __T("failed to create threads", threads); 63 64 perf_thread_map__set_pid(threads, 0, 0); 65 66 evsel = perf_evsel__new(&attr); 67 __T("failed to create evsel", evsel); 68 69 err = perf_evsel__open(evsel, NULL, threads); 70 __T("failed to open evsel", err == 0); 71 72 perf_evsel__read(evsel, 0, 0, &counts); 73 __T("failed to read value for evsel", counts.val != 0); 74 75 perf_evsel__close(evsel); 76 perf_evsel__delete(evsel); 77 78 perf_thread_map__put(threads); 79 return 0; 80 } 81 82 static int test_stat_thread_enable(void) 83 { 84 struct perf_counts_values counts = { .val = 0 }; 85 struct perf_thread_map *threads; 86 struct perf_evsel *evsel; 87 struct perf_event_attr attr = { 88 .type = PERF_TYPE_SOFTWARE, 89 .config = PERF_COUNT_SW_TASK_CLOCK, 90 .disabled = 1, 91 }; 92 int err; 93 94 threads = perf_thread_map__new_dummy(); 95 __T("failed to create threads", threads); 96 97 perf_thread_map__set_pid(threads, 0, 0); 98 99 evsel = perf_evsel__new(&attr); 100 __T("failed to create evsel", evsel); 101 102 err = perf_evsel__open(evsel, NULL, threads); 103 __T("failed to open evsel", err == 0); 104 105 perf_evsel__read(evsel, 0, 0, &counts); 106 __T("failed to read value for evsel", counts.val == 0); 107 108 err = perf_evsel__enable(evsel); 109 __T("failed to enable evsel", err == 0); 110 111 perf_evsel__read(evsel, 0, 0, &counts); 112 __T("failed to read value for evsel", counts.val != 0); 113 114 err = perf_evsel__disable(evsel); 115 __T("failed to enable evsel", err == 0); 116 117 perf_evsel__close(evsel); 118 perf_evsel__delete(evsel); 119 120 perf_thread_map__put(threads); 121 return 0; 122 } 123 124 static int test_stat_user_read(int event) 125 { 126 struct perf_counts_values counts = { .val = 0 }; 127 struct perf_thread_map *threads; 128 struct perf_evsel *evsel; 129 struct perf_event_mmap_page *pc; 130 struct perf_event_attr attr = { 131 .type = PERF_TYPE_HARDWARE, 132 .config = event, 133 #ifdef __aarch64__ 134 .config1 = 0x2, /* Request user access */ 135 #endif 136 }; 137 int err, i; 138 139 threads = perf_thread_map__new_dummy(); 140 __T("failed to create threads", threads); 141 142 perf_thread_map__set_pid(threads, 0, 0); 143 144 evsel = perf_evsel__new(&attr); 145 __T("failed to create evsel", evsel); 146 147 err = perf_evsel__open(evsel, NULL, threads); 148 __T("failed to open evsel", err == 0); 149 150 err = perf_evsel__mmap(evsel, 0); 151 __T("failed to mmap evsel", err == 0); 152 153 pc = perf_evsel__mmap_base(evsel, 0, 0); 154 __T("failed to get mmapped address", pc); 155 156 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) 157 __T("userspace counter access not supported", pc->cap_user_rdpmc); 158 __T("userspace counter access not enabled", pc->index); 159 __T("userspace counter width not set", pc->pmc_width >= 32); 160 #endif 161 162 perf_evsel__read(evsel, 0, 0, &counts); 163 __T("failed to read value for evsel", counts.val != 0); 164 165 for (i = 0; i < 5; i++) { 166 volatile int count = 0x10000 << i; 167 __u64 start, end, last = 0; 168 169 __T_VERBOSE("\tloop = %u, ", count); 170 171 perf_evsel__read(evsel, 0, 0, &counts); 172 start = counts.val; 173 174 while (count--) ; 175 176 perf_evsel__read(evsel, 0, 0, &counts); 177 end = counts.val; 178 179 __T("invalid counter data", (end - start) > last); 180 last = end - start; 181 __T_VERBOSE("count = %llu\n", end - start); 182 } 183 184 perf_evsel__munmap(evsel); 185 perf_evsel__close(evsel); 186 perf_evsel__delete(evsel); 187 188 perf_thread_map__put(threads); 189 return 0; 190 } 191 192 int test_evsel(int argc, char **argv) 193 { 194 __T_START; 195 196 libperf_init(libperf_print); 197 198 test_stat_cpu(); 199 test_stat_thread(); 200 test_stat_thread_enable(); 201 test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS); 202 test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES); 203 204 __T_END; 205 return tests_failed == 0 ? 0 : -1; 206 } 207