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 10 #include <byteswap.h> 11 #include "asm/bug.h" 12 #include "evsel.h" 13 #include "evlist.h" 14 #include "util.h" 15 #include "cpumap.h" 16 #include "thread_map.h" 17 #include "target.h" 18 #include "../../../include/linux/hw_breakpoint.h" 19 20 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 21 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) 22 23 static int __perf_evsel__sample_size(u64 sample_type) 24 { 25 u64 mask = sample_type & PERF_SAMPLE_MASK; 26 int size = 0; 27 int i; 28 29 for (i = 0; i < 64; i++) { 30 if (mask & (1ULL << i)) 31 size++; 32 } 33 34 size *= sizeof(u64); 35 36 return size; 37 } 38 39 void hists__init(struct hists *hists) 40 { 41 memset(hists, 0, sizeof(*hists)); 42 hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT; 43 hists->entries_in = &hists->entries_in_array[0]; 44 hists->entries_collapsed = RB_ROOT; 45 hists->entries = RB_ROOT; 46 pthread_mutex_init(&hists->lock, NULL); 47 } 48 49 void perf_evsel__init(struct perf_evsel *evsel, 50 struct perf_event_attr *attr, int idx) 51 { 52 evsel->idx = idx; 53 evsel->attr = *attr; 54 INIT_LIST_HEAD(&evsel->node); 55 hists__init(&evsel->hists); 56 evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); 57 } 58 59 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) 60 { 61 struct perf_evsel *evsel = zalloc(sizeof(*evsel)); 62 63 if (evsel != NULL) 64 perf_evsel__init(evsel, attr, idx); 65 66 return evsel; 67 } 68 69 static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { 70 "cycles", 71 "instructions", 72 "cache-references", 73 "cache-misses", 74 "branches", 75 "branch-misses", 76 "bus-cycles", 77 "stalled-cycles-frontend", 78 "stalled-cycles-backend", 79 "ref-cycles", 80 }; 81 82 static const char *__perf_evsel__hw_name(u64 config) 83 { 84 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config]) 85 return perf_evsel__hw_names[config]; 86 87 return "unknown-hardware"; 88 } 89 90 static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) 91 { 92 int colon = 0, r = 0; 93 struct perf_event_attr *attr = &evsel->attr; 94 bool exclude_guest_default = false; 95 96 #define MOD_PRINT(context, mod) do { \ 97 if (!attr->exclude_##context) { \ 98 if (!colon) colon = ++r; \ 99 r += scnprintf(bf + r, size - r, "%c", mod); \ 100 } } while(0) 101 102 if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) { 103 MOD_PRINT(kernel, 'k'); 104 MOD_PRINT(user, 'u'); 105 MOD_PRINT(hv, 'h'); 106 exclude_guest_default = true; 107 } 108 109 if (attr->precise_ip) { 110 if (!colon) 111 colon = ++r; 112 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp"); 113 exclude_guest_default = true; 114 } 115 116 if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) { 117 MOD_PRINT(host, 'H'); 118 MOD_PRINT(guest, 'G'); 119 } 120 #undef MOD_PRINT 121 if (colon) 122 bf[colon - 1] = ':'; 123 return r; 124 } 125 126 static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) 127 { 128 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); 129 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); 130 } 131 132 static const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX] = { 133 "cpu-clock", 134 "task-clock", 135 "page-faults", 136 "context-switches", 137 "CPU-migrations", 138 "minor-faults", 139 "major-faults", 140 "alignment-faults", 141 "emulation-faults", 142 }; 143 144 static const char *__perf_evsel__sw_name(u64 config) 145 { 146 if (config < PERF_COUNT_SW_MAX && perf_evsel__sw_names[config]) 147 return perf_evsel__sw_names[config]; 148 return "unknown-software"; 149 } 150 151 static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) 152 { 153 int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); 154 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); 155 } 156 157 static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) 158 { 159 int r; 160 161 r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr); 162 163 if (type & HW_BREAKPOINT_R) 164 r += scnprintf(bf + r, size - r, "r"); 165 166 if (type & HW_BREAKPOINT_W) 167 r += scnprintf(bf + r, size - r, "w"); 168 169 if (type & HW_BREAKPOINT_X) 170 r += scnprintf(bf + r, size - r, "x"); 171 172 return r; 173 } 174 175 static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size) 176 { 177 struct perf_event_attr *attr = &evsel->attr; 178 int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type); 179 return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); 180 } 181 182 const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] 183 [PERF_EVSEL__MAX_ALIASES] = { 184 { "L1-dcache", "l1-d", "l1d", "L1-data", }, 185 { "L1-icache", "l1-i", "l1i", "L1-instruction", }, 186 { "LLC", "L2", }, 187 { "dTLB", "d-tlb", "Data-TLB", }, 188 { "iTLB", "i-tlb", "Instruction-TLB", }, 189 { "branch", "branches", "bpu", "btb", "bpc", }, 190 { "node", }, 191 }; 192 193 const char *perf_evsel__hw_cache_op[PERF_COUNT_HW_CACHE_OP_MAX] 194 [PERF_EVSEL__MAX_ALIASES] = { 195 { "load", "loads", "read", }, 196 { "store", "stores", "write", }, 197 { "prefetch", "prefetches", "speculative-read", "speculative-load", }, 198 }; 199 200 const char *perf_evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] 201 [PERF_EVSEL__MAX_ALIASES] = { 202 { "refs", "Reference", "ops", "access", }, 203 { "misses", "miss", }, 204 }; 205 206 #define C(x) PERF_COUNT_HW_CACHE_##x 207 #define CACHE_READ (1 << C(OP_READ)) 208 #define CACHE_WRITE (1 << C(OP_WRITE)) 209 #define CACHE_PREFETCH (1 << C(OP_PREFETCH)) 210 #define COP(x) (1 << x) 211 212 /* 213 * cache operartion stat 214 * L1I : Read and prefetch only 215 * ITLB and BPU : Read-only 216 */ 217 static unsigned long perf_evsel__hw_cache_stat[C(MAX)] = { 218 [C(L1D)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), 219 [C(L1I)] = (CACHE_READ | CACHE_PREFETCH), 220 [C(LL)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), 221 [C(DTLB)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), 222 [C(ITLB)] = (CACHE_READ), 223 [C(BPU)] = (CACHE_READ), 224 [C(NODE)] = (CACHE_READ | CACHE_WRITE | CACHE_PREFETCH), 225 }; 226 227 bool perf_evsel__is_cache_op_valid(u8 type, u8 op) 228 { 229 if (perf_evsel__hw_cache_stat[type] & COP(op)) 230 return true; /* valid */ 231 else 232 return false; /* invalid */ 233 } 234 235 int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, 236 char *bf, size_t size) 237 { 238 if (result) { 239 return scnprintf(bf, size, "%s-%s-%s", perf_evsel__hw_cache[type][0], 240 perf_evsel__hw_cache_op[op][0], 241 perf_evsel__hw_cache_result[result][0]); 242 } 243 244 return scnprintf(bf, size, "%s-%s", perf_evsel__hw_cache[type][0], 245 perf_evsel__hw_cache_op[op][1]); 246 } 247 248 static int __perf_evsel__hw_cache_name(u64 config, char *bf, size_t size) 249 { 250 u8 op, result, type = (config >> 0) & 0xff; 251 const char *err = "unknown-ext-hardware-cache-type"; 252 253 if (type > PERF_COUNT_HW_CACHE_MAX) 254 goto out_err; 255 256 op = (config >> 8) & 0xff; 257 err = "unknown-ext-hardware-cache-op"; 258 if (op > PERF_COUNT_HW_CACHE_OP_MAX) 259 goto out_err; 260 261 result = (config >> 16) & 0xff; 262 err = "unknown-ext-hardware-cache-result"; 263 if (result > PERF_COUNT_HW_CACHE_RESULT_MAX) 264 goto out_err; 265 266 err = "invalid-cache"; 267 if (!perf_evsel__is_cache_op_valid(type, op)) 268 goto out_err; 269 270 return __perf_evsel__hw_cache_type_op_res_name(type, op, result, bf, size); 271 out_err: 272 return scnprintf(bf, size, "%s", err); 273 } 274 275 static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) 276 { 277 int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); 278 return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); 279 } 280 281 static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) 282 { 283 int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); 284 return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); 285 } 286 287 const char *perf_evsel__name(struct perf_evsel *evsel) 288 { 289 char bf[128]; 290 291 if (evsel->name) 292 return evsel->name; 293 294 switch (evsel->attr.type) { 295 case PERF_TYPE_RAW: 296 perf_evsel__raw_name(evsel, bf, sizeof(bf)); 297 break; 298 299 case PERF_TYPE_HARDWARE: 300 perf_evsel__hw_name(evsel, bf, sizeof(bf)); 301 break; 302 303 case PERF_TYPE_HW_CACHE: 304 perf_evsel__hw_cache_name(evsel, bf, sizeof(bf)); 305 break; 306 307 case PERF_TYPE_SOFTWARE: 308 perf_evsel__sw_name(evsel, bf, sizeof(bf)); 309 break; 310 311 case PERF_TYPE_TRACEPOINT: 312 scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint"); 313 break; 314 315 case PERF_TYPE_BREAKPOINT: 316 perf_evsel__bp_name(evsel, bf, sizeof(bf)); 317 break; 318 319 default: 320 scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); 321 break; 322 } 323 324 evsel->name = strdup(bf); 325 326 return evsel->name ?: "unknown"; 327 } 328 329 void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 330 struct perf_evsel *first) 331 { 332 struct perf_event_attr *attr = &evsel->attr; 333 int track = !evsel->idx; /* only the first counter needs these */ 334 335 attr->disabled = 1; 336 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 337 attr->inherit = !opts->no_inherit; 338 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 339 PERF_FORMAT_TOTAL_TIME_RUNNING | 340 PERF_FORMAT_ID; 341 342 attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; 343 344 /* 345 * We default some events to a 1 default interval. But keep 346 * it a weak assumption overridable by the user. 347 */ 348 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 349 opts->user_interval != ULLONG_MAX)) { 350 if (opts->freq) { 351 attr->sample_type |= PERF_SAMPLE_PERIOD; 352 attr->freq = 1; 353 attr->sample_freq = opts->freq; 354 } else { 355 attr->sample_period = opts->default_interval; 356 } 357 } 358 359 if (opts->no_samples) 360 attr->sample_freq = 0; 361 362 if (opts->inherit_stat) 363 attr->inherit_stat = 1; 364 365 if (opts->sample_address) { 366 attr->sample_type |= PERF_SAMPLE_ADDR; 367 attr->mmap_data = track; 368 } 369 370 if (opts->call_graph) 371 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 372 373 if (perf_target__has_cpu(&opts->target)) 374 attr->sample_type |= PERF_SAMPLE_CPU; 375 376 if (opts->period) 377 attr->sample_type |= PERF_SAMPLE_PERIOD; 378 379 if (!opts->sample_id_all_missing && 380 (opts->sample_time || !opts->no_inherit || 381 perf_target__has_cpu(&opts->target))) 382 attr->sample_type |= PERF_SAMPLE_TIME; 383 384 if (opts->raw_samples) { 385 attr->sample_type |= PERF_SAMPLE_TIME; 386 attr->sample_type |= PERF_SAMPLE_RAW; 387 attr->sample_type |= PERF_SAMPLE_CPU; 388 } 389 390 if (opts->no_delay) { 391 attr->watermark = 0; 392 attr->wakeup_events = 1; 393 } 394 if (opts->branch_stack) { 395 attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; 396 attr->branch_sample_type = opts->branch_stack; 397 } 398 399 attr->mmap = track; 400 attr->comm = track; 401 402 if (perf_target__none(&opts->target) && 403 (!opts->group || evsel == first)) { 404 attr->enable_on_exec = 1; 405 } 406 } 407 408 int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 409 { 410 int cpu, thread; 411 evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); 412 413 if (evsel->fd) { 414 for (cpu = 0; cpu < ncpus; cpu++) { 415 for (thread = 0; thread < nthreads; thread++) { 416 FD(evsel, cpu, thread) = -1; 417 } 418 } 419 } 420 421 return evsel->fd != NULL ? 0 : -ENOMEM; 422 } 423 424 int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) 425 { 426 evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); 427 if (evsel->sample_id == NULL) 428 return -ENOMEM; 429 430 evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); 431 if (evsel->id == NULL) { 432 xyarray__delete(evsel->sample_id); 433 evsel->sample_id = NULL; 434 return -ENOMEM; 435 } 436 437 return 0; 438 } 439 440 int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) 441 { 442 evsel->counts = zalloc((sizeof(*evsel->counts) + 443 (ncpus * sizeof(struct perf_counts_values)))); 444 return evsel->counts != NULL ? 0 : -ENOMEM; 445 } 446 447 void perf_evsel__free_fd(struct perf_evsel *evsel) 448 { 449 xyarray__delete(evsel->fd); 450 evsel->fd = NULL; 451 } 452 453 void perf_evsel__free_id(struct perf_evsel *evsel) 454 { 455 xyarray__delete(evsel->sample_id); 456 evsel->sample_id = NULL; 457 free(evsel->id); 458 evsel->id = NULL; 459 } 460 461 void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 462 { 463 int cpu, thread; 464 465 for (cpu = 0; cpu < ncpus; cpu++) 466 for (thread = 0; thread < nthreads; ++thread) { 467 close(FD(evsel, cpu, thread)); 468 FD(evsel, cpu, thread) = -1; 469 } 470 } 471 472 void perf_evsel__exit(struct perf_evsel *evsel) 473 { 474 assert(list_empty(&evsel->node)); 475 xyarray__delete(evsel->fd); 476 xyarray__delete(evsel->sample_id); 477 free(evsel->id); 478 } 479 480 void perf_evsel__delete(struct perf_evsel *evsel) 481 { 482 perf_evsel__exit(evsel); 483 close_cgroup(evsel->cgrp); 484 free(evsel->name); 485 free(evsel); 486 } 487 488 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, 489 int cpu, int thread, bool scale) 490 { 491 struct perf_counts_values count; 492 size_t nv = scale ? 3 : 1; 493 494 if (FD(evsel, cpu, thread) < 0) 495 return -EINVAL; 496 497 if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0) 498 return -ENOMEM; 499 500 if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) 501 return -errno; 502 503 if (scale) { 504 if (count.run == 0) 505 count.val = 0; 506 else if (count.run < count.ena) 507 count.val = (u64)((double)count.val * count.ena / count.run + 0.5); 508 } else 509 count.ena = count.run = 0; 510 511 evsel->counts->cpu[cpu] = count; 512 return 0; 513 } 514 515 int __perf_evsel__read(struct perf_evsel *evsel, 516 int ncpus, int nthreads, bool scale) 517 { 518 size_t nv = scale ? 3 : 1; 519 int cpu, thread; 520 struct perf_counts_values *aggr = &evsel->counts->aggr, count; 521 522 aggr->val = aggr->ena = aggr->run = 0; 523 524 for (cpu = 0; cpu < ncpus; cpu++) { 525 for (thread = 0; thread < nthreads; thread++) { 526 if (FD(evsel, cpu, thread) < 0) 527 continue; 528 529 if (readn(FD(evsel, cpu, thread), 530 &count, nv * sizeof(u64)) < 0) 531 return -errno; 532 533 aggr->val += count.val; 534 if (scale) { 535 aggr->ena += count.ena; 536 aggr->run += count.run; 537 } 538 } 539 } 540 541 evsel->counts->scaled = 0; 542 if (scale) { 543 if (aggr->run == 0) { 544 evsel->counts->scaled = -1; 545 aggr->val = 0; 546 return 0; 547 } 548 549 if (aggr->run < aggr->ena) { 550 evsel->counts->scaled = 1; 551 aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5); 552 } 553 } else 554 aggr->ena = aggr->run = 0; 555 556 return 0; 557 } 558 559 static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 560 struct thread_map *threads, bool group, 561 struct xyarray *group_fds) 562 { 563 int cpu, thread; 564 unsigned long flags = 0; 565 int pid = -1, err; 566 567 if (evsel->fd == NULL && 568 perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) 569 return -ENOMEM; 570 571 if (evsel->cgrp) { 572 flags = PERF_FLAG_PID_CGROUP; 573 pid = evsel->cgrp->fd; 574 } 575 576 for (cpu = 0; cpu < cpus->nr; cpu++) { 577 int group_fd = group_fds ? GROUP_FD(group_fds, cpu) : -1; 578 579 for (thread = 0; thread < threads->nr; thread++) { 580 581 if (!evsel->cgrp) 582 pid = threads->map[thread]; 583 584 FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, 585 pid, 586 cpus->map[cpu], 587 group_fd, flags); 588 if (FD(evsel, cpu, thread) < 0) { 589 err = -errno; 590 goto out_close; 591 } 592 593 if (group && group_fd == -1) 594 group_fd = FD(evsel, cpu, thread); 595 } 596 } 597 598 return 0; 599 600 out_close: 601 do { 602 while (--thread >= 0) { 603 close(FD(evsel, cpu, thread)); 604 FD(evsel, cpu, thread) = -1; 605 } 606 thread = threads->nr; 607 } while (--cpu >= 0); 608 return err; 609 } 610 611 void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) 612 { 613 if (evsel->fd == NULL) 614 return; 615 616 perf_evsel__close_fd(evsel, ncpus, nthreads); 617 perf_evsel__free_fd(evsel); 618 evsel->fd = NULL; 619 } 620 621 static struct { 622 struct cpu_map map; 623 int cpus[1]; 624 } empty_cpu_map = { 625 .map.nr = 1, 626 .cpus = { -1, }, 627 }; 628 629 static struct { 630 struct thread_map map; 631 int threads[1]; 632 } empty_thread_map = { 633 .map.nr = 1, 634 .threads = { -1, }, 635 }; 636 637 int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, 638 struct thread_map *threads, bool group, 639 struct xyarray *group_fd) 640 { 641 if (cpus == NULL) { 642 /* Work around old compiler warnings about strict aliasing */ 643 cpus = &empty_cpu_map.map; 644 } 645 646 if (threads == NULL) 647 threads = &empty_thread_map.map; 648 649 return __perf_evsel__open(evsel, cpus, threads, group, group_fd); 650 } 651 652 int perf_evsel__open_per_cpu(struct perf_evsel *evsel, 653 struct cpu_map *cpus, bool group, 654 struct xyarray *group_fd) 655 { 656 return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, 657 group_fd); 658 } 659 660 int perf_evsel__open_per_thread(struct perf_evsel *evsel, 661 struct thread_map *threads, bool group, 662 struct xyarray *group_fd) 663 { 664 return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, 665 group_fd); 666 } 667 668 static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 669 struct perf_sample *sample, 670 bool swapped) 671 { 672 const u64 *array = event->sample.array; 673 union u64_swap u; 674 675 array += ((event->header.size - 676 sizeof(event->header)) / sizeof(u64)) - 1; 677 678 if (type & PERF_SAMPLE_CPU) { 679 u.val64 = *array; 680 if (swapped) { 681 /* undo swap of u64, then swap on individual u32s */ 682 u.val64 = bswap_64(u.val64); 683 u.val32[0] = bswap_32(u.val32[0]); 684 } 685 686 sample->cpu = u.val32[0]; 687 array--; 688 } 689 690 if (type & PERF_SAMPLE_STREAM_ID) { 691 sample->stream_id = *array; 692 array--; 693 } 694 695 if (type & PERF_SAMPLE_ID) { 696 sample->id = *array; 697 array--; 698 } 699 700 if (type & PERF_SAMPLE_TIME) { 701 sample->time = *array; 702 array--; 703 } 704 705 if (type & PERF_SAMPLE_TID) { 706 u.val64 = *array; 707 if (swapped) { 708 /* undo swap of u64, then swap on individual u32s */ 709 u.val64 = bswap_64(u.val64); 710 u.val32[0] = bswap_32(u.val32[0]); 711 u.val32[1] = bswap_32(u.val32[1]); 712 } 713 714 sample->pid = u.val32[0]; 715 sample->tid = u.val32[1]; 716 } 717 718 return 0; 719 } 720 721 static bool sample_overlap(const union perf_event *event, 722 const void *offset, u64 size) 723 { 724 const void *base = event; 725 726 if (offset + size > base + event->header.size) 727 return true; 728 729 return false; 730 } 731 732 int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, 733 struct perf_sample *data, bool swapped) 734 { 735 u64 type = evsel->attr.sample_type; 736 const u64 *array; 737 738 /* 739 * used for cross-endian analysis. See git commit 65014ab3 740 * for why this goofiness is needed. 741 */ 742 union u64_swap u; 743 744 memset(data, 0, sizeof(*data)); 745 data->cpu = data->pid = data->tid = -1; 746 data->stream_id = data->id = data->time = -1ULL; 747 data->period = 1; 748 749 if (event->header.type != PERF_RECORD_SAMPLE) { 750 if (!evsel->attr.sample_id_all) 751 return 0; 752 return perf_event__parse_id_sample(event, type, data, swapped); 753 } 754 755 array = event->sample.array; 756 757 if (evsel->sample_size + sizeof(event->header) > event->header.size) 758 return -EFAULT; 759 760 if (type & PERF_SAMPLE_IP) { 761 data->ip = event->ip.ip; 762 array++; 763 } 764 765 if (type & PERF_SAMPLE_TID) { 766 u.val64 = *array; 767 if (swapped) { 768 /* undo swap of u64, then swap on individual u32s */ 769 u.val64 = bswap_64(u.val64); 770 u.val32[0] = bswap_32(u.val32[0]); 771 u.val32[1] = bswap_32(u.val32[1]); 772 } 773 774 data->pid = u.val32[0]; 775 data->tid = u.val32[1]; 776 array++; 777 } 778 779 if (type & PERF_SAMPLE_TIME) { 780 data->time = *array; 781 array++; 782 } 783 784 data->addr = 0; 785 if (type & PERF_SAMPLE_ADDR) { 786 data->addr = *array; 787 array++; 788 } 789 790 data->id = -1ULL; 791 if (type & PERF_SAMPLE_ID) { 792 data->id = *array; 793 array++; 794 } 795 796 if (type & PERF_SAMPLE_STREAM_ID) { 797 data->stream_id = *array; 798 array++; 799 } 800 801 if (type & PERF_SAMPLE_CPU) { 802 803 u.val64 = *array; 804 if (swapped) { 805 /* undo swap of u64, then swap on individual u32s */ 806 u.val64 = bswap_64(u.val64); 807 u.val32[0] = bswap_32(u.val32[0]); 808 } 809 810 data->cpu = u.val32[0]; 811 array++; 812 } 813 814 if (type & PERF_SAMPLE_PERIOD) { 815 data->period = *array; 816 array++; 817 } 818 819 if (type & PERF_SAMPLE_READ) { 820 fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); 821 return -1; 822 } 823 824 if (type & PERF_SAMPLE_CALLCHAIN) { 825 if (sample_overlap(event, array, sizeof(data->callchain->nr))) 826 return -EFAULT; 827 828 data->callchain = (struct ip_callchain *)array; 829 830 if (sample_overlap(event, array, data->callchain->nr)) 831 return -EFAULT; 832 833 array += 1 + data->callchain->nr; 834 } 835 836 if (type & PERF_SAMPLE_RAW) { 837 const u64 *pdata; 838 839 u.val64 = *array; 840 if (WARN_ONCE(swapped, 841 "Endianness of raw data not corrected!\n")) { 842 /* undo swap of u64, then swap on individual u32s */ 843 u.val64 = bswap_64(u.val64); 844 u.val32[0] = bswap_32(u.val32[0]); 845 u.val32[1] = bswap_32(u.val32[1]); 846 } 847 848 if (sample_overlap(event, array, sizeof(u32))) 849 return -EFAULT; 850 851 data->raw_size = u.val32[0]; 852 pdata = (void *) array + sizeof(u32); 853 854 if (sample_overlap(event, pdata, data->raw_size)) 855 return -EFAULT; 856 857 data->raw_data = (void *) pdata; 858 859 array = (void *)array + data->raw_size + sizeof(u32); 860 } 861 862 if (type & PERF_SAMPLE_BRANCH_STACK) { 863 u64 sz; 864 865 data->branch_stack = (struct branch_stack *)array; 866 array++; /* nr */ 867 868 sz = data->branch_stack->nr * sizeof(struct branch_entry); 869 sz /= sizeof(u64); 870 array += sz; 871 } 872 return 0; 873 } 874 875 int perf_event__synthesize_sample(union perf_event *event, u64 type, 876 const struct perf_sample *sample, 877 bool swapped) 878 { 879 u64 *array; 880 881 /* 882 * used for cross-endian analysis. See git commit 65014ab3 883 * for why this goofiness is needed. 884 */ 885 union u64_swap u; 886 887 array = event->sample.array; 888 889 if (type & PERF_SAMPLE_IP) { 890 event->ip.ip = sample->ip; 891 array++; 892 } 893 894 if (type & PERF_SAMPLE_TID) { 895 u.val32[0] = sample->pid; 896 u.val32[1] = sample->tid; 897 if (swapped) { 898 /* 899 * Inverse of what is done in perf_evsel__parse_sample 900 */ 901 u.val32[0] = bswap_32(u.val32[0]); 902 u.val32[1] = bswap_32(u.val32[1]); 903 u.val64 = bswap_64(u.val64); 904 } 905 906 *array = u.val64; 907 array++; 908 } 909 910 if (type & PERF_SAMPLE_TIME) { 911 *array = sample->time; 912 array++; 913 } 914 915 if (type & PERF_SAMPLE_ADDR) { 916 *array = sample->addr; 917 array++; 918 } 919 920 if (type & PERF_SAMPLE_ID) { 921 *array = sample->id; 922 array++; 923 } 924 925 if (type & PERF_SAMPLE_STREAM_ID) { 926 *array = sample->stream_id; 927 array++; 928 } 929 930 if (type & PERF_SAMPLE_CPU) { 931 u.val32[0] = sample->cpu; 932 if (swapped) { 933 /* 934 * Inverse of what is done in perf_evsel__parse_sample 935 */ 936 u.val32[0] = bswap_32(u.val32[0]); 937 u.val64 = bswap_64(u.val64); 938 } 939 *array = u.val64; 940 array++; 941 } 942 943 if (type & PERF_SAMPLE_PERIOD) { 944 *array = sample->period; 945 array++; 946 } 947 948 return 0; 949 } 950