1 #include <linux/compiler.h> 2 #include <errno.h> 3 #include <inttypes.h> 4 #include <string.h> 5 #include <sys/wait.h> 6 #include "tests.h" 7 #include "evlist.h" 8 #include "evsel.h" 9 #include "util.h" 10 #include "debug.h" 11 #include "thread_map.h" 12 #include "target.h" 13 14 static int attach__enable_on_exec(struct perf_evlist *evlist) 15 { 16 struct perf_evsel *evsel = perf_evlist__last(evlist); 17 struct target target = { 18 .uid = UINT_MAX, 19 }; 20 const char *argv[] = { "true", NULL, }; 21 char sbuf[STRERR_BUFSIZE]; 22 int err; 23 24 pr_debug("attaching to spawned child, enable on exec\n"); 25 26 err = perf_evlist__create_maps(evlist, &target); 27 if (err < 0) { 28 pr_debug("Not enough memory to create thread/cpu maps\n"); 29 return err; 30 } 31 32 err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL); 33 if (err < 0) { 34 pr_debug("Couldn't run the workload!\n"); 35 return err; 36 } 37 38 evsel->attr.enable_on_exec = 1; 39 40 err = perf_evlist__open(evlist); 41 if (err < 0) { 42 pr_debug("perf_evlist__open: %s\n", 43 str_error_r(errno, sbuf, sizeof(sbuf))); 44 return err; 45 } 46 47 return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; 48 } 49 50 static int detach__enable_on_exec(struct perf_evlist *evlist) 51 { 52 waitpid(evlist->workload.pid, NULL, 0); 53 return 0; 54 } 55 56 static int attach__current_disabled(struct perf_evlist *evlist) 57 { 58 struct perf_evsel *evsel = perf_evlist__last(evlist); 59 struct thread_map *threads; 60 int err; 61 62 pr_debug("attaching to current thread as disabled\n"); 63 64 threads = thread_map__new(-1, getpid(), UINT_MAX); 65 if (threads == NULL) { 66 pr_debug("thread_map__new\n"); 67 return -1; 68 } 69 70 evsel->attr.disabled = 1; 71 72 err = perf_evsel__open_per_thread(evsel, threads); 73 if (err) { 74 pr_debug("Failed to open event cpu-clock:u\n"); 75 return err; 76 } 77 78 thread_map__put(threads); 79 return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; 80 } 81 82 static int attach__current_enabled(struct perf_evlist *evlist) 83 { 84 struct perf_evsel *evsel = perf_evlist__last(evlist); 85 struct thread_map *threads; 86 int err; 87 88 pr_debug("attaching to current thread as enabled\n"); 89 90 threads = thread_map__new(-1, getpid(), UINT_MAX); 91 if (threads == NULL) { 92 pr_debug("failed to call thread_map__new\n"); 93 return -1; 94 } 95 96 err = perf_evsel__open_per_thread(evsel, threads); 97 98 thread_map__put(threads); 99 return err == 0 ? TEST_OK : TEST_FAIL; 100 } 101 102 static int detach__disable(struct perf_evlist *evlist) 103 { 104 struct perf_evsel *evsel = perf_evlist__last(evlist); 105 106 return perf_evsel__enable(evsel); 107 } 108 109 static int attach__cpu_disabled(struct perf_evlist *evlist) 110 { 111 struct perf_evsel *evsel = perf_evlist__last(evlist); 112 struct cpu_map *cpus; 113 int err; 114 115 pr_debug("attaching to CPU 0 as enabled\n"); 116 117 cpus = cpu_map__new("0"); 118 if (cpus == NULL) { 119 pr_debug("failed to call cpu_map__new\n"); 120 return -1; 121 } 122 123 evsel->attr.disabled = 1; 124 125 err = perf_evsel__open_per_cpu(evsel, cpus); 126 if (err) { 127 if (err == -EACCES) 128 return TEST_SKIP; 129 130 pr_debug("Failed to open event cpu-clock:u\n"); 131 return err; 132 } 133 134 cpu_map__put(cpus); 135 return perf_evsel__enable(evsel); 136 } 137 138 static int attach__cpu_enabled(struct perf_evlist *evlist) 139 { 140 struct perf_evsel *evsel = perf_evlist__last(evlist); 141 struct cpu_map *cpus; 142 int err; 143 144 pr_debug("attaching to CPU 0 as enabled\n"); 145 146 cpus = cpu_map__new("0"); 147 if (cpus == NULL) { 148 pr_debug("failed to call cpu_map__new\n"); 149 return -1; 150 } 151 152 err = perf_evsel__open_per_cpu(evsel, cpus); 153 if (err == -EACCES) 154 return TEST_SKIP; 155 156 cpu_map__put(cpus); 157 return err ? TEST_FAIL : TEST_OK; 158 } 159 160 static int test_times(int (attach)(struct perf_evlist *), 161 int (detach)(struct perf_evlist *)) 162 { 163 struct perf_counts_values count; 164 struct perf_evlist *evlist = NULL; 165 struct perf_evsel *evsel; 166 int err = -1, i; 167 168 evlist = perf_evlist__new(); 169 if (!evlist) { 170 pr_debug("failed to create event list\n"); 171 goto out_err; 172 } 173 174 err = parse_events(evlist, "cpu-clock:u", NULL); 175 if (err) { 176 pr_debug("failed to parse event cpu-clock:u\n"); 177 goto out_err; 178 } 179 180 evsel = perf_evlist__last(evlist); 181 evsel->attr.read_format |= 182 PERF_FORMAT_TOTAL_TIME_ENABLED | 183 PERF_FORMAT_TOTAL_TIME_RUNNING; 184 185 err = attach(evlist); 186 if (err == TEST_SKIP) { 187 pr_debug(" SKIP : not enough rights\n"); 188 return err; 189 } 190 191 TEST_ASSERT_VAL("failed to attach", !err); 192 193 for (i = 0; i < 100000000; i++) { } 194 195 TEST_ASSERT_VAL("failed to detach", !detach(evlist)); 196 197 perf_evsel__read(evsel, 0, 0, &count); 198 199 err = !(count.ena == count.run); 200 201 pr_debug(" %s: ena %" PRIu64", run %" PRIu64"\n", 202 !err ? "OK " : "FAILED", 203 count.ena, count.run); 204 205 out_err: 206 perf_evlist__delete(evlist); 207 return !err ? TEST_OK : TEST_FAIL; 208 } 209 210 /* 211 * This test creates software event 'cpu-clock' 212 * attaches it in several ways (explained below) 213 * and checks that enabled and running times 214 * match. 215 */ 216 int test__event_times(int subtest __maybe_unused) 217 { 218 int err, ret = 0; 219 220 #define _T(attach, detach) \ 221 err = test_times(attach, detach); \ 222 if (err && (ret == TEST_OK || ret == TEST_SKIP)) \ 223 ret = err; 224 225 /* attach on newly spawned process after exec */ 226 _T(attach__enable_on_exec, detach__enable_on_exec) 227 /* attach on current process as enabled */ 228 _T(attach__current_enabled, detach__disable) 229 /* attach on current process as disabled */ 230 _T(attach__current_disabled, detach__disable) 231 /* attach on cpu as disabled */ 232 _T(attach__cpu_disabled, detach__disable) 233 /* attach on cpu as enabled */ 234 _T(attach__cpu_enabled, detach__disable) 235 236 #undef _T 237 return ret; 238 } 239