diff options
| -rw-r--r-- | include/linux/perf_event.h | 1 | ||||
| -rw-r--r-- | kernel/perf_event.c | 129 |
2 files changed, 76 insertions, 54 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index adf6d9931643..b9950b1620d8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -759,6 +759,7 @@ struct perf_event { | |||
| 759 | 759 | ||
| 760 | struct perf_event_attr attr; | 760 | struct perf_event_attr attr; |
| 761 | u16 header_size; | 761 | u16 header_size; |
| 762 | u16 id_header_size; | ||
| 762 | u16 read_size; | 763 | u16 read_size; |
| 763 | struct hw_perf_event hw; | 764 | struct hw_perf_event hw; |
| 764 | 765 | ||
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index 7961b27aceea..a04799769566 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
| @@ -133,6 +133,28 @@ static void unclone_ctx(struct perf_event_context *ctx) | |||
| 133 | } | 133 | } |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | static u32 perf_event_pid(struct perf_event *event, struct task_struct *p) | ||
| 137 | { | ||
| 138 | /* | ||
| 139 | * only top level events have the pid namespace they were created in | ||
| 140 | */ | ||
| 141 | if (event->parent) | ||
| 142 | event = event->parent; | ||
| 143 | |||
| 144 | return task_tgid_nr_ns(p, event->ns); | ||
| 145 | } | ||
| 146 | |||
| 147 | static u32 perf_event_tid(struct perf_event *event, struct task_struct *p) | ||
| 148 | { | ||
| 149 | /* | ||
| 150 | * only top level events have the pid namespace they were created in | ||
| 151 | */ | ||
| 152 | if (event->parent) | ||
| 153 | event = event->parent; | ||
| 154 | |||
| 155 | return task_pid_nr_ns(p, event->ns); | ||
| 156 | } | ||
| 157 | |||
| 136 | /* | 158 | /* |
| 137 | * If we inherit events we want to return the parent event id | 159 | * If we inherit events we want to return the parent event id |
| 138 | * to userspace. | 160 | * to userspace. |
| @@ -351,15 +373,30 @@ static void perf_event__header_size(struct perf_event *event) | |||
| 351 | if (sample_type & PERF_SAMPLE_IP) | 373 | if (sample_type & PERF_SAMPLE_IP) |
| 352 | size += sizeof(data->ip); | 374 | size += sizeof(data->ip); |
| 353 | 375 | ||
| 376 | if (sample_type & PERF_SAMPLE_ADDR) | ||
| 377 | size += sizeof(data->addr); | ||
| 378 | |||
| 379 | if (sample_type & PERF_SAMPLE_PERIOD) | ||
| 380 | size += sizeof(data->period); | ||
| 381 | |||
| 382 | if (sample_type & PERF_SAMPLE_READ) | ||
| 383 | size += event->read_size; | ||
| 384 | |||
| 385 | event->header_size = size; | ||
| 386 | } | ||
| 387 | |||
| 388 | static void perf_event__id_header_size(struct perf_event *event) | ||
| 389 | { | ||
| 390 | struct perf_sample_data *data; | ||
| 391 | u64 sample_type = event->attr.sample_type; | ||
| 392 | u16 size = 0; | ||
| 393 | |||
| 354 | if (sample_type & PERF_SAMPLE_TID) | 394 | if (sample_type & PERF_SAMPLE_TID) |
| 355 | size += sizeof(data->tid_entry); | 395 | size += sizeof(data->tid_entry); |
| 356 | 396 | ||
| 357 | if (sample_type & PERF_SAMPLE_TIME) | 397 | if (sample_type & PERF_SAMPLE_TIME) |
| 358 | size += sizeof(data->time); | 398 | size += sizeof(data->time); |
| 359 | 399 | ||
| 360 | if (sample_type & PERF_SAMPLE_ADDR) | ||
| 361 | size += sizeof(data->addr); | ||
| 362 | |||
| 363 | if (sample_type & PERF_SAMPLE_ID) | 400 | if (sample_type & PERF_SAMPLE_ID) |
| 364 | size += sizeof(data->id); | 401 | size += sizeof(data->id); |
| 365 | 402 | ||
| @@ -369,13 +406,7 @@ static void perf_event__header_size(struct perf_event *event) | |||
| 369 | if (sample_type & PERF_SAMPLE_CPU) | 406 | if (sample_type & PERF_SAMPLE_CPU) |
| 370 | size += sizeof(data->cpu_entry); | 407 | size += sizeof(data->cpu_entry); |
| 371 | 408 | ||
| 372 | if (sample_type & PERF_SAMPLE_PERIOD) | 409 | event->id_header_size = size; |
| 373 | size += sizeof(data->period); | ||
| 374 | |||
| 375 | if (sample_type & PERF_SAMPLE_READ) | ||
| 376 | size += event->read_size; | ||
| 377 | |||
| 378 | event->header_size = size; | ||
| 379 | } | 410 | } |
| 380 | 411 | ||
| 381 | static void perf_group_attach(struct perf_event *event) | 412 | static void perf_group_attach(struct perf_event *event) |
| @@ -3357,6 +3388,36 @@ __always_inline void perf_output_copy(struct perf_output_handle *handle, | |||
| 3357 | } while (len); | 3388 | } while (len); |
| 3358 | } | 3389 | } |
| 3359 | 3390 | ||
| 3391 | static void perf_event_header__init_id(struct perf_event_header *header, | ||
| 3392 | struct perf_sample_data *data, | ||
| 3393 | struct perf_event *event) | ||
| 3394 | { | ||
| 3395 | u64 sample_type = event->attr.sample_type; | ||
| 3396 | |||
| 3397 | data->type = sample_type; | ||
| 3398 | header->size += event->id_header_size; | ||
| 3399 | |||
| 3400 | if (sample_type & PERF_SAMPLE_TID) { | ||
| 3401 | /* namespace issues */ | ||
| 3402 | data->tid_entry.pid = perf_event_pid(event, current); | ||
| 3403 | data->tid_entry.tid = perf_event_tid(event, current); | ||
| 3404 | } | ||
| 3405 | |||
| 3406 | if (sample_type & PERF_SAMPLE_TIME) | ||
| 3407 | data->time = perf_clock(); | ||
| 3408 | |||
| 3409 | if (sample_type & PERF_SAMPLE_ID) | ||
| 3410 | data->id = primary_event_id(event); | ||
| 3411 | |||
| 3412 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 3413 | data->stream_id = event->id; | ||
| 3414 | |||
| 3415 | if (sample_type & PERF_SAMPLE_CPU) { | ||
| 3416 | data->cpu_entry.cpu = raw_smp_processor_id(); | ||
| 3417 | data->cpu_entry.reserved = 0; | ||
| 3418 | } | ||
| 3419 | } | ||
| 3420 | |||
| 3360 | int perf_output_begin(struct perf_output_handle *handle, | 3421 | int perf_output_begin(struct perf_output_handle *handle, |
| 3361 | struct perf_event *event, unsigned int size, | 3422 | struct perf_event *event, unsigned int size, |
| 3362 | int nmi, int sample) | 3423 | int nmi, int sample) |
| @@ -3459,28 +3520,6 @@ void perf_output_end(struct perf_output_handle *handle) | |||
| 3459 | rcu_read_unlock(); | 3520 | rcu_read_unlock(); |
| 3460 | } | 3521 | } |
| 3461 | 3522 | ||
| 3462 | static u32 perf_event_pid(struct perf_event *event, struct task_struct *p) | ||
| 3463 | { | ||
| 3464 | /* | ||
| 3465 | * only top level events have the pid namespace they were created in | ||
| 3466 | */ | ||
| 3467 | if (event->parent) | ||
| 3468 | event = event->parent; | ||
| 3469 | |||
| 3470 | return task_tgid_nr_ns(p, event->ns); | ||
| 3471 | } | ||
| 3472 | |||
| 3473 | static u32 perf_event_tid(struct perf_event *event, struct task_struct *p) | ||
| 3474 | { | ||
| 3475 | /* | ||
| 3476 | * only top level events have the pid namespace they were created in | ||
| 3477 | */ | ||
| 3478 | if (event->parent) | ||
| 3479 | event = event->parent; | ||
| 3480 | |||
| 3481 | return task_pid_nr_ns(p, event->ns); | ||
| 3482 | } | ||
| 3483 | |||
| 3484 | static void perf_output_read_one(struct perf_output_handle *handle, | 3523 | static void perf_output_read_one(struct perf_output_handle *handle, |
| 3485 | struct perf_event *event, | 3524 | struct perf_event *event, |
| 3486 | u64 enabled, u64 running) | 3525 | u64 enabled, u64 running) |
| @@ -3655,37 +3694,17 @@ void perf_prepare_sample(struct perf_event_header *header, | |||
| 3655 | { | 3694 | { |
| 3656 | u64 sample_type = event->attr.sample_type; | 3695 | u64 sample_type = event->attr.sample_type; |
| 3657 | 3696 | ||
| 3658 | data->type = sample_type; | ||
| 3659 | |||
| 3660 | header->type = PERF_RECORD_SAMPLE; | 3697 | header->type = PERF_RECORD_SAMPLE; |
| 3661 | header->size = sizeof(*header) + event->header_size; | 3698 | header->size = sizeof(*header) + event->header_size; |
| 3662 | 3699 | ||
| 3663 | header->misc = 0; | 3700 | header->misc = 0; |
| 3664 | header->misc |= perf_misc_flags(regs); | 3701 | header->misc |= perf_misc_flags(regs); |
| 3665 | 3702 | ||
| 3703 | perf_event_header__init_id(header, data, event); | ||
| 3704 | |||
| 3666 | if (sample_type & PERF_SAMPLE_IP) | 3705 | if (sample_type & PERF_SAMPLE_IP) |
| 3667 | data->ip = perf_instruction_pointer(regs); | 3706 | data->ip = perf_instruction_pointer(regs); |
| 3668 | 3707 | ||
| 3669 | if (sample_type & PERF_SAMPLE_TID) { | ||
| 3670 | /* namespace issues */ | ||
| 3671 | data->tid_entry.pid = perf_event_pid(event, current); | ||
| 3672 | data->tid_entry.tid = perf_event_tid(event, current); | ||
| 3673 | } | ||
| 3674 | |||
| 3675 | if (sample_type & PERF_SAMPLE_TIME) | ||
| 3676 | data->time = perf_clock(); | ||
| 3677 | |||
| 3678 | if (sample_type & PERF_SAMPLE_ID) | ||
| 3679 | data->id = primary_event_id(event); | ||
| 3680 | |||
| 3681 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 3682 | data->stream_id = event->id; | ||
| 3683 | |||
| 3684 | if (sample_type & PERF_SAMPLE_CPU) { | ||
| 3685 | data->cpu_entry.cpu = raw_smp_processor_id(); | ||
| 3686 | data->cpu_entry.reserved = 0; | ||
| 3687 | } | ||
| 3688 | |||
| 3689 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { | 3708 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { |
| 3690 | int size = 1; | 3709 | int size = 1; |
| 3691 | 3710 | ||
| @@ -5745,6 +5764,7 @@ SYSCALL_DEFINE5(perf_event_open, | |||
| 5745 | * Precalculate sample_data sizes | 5764 | * Precalculate sample_data sizes |
| 5746 | */ | 5765 | */ |
| 5747 | perf_event__header_size(event); | 5766 | perf_event__header_size(event); |
| 5767 | perf_event__id_header_size(event); | ||
| 5748 | 5768 | ||
| 5749 | /* | 5769 | /* |
| 5750 | * Drop the reference on the group_event after placing the | 5770 | * Drop the reference on the group_event after placing the |
| @@ -6102,6 +6122,7 @@ inherit_event(struct perf_event *parent_event, | |||
| 6102 | * Precalculate sample_data sizes | 6122 | * Precalculate sample_data sizes |
| 6103 | */ | 6123 | */ |
| 6104 | perf_event__header_size(child_event); | 6124 | perf_event__header_size(child_event); |
| 6125 | perf_event__id_header_size(child_event); | ||
| 6105 | 6126 | ||
| 6106 | /* | 6127 | /* |
| 6107 | * Link it up in the child's context: | 6128 | * Link it up in the child's context: |
