evsel.c (2d8ad8719591fa803b0d589ed057fa46f49b7155) | evsel.c (a91e5431d54f5359fccb5ec2512f252eb217707e) |
---|---|
1/* 2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> 3 * 4 * Parts came from builtin-{top,stat,record}.c, see those files for further 5 * copyright notes. 6 * 7 * Released under the GPL v2. (and only v2, not any later version) 8 */ 9 |
|
1#include "evsel.h" | 10#include "evsel.h" |
2#include "../perf.h" | 11#include "evlist.h" |
3#include "util.h" 4#include "cpumap.h" | 12#include "util.h" 13#include "cpumap.h" |
5#include "thread.h" | 14#include "thread_map.h" |
6 7#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 8 | 15 16#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 17 |
18void perf_evsel__init(struct perf_evsel *evsel, 19 struct perf_event_attr *attr, int idx) 20{ 21 evsel->idx = idx; 22 evsel->attr = *attr; 23 INIT_LIST_HEAD(&evsel->node); 24} 25 |
|
9struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 10{ 11 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 12 | 26struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 27{ 28 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 29 |
13 if (evsel != NULL) { 14 evsel->idx = idx; 15 evsel->attr = *attr; 16 INIT_LIST_HEAD(&evsel->node); 17 } | 30 if (evsel != NULL) 31 perf_evsel__init(evsel, attr, idx); |
18 19 return evsel; 20} 21 22int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 23{ 24 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 25 return evsel->fd != NULL ? 0 : -ENOMEM; 26} 27 | 32 33 return evsel; 34} 35 36int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 37{ 38 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 39 return evsel->fd != NULL ? 0 : -ENOMEM; 40} 41 |
42int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 43{ 44 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 45 if (evsel->sample_id == NULL) 46 return -ENOMEM; 47 48 evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); 49 if (evsel->id == NULL) { 50 xyarray__delete(evsel->sample_id); 51 evsel->sample_id = NULL; 52 return -ENOMEM; 53 } 54 55 return 0; 56} 57 |
|
28int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 29{ 30 evsel->counts = zalloc((sizeof(*evsel->counts) + 31 (ncpus * sizeof(struct perf_counts_values)))); 32 return evsel->counts != NULL ? 0 : -ENOMEM; 33} 34 35void perf_evsel__free_fd(struct perf_evsel *evsel) 36{ 37 xyarray__delete(evsel->fd); 38 evsel->fd = NULL; 39} 40 | 58int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 59{ 60 evsel->counts = zalloc((sizeof(*evsel->counts) + 61 (ncpus * sizeof(struct perf_counts_values)))); 62 return evsel->counts != NULL ? 0 : -ENOMEM; 63} 64 65void perf_evsel__free_fd(struct perf_evsel *evsel) 66{ 67 xyarray__delete(evsel->fd); 68 evsel->fd = NULL; 69} 70 |
71void perf_evsel__free_id(struct perf_evsel *evsel) 72{ 73 xyarray__delete(evsel->sample_id); 74 evsel->sample_id = NULL; 75 free(evsel->id); 76 evsel->id = NULL; 77} 78 |
|
41void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 42{ 43 int cpu, thread; 44 45 for (cpu = 0; cpu < ncpus; cpu++) 46 for (thread = 0; thread < nthreads; ++thread) { 47 close(FD(evsel, cpu, thread)); 48 FD(evsel, cpu, thread) = -1; 49 } 50} 51 | 79void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 80{ 81 int cpu, thread; 82 83 for (cpu = 0; cpu < ncpus; cpu++) 84 for (thread = 0; thread < nthreads; ++thread) { 85 close(FD(evsel, cpu, thread)); 86 FD(evsel, cpu, thread) = -1; 87 } 88} 89 |
52void perf_evsel__delete(struct perf_evsel *evsel) | 90void perf_evsel__exit(struct perf_evsel *evsel) |
53{ 54 assert(list_empty(&evsel->node)); 55 xyarray__delete(evsel->fd); | 91{ 92 assert(list_empty(&evsel->node)); 93 xyarray__delete(evsel->fd); |
94 xyarray__delete(evsel->sample_id); 95 free(evsel->id); 96} 97 98void perf_evsel__delete(struct perf_evsel *evsel) 99{ 100 perf_evsel__exit(evsel); 101 close_cgroup(evsel->cgrp); 102 free(evsel->name); |
|
56 free(evsel); 57} 58 59int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 60 int cpu, int thread, bool scale) 61{ 62 struct perf_counts_values count; 63 size_t nv = scale ? 3 : 1; --- 21 unchanged lines hidden (view full) --- 85 86int __perf_evsel__read(struct perf_evsel *evsel, 87 int ncpus, int nthreads, bool scale) 88{ 89 size_t nv = scale ? 3 : 1; 90 int cpu, thread; 91 struct perf_counts_values *aggr = &evsel->counts->aggr, count; 92 | 103 free(evsel); 104} 105 106int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 107 int cpu, int thread, bool scale) 108{ 109 struct perf_counts_values count; 110 size_t nv = scale ? 3 : 1; --- 21 unchanged lines hidden (view full) --- 132 133int __perf_evsel__read(struct perf_evsel *evsel, 134 int ncpus, int nthreads, bool scale) 135{ 136 size_t nv = scale ? 3 : 1; 137 int cpu, thread; 138 struct perf_counts_values *aggr = &evsel->counts->aggr, count; 139 |
93 aggr->val = 0; | 140 aggr->val = aggr->ena = aggr->run = 0; |
94 95 for (cpu = 0; cpu < ncpus; cpu++) { 96 for (thread = 0; thread < nthreads; thread++) { 97 if (FD(evsel, cpu, thread) < 0) 98 continue; 99 100 if (readn(FD(evsel, cpu, thread), 101 &count, nv * sizeof(u64)) < 0) --- 21 unchanged lines hidden (view full) --- 123 } 124 } else 125 aggr->ena = aggr->run = 0; 126 127 return 0; 128} 129 130static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, | 141 142 for (cpu = 0; cpu < ncpus; cpu++) { 143 for (thread = 0; thread < nthreads; thread++) { 144 if (FD(evsel, cpu, thread) < 0) 145 continue; 146 147 if (readn(FD(evsel, cpu, thread), 148 &count, nv * sizeof(u64)) < 0) --- 21 unchanged lines hidden (view full) --- 170 } 171 } else 172 aggr->ena = aggr->run = 0; 173 174 return 0; 175} 176 177static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, |
131 struct thread_map *threads) | 178 struct thread_map *threads, bool group, bool inherit) |
132{ 133 int cpu, thread; | 179{ 180 int cpu, thread; |
181 unsigned long flags = 0; 182 int pid = -1; |
|
134 135 if (evsel->fd == NULL && 136 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 137 return -1; 138 | 183 184 if (evsel->fd == NULL && 185 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 186 return -1; 187 |
188 if (evsel->cgrp) { 189 flags = PERF_FLAG_PID_CGROUP; 190 pid = evsel->cgrp->fd; 191 } 192 |
|
139 for (cpu = 0; cpu < cpus->nr; cpu++) { | 193 for (cpu = 0; cpu < cpus->nr; cpu++) { |
194 int group_fd = -1; 195 /* 196 * Don't allow mmap() of inherited per-task counters. This 197 * would create a performance issue due to all children writing 198 * to the same buffer. 199 * 200 * FIXME: 201 * Proper fix is not to pass 'inherit' to perf_evsel__open*, 202 * but a 'flags' parameter, with 'group' folded there as well, 203 * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if 204 * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is 205 * set. Lets go for the minimal fix first tho. 206 */ 207 evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit; 208 |
|
140 for (thread = 0; thread < threads->nr; thread++) { | 209 for (thread = 0; thread < threads->nr; thread++) { |
210 211 if (!evsel->cgrp) 212 pid = threads->map[thread]; 213 |
|
141 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, | 214 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, |
142 threads->map[thread], 143 cpus->map[cpu], -1, 0); | 215 pid, 216 cpus->map[cpu], 217 group_fd, flags); |
144 if (FD(evsel, cpu, thread) < 0) 145 goto out_close; | 218 if (FD(evsel, cpu, thread) < 0) 219 goto out_close; |
220 221 if (group && group_fd == -1) 222 group_fd = FD(evsel, cpu, thread); |
|
146 } 147 } 148 149 return 0; 150 151out_close: 152 do { 153 while (--thread >= 0) { --- 16 unchanged lines hidden (view full) --- 170static struct { 171 struct thread_map map; 172 int threads[1]; 173} empty_thread_map = { 174 .map.nr = 1, 175 .threads = { -1, }, 176}; 177 | 223 } 224 } 225 226 return 0; 227 228out_close: 229 do { 230 while (--thread >= 0) { --- 16 unchanged lines hidden (view full) --- 247static struct { 248 struct thread_map map; 249 int threads[1]; 250} empty_thread_map = { 251 .map.nr = 1, 252 .threads = { -1, }, 253}; 254 |
178int perf_evsel__open(struct perf_evsel *evsel, 179 struct cpu_map *cpus, struct thread_map *threads) | 255int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 256 struct thread_map *threads, bool group, bool inherit) |
180{ | 257{ |
181 | |
182 if (cpus == NULL) { 183 /* Work around old compiler warnings about strict aliasing */ 184 cpus = &empty_cpu_map.map; 185 } 186 187 if (threads == NULL) 188 threads = &empty_thread_map.map; 189 | 258 if (cpus == NULL) { 259 /* Work around old compiler warnings about strict aliasing */ 260 cpus = &empty_cpu_map.map; 261 } 262 263 if (threads == NULL) 264 threads = &empty_thread_map.map; 265 |
190 return __perf_evsel__open(evsel, cpus, threads); | 266 return __perf_evsel__open(evsel, cpus, threads, group, inherit); |
191} 192 | 267} 268 |
193int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) | 269int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 270 struct cpu_map *cpus, bool group, bool inherit) |
194{ | 271{ |
195 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); | 272 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit); |
196} 197 | 273} 274 |
198int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) | 275int perf_evsel__open_per_thread(struct perf_evsel *evsel, 276 struct thread_map *threads, bool group, bool inherit) |
199{ | 277{ |
200 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); | 278 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); |
201} | 279} |
280 281static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 282 struct perf_sample *sample) 283{ 284 const u64 *array = event->sample.array; 285 286 array += ((event->header.size - 287 sizeof(event->header)) / sizeof(u64)) - 1; 288 289 if (type & PERF_SAMPLE_CPU) { 290 u32 *p = (u32 *)array; 291 sample->cpu = *p; 292 array--; 293 } 294 295 if (type & PERF_SAMPLE_STREAM_ID) { 296 sample->stream_id = *array; 297 array--; 298 } 299 300 if (type & PERF_SAMPLE_ID) { 301 sample->id = *array; 302 array--; 303 } 304 305 if (type & PERF_SAMPLE_TIME) { 306 sample->time = *array; 307 array--; 308 } 309 310 if (type & PERF_SAMPLE_TID) { 311 u32 *p = (u32 *)array; 312 sample->pid = p[0]; 313 sample->tid = p[1]; 314 } 315 316 return 0; 317} 318 319int perf_event__parse_sample(const union perf_event *event, u64 type, 320 bool sample_id_all, struct perf_sample *data) 321{ 322 const u64 *array; 323 324 data->cpu = data->pid = data->tid = -1; 325 data->stream_id = data->id = data->time = -1ULL; 326 327 if (event->header.type != PERF_RECORD_SAMPLE) { 328 if (!sample_id_all) 329 return 0; 330 return perf_event__parse_id_sample(event, type, data); 331 } 332 333 array = event->sample.array; 334 335 if (type & PERF_SAMPLE_IP) { 336 data->ip = event->ip.ip; 337 array++; 338 } 339 340 if (type & PERF_SAMPLE_TID) { 341 u32 *p = (u32 *)array; 342 data->pid = p[0]; 343 data->tid = p[1]; 344 array++; 345 } 346 347 if (type & PERF_SAMPLE_TIME) { 348 data->time = *array; 349 array++; 350 } 351 352 if (type & PERF_SAMPLE_ADDR) { 353 data->addr = *array; 354 array++; 355 } 356 357 data->id = -1ULL; 358 if (type & PERF_SAMPLE_ID) { 359 data->id = *array; 360 array++; 361 } 362 363 if (type & PERF_SAMPLE_STREAM_ID) { 364 data->stream_id = *array; 365 array++; 366 } 367 368 if (type & PERF_SAMPLE_CPU) { 369 u32 *p = (u32 *)array; 370 data->cpu = *p; 371 array++; 372 } 373 374 if (type & PERF_SAMPLE_PERIOD) { 375 data->period = *array; 376 array++; 377 } 378 379 if (type & PERF_SAMPLE_READ) { 380 fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); 381 return -1; 382 } 383 384 if (type & PERF_SAMPLE_CALLCHAIN) { 385 data->callchain = (struct ip_callchain *)array; 386 array += 1 + data->callchain->nr; 387 } 388 389 if (type & PERF_SAMPLE_RAW) { 390 u32 *p = (u32 *)array; 391 data->raw_size = *p; 392 p++; 393 data->raw_data = p; 394 } 395 396 return 0; 397} |
|