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