Due to a discussion with Adrian I had a good look at the perf_event_type record layout and found the documentation to be somewhat unclear.
Unified · Split
| @@ -478,6 +478,16 @@ enum perf_event_type { · 477 unmodified lines | ||
| 478 | 478 | * file will be supported by older perf tools, with these new optional |
| 479 | 479 | * fields being ignored. |
| 480 | 480 | * |
| 481 | + * struct sample_id { | |
| 482 | + * { u32 pid, tid; } && PERF_SAMPLE_TID | |
| 483 | + * { u64 time; } && PERF_SAMPLE_TIME | |
| 484 | + * { u64 id; } && PERF_SAMPLE_ID | |
| 485 | + * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID | |
| 486 | + * { u32 cpu, res; } && PERF_SAMPLE_CPU | |
| 487 | + * } && perf_event_attr::sample_id_all | |
| 488 | + */ | |
| 489 | + | |
| 490 | + /* | |
| 481 | 491 | * The MMAP events record the PROT_EXEC mappings so that we can |
| 482 | 492 | * correlate userspace IPs to code. They have the following structure: |
| 483 | 493 | * |
| @@ -498,6 +508,7 @@ enum perf_event_type { · 14 unmodified lines | ||
| 498 | 508 | * struct perf_event_header header; |
| 499 | 509 | * u64 id; |
| 500 | 510 | * u64 lost; |
| 511 | + * struct sample_id sample_id; | |
| 501 | 512 | * }; |
| 502 | 513 | */ |
| 503 | 514 | PERF_RECORD_LOST = 2, |
| @@ -508,6 +519,7 @@ enum perf_event_type { · 4 unmodified lines | ||
| 508 | 519 | * |
| 509 | 520 | * u32 pid, tid; |
| 510 | 521 | * char comm[]; |
| 522 | + * struct sample_id sample_id; | |
| 511 | 523 | * }; |
| 512 | 524 | */ |
| 513 | 525 | PERF_RECORD_COMM = 3, |
| @@ -518,6 +530,7 @@ enum perf_event_type { · 4 unmodified lines | ||
| 518 | 530 | * u32 pid, ppid; |
| 519 | 531 | * u32 tid, ptid; |
| 520 | 532 | * u64 time; |
| 533 | + * struct sample_id sample_id; | |
| 521 | 534 | * }; |
| 522 | 535 | */ |
| 523 | 536 | PERF_RECORD_EXIT = 4, |
| @@ -528,6 +541,7 @@ enum perf_event_type { · 4 unmodified lines | ||
| 528 | 541 | * u64 time; |
| 529 | 542 | * u64 id; |
| 530 | 543 | * u64 stream_id; |
| 544 | + * struct sample_id sample_id; | |
| 531 | 545 | * }; |
| 532 | 546 | */ |
| 533 | 547 | PERF_RECORD_THROTTLE = 5, |
| @@ -539,6 +553,7 @@ enum perf_event_type { · 5 unmodified lines | ||
| 539 | 553 | * u32 pid, ppid; |
| 540 | 554 | * u32 tid, ptid; |
| 541 | 555 | * u64 time; |
| 556 | + * struct sample_id sample_id; | |
| 542 | 557 | * }; |
| 543 | 558 | */ |
| 544 | 559 | PERF_RECORD_FORK = 7, |
| @@ -549,6 +564,7 @@ enum perf_event_type { · 4 unmodified lines | ||
| 549 | 564 | * u32 pid, tid; |
| 550 | 565 | * |
| 551 | 566 | * struct read_format values; |
| 567 | + * struct sample_id sample_id; | |
| 552 | 568 | * }; |
| 553 | 569 | */ |
| 554 | 570 | PERF_RECORD_READ = 8, |
| @@ -596,7 +612,7 @@ enum perf_event_type { · 41 unmodified lines | ||
| 596 | 612 | * u64 dyn_size; } && PERF_SAMPLE_STACK_USER |
| 597 | 613 | * |
| 598 | 614 | * { u64 weight; } && PERF_SAMPLE_WEIGHT |
| 599 | − * { u64 data_src; } && PERF_SAMPLE_DATA_SRC | |
| 615 | + * { u64 data_src; } && PERF_SAMPLE_DATA_SRC | |
| 600 | 616 | * }; |
| 601 | 617 | */ |
| 602 | 618 | PERF_RECORD_SAMPLE = 9, |
| @@ -4462,20 +4462,6 @@ void perf_output_sample(struct perf_output_handle *handle, · 4461 unmodified lines | ||
| 4462 | 4462 | } |
| 4463 | 4463 | } |
| 4464 | 4464 | |
| 4465 | − if (!event->attr.watermark) { | |
| 4466 | − int wakeup_events = event->attr.wakeup_events; | |
| 4467 | − | |
| 4468 | − if (wakeup_events) { | |
| 4469 | − struct ring_buffer *rb = handle->rb; | |
| 4470 | − int events = local_inc_return(&rb->events); | |
| 4471 | − | |
| 4472 | − if (events >= wakeup_events) { | |
| 4473 | − local_sub(wakeup_events, &rb->events); | |
| 4474 | − local_inc(&rb->wakeup); | |
| 4475 | − } | |
| 4476 | − } | |
| 4477 | − } | |
| 4478 | − | |
| 4479 | 4465 | if (sample_type & PERF_SAMPLE_BRANCH_STACK) { |
| 4480 | 4466 | if (data->br_stack) { |
| 4481 | 4467 | size_t size; |
| @@ -4511,16 +4497,31 @@ void perf_output_sample(struct perf_output_handle *handle, · 29 unmodified lines | ||
| 4511 | 4497 | } |
| 4512 | 4498 | } |
| 4513 | 4499 | |
| 4514 | − if (sample_type & PERF_SAMPLE_STACK_USER) | |
| 4500 | + if (sample_type & PERF_SAMPLE_STACK_USER) { | |
| 4515 | 4501 | perf_output_sample_ustack(handle, |
| 4516 | 4502 | data->stack_user_size, |
| 4517 | 4503 | data->regs_user.regs); |
| 4504 | + } | |
| 4518 | 4505 | |
| 4519 | 4506 | if (sample_type & PERF_SAMPLE_WEIGHT) |
| 4520 | 4507 | perf_output_put(handle, data->weight); |
| 4521 | 4508 | |
| 4522 | 4509 | if (sample_type & PERF_SAMPLE_DATA_SRC) |
| 4523 | 4510 | perf_output_put(handle, data->data_src.val); |
| 4511 | + | |
| 4512 | + if (!event->attr.watermark) { | |
| 4513 | + int wakeup_events = event->attr.wakeup_events; | |
| 4514 | + | |
| 4515 | + if (wakeup_events) { | |
| 4516 | + struct ring_buffer *rb = handle->rb; | |
| 4517 | + int events = local_inc_return(&rb->events); | |
| 4518 | + | |
| 4519 | + if (events >= wakeup_events) { | |
| 4520 | + local_sub(wakeup_events, &rb->events); | |
| 4521 | + local_inc(&rb->wakeup); | |
| 4522 | + } | |
| 4523 | + } | |
| 4524 | + } | |
| 4524 | 4525 | } |
| 4525 | 4526 | |
| 4526 | 4527 | void perf_prepare_sample(struct perf_event_header *header, |