diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-12-04 20:02:20 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-12-04 20:02:20 -0500 |
commit | c980d1091810df13f21aabbce545fd98f545bbf7 (patch) | |
tree | ccf26c6f97ac4965dee6daa7a91dde6b4108b94e /kernel | |
parent | 6844c09d849aeb00e8ddfe9525e8567a531c22d0 (diff) |
perf events: Make sample_type identity fields available in all PERF_RECORD_ events
If perf_event_attr.sample_id_all is set it will add the PERF_SAMPLE_ identity
info:
TID, TIME, ID, CPU, STREAM_ID
As a trailer, so that older perf tools can process new files, just ignoring the
extra payload.
With this its possible to do further analysis on problems in the event stream,
like detecting reordering of MMAP and FORK events, etc.
V2: Fixup header size in comm, mmap and task processing, as we have to take into
account different sample_types for each matching event, noticed by Thomas Gleixner.
Thomas also noticed a problem in v2 where if we didn't had space in the buffer we
wouldn't restore the header size.
Tested-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Ian Munsie <imunsie@au1.ibm.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Ian Munsie <imunsie@au1.ibm.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/perf_event.c | 108 |
1 files changed, 91 insertions, 17 deletions
diff --git a/kernel/perf_event.c b/kernel/perf_event.c index a04799769566..77ad22c00b9d 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c | |||
@@ -3388,9 +3388,9 @@ __always_inline void perf_output_copy(struct perf_output_handle *handle, | |||
3388 | } while (len); | 3388 | } while (len); |
3389 | } | 3389 | } |
3390 | 3390 | ||
3391 | static void perf_event_header__init_id(struct perf_event_header *header, | 3391 | static void __perf_event_header__init_id(struct perf_event_header *header, |
3392 | struct perf_sample_data *data, | 3392 | struct perf_sample_data *data, |
3393 | struct perf_event *event) | 3393 | struct perf_event *event) |
3394 | { | 3394 | { |
3395 | u64 sample_type = event->attr.sample_type; | 3395 | u64 sample_type = event->attr.sample_type; |
3396 | 3396 | ||
@@ -3418,6 +3418,43 @@ static void perf_event_header__init_id(struct perf_event_header *header, | |||
3418 | } | 3418 | } |
3419 | } | 3419 | } |
3420 | 3420 | ||
3421 | static void perf_event_header__init_id(struct perf_event_header *header, | ||
3422 | struct perf_sample_data *data, | ||
3423 | struct perf_event *event) | ||
3424 | { | ||
3425 | if (event->attr.sample_id_all) | ||
3426 | __perf_event_header__init_id(header, data, event); | ||
3427 | } | ||
3428 | |||
3429 | static void __perf_event__output_id_sample(struct perf_output_handle *handle, | ||
3430 | struct perf_sample_data *data) | ||
3431 | { | ||
3432 | u64 sample_type = data->type; | ||
3433 | |||
3434 | if (sample_type & PERF_SAMPLE_TID) | ||
3435 | perf_output_put(handle, data->tid_entry); | ||
3436 | |||
3437 | if (sample_type & PERF_SAMPLE_TIME) | ||
3438 | perf_output_put(handle, data->time); | ||
3439 | |||
3440 | if (sample_type & PERF_SAMPLE_ID) | ||
3441 | perf_output_put(handle, data->id); | ||
3442 | |||
3443 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
3444 | perf_output_put(handle, data->stream_id); | ||
3445 | |||
3446 | if (sample_type & PERF_SAMPLE_CPU) | ||
3447 | perf_output_put(handle, data->cpu_entry); | ||
3448 | } | ||
3449 | |||
3450 | static void perf_event__output_id_sample(struct perf_event *event, | ||
3451 | struct perf_output_handle *handle, | ||
3452 | struct perf_sample_data *sample) | ||
3453 | { | ||
3454 | if (event->attr.sample_id_all) | ||
3455 | __perf_event__output_id_sample(handle, sample); | ||
3456 | } | ||
3457 | |||
3421 | int perf_output_begin(struct perf_output_handle *handle, | 3458 | int perf_output_begin(struct perf_output_handle *handle, |
3422 | struct perf_event *event, unsigned int size, | 3459 | struct perf_event *event, unsigned int size, |
3423 | int nmi, int sample) | 3460 | int nmi, int sample) |
@@ -3425,6 +3462,7 @@ int perf_output_begin(struct perf_output_handle *handle, | |||
3425 | struct perf_buffer *buffer; | 3462 | struct perf_buffer *buffer; |
3426 | unsigned long tail, offset, head; | 3463 | unsigned long tail, offset, head; |
3427 | int have_lost; | 3464 | int have_lost; |
3465 | struct perf_sample_data sample_data; | ||
3428 | struct { | 3466 | struct { |
3429 | struct perf_event_header header; | 3467 | struct perf_event_header header; |
3430 | u64 id; | 3468 | u64 id; |
@@ -3451,8 +3489,12 @@ int perf_output_begin(struct perf_output_handle *handle, | |||
3451 | goto out; | 3489 | goto out; |
3452 | 3490 | ||
3453 | have_lost = local_read(&buffer->lost); | 3491 | have_lost = local_read(&buffer->lost); |
3454 | if (have_lost) | 3492 | if (have_lost) { |
3455 | size += sizeof(lost_event); | 3493 | lost_event.header.size = sizeof(lost_event); |
3494 | perf_event_header__init_id(&lost_event.header, &sample_data, | ||
3495 | event); | ||
3496 | size += lost_event.header.size; | ||
3497 | } | ||
3456 | 3498 | ||
3457 | perf_output_get_handle(handle); | 3499 | perf_output_get_handle(handle); |
3458 | 3500 | ||
@@ -3483,11 +3525,11 @@ int perf_output_begin(struct perf_output_handle *handle, | |||
3483 | if (have_lost) { | 3525 | if (have_lost) { |
3484 | lost_event.header.type = PERF_RECORD_LOST; | 3526 | lost_event.header.type = PERF_RECORD_LOST; |
3485 | lost_event.header.misc = 0; | 3527 | lost_event.header.misc = 0; |
3486 | lost_event.header.size = sizeof(lost_event); | ||
3487 | lost_event.id = event->id; | 3528 | lost_event.id = event->id; |
3488 | lost_event.lost = local_xchg(&buffer->lost, 0); | 3529 | lost_event.lost = local_xchg(&buffer->lost, 0); |
3489 | 3530 | ||
3490 | perf_output_put(handle, lost_event); | 3531 | perf_output_put(handle, lost_event); |
3532 | perf_event__output_id_sample(event, handle, &sample_data); | ||
3491 | } | 3533 | } |
3492 | 3534 | ||
3493 | return 0; | 3535 | return 0; |
@@ -3700,7 +3742,7 @@ void perf_prepare_sample(struct perf_event_header *header, | |||
3700 | header->misc = 0; | 3742 | header->misc = 0; |
3701 | header->misc |= perf_misc_flags(regs); | 3743 | header->misc |= perf_misc_flags(regs); |
3702 | 3744 | ||
3703 | perf_event_header__init_id(header, data, event); | 3745 | __perf_event_header__init_id(header, data, event); |
3704 | 3746 | ||
3705 | if (sample_type & PERF_SAMPLE_IP) | 3747 | if (sample_type & PERF_SAMPLE_IP) |
3706 | data->ip = perf_instruction_pointer(regs); | 3748 | data->ip = perf_instruction_pointer(regs); |
@@ -3768,6 +3810,7 @@ perf_event_read_event(struct perf_event *event, | |||
3768 | struct task_struct *task) | 3810 | struct task_struct *task) |
3769 | { | 3811 | { |
3770 | struct perf_output_handle handle; | 3812 | struct perf_output_handle handle; |
3813 | struct perf_sample_data sample; | ||
3771 | struct perf_read_event read_event = { | 3814 | struct perf_read_event read_event = { |
3772 | .header = { | 3815 | .header = { |
3773 | .type = PERF_RECORD_READ, | 3816 | .type = PERF_RECORD_READ, |
@@ -3779,12 +3822,14 @@ perf_event_read_event(struct perf_event *event, | |||
3779 | }; | 3822 | }; |
3780 | int ret; | 3823 | int ret; |
3781 | 3824 | ||
3825 | perf_event_header__init_id(&read_event.header, &sample, event); | ||
3782 | ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0); | 3826 | ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0); |
3783 | if (ret) | 3827 | if (ret) |
3784 | return; | 3828 | return; |
3785 | 3829 | ||
3786 | perf_output_put(&handle, read_event); | 3830 | perf_output_put(&handle, read_event); |
3787 | perf_output_read(&handle, event); | 3831 | perf_output_read(&handle, event); |
3832 | perf_event__output_id_sample(event, &handle, &sample); | ||
3788 | 3833 | ||
3789 | perf_output_end(&handle); | 3834 | perf_output_end(&handle); |
3790 | } | 3835 | } |
@@ -3814,14 +3859,16 @@ static void perf_event_task_output(struct perf_event *event, | |||
3814 | struct perf_task_event *task_event) | 3859 | struct perf_task_event *task_event) |
3815 | { | 3860 | { |
3816 | struct perf_output_handle handle; | 3861 | struct perf_output_handle handle; |
3862 | struct perf_sample_data sample; | ||
3817 | struct task_struct *task = task_event->task; | 3863 | struct task_struct *task = task_event->task; |
3818 | int size, ret; | 3864 | int ret, size = task_event->event_id.header.size; |
3819 | 3865 | ||
3820 | size = task_event->event_id.header.size; | 3866 | perf_event_header__init_id(&task_event->event_id.header, &sample, event); |
3821 | ret = perf_output_begin(&handle, event, size, 0, 0); | ||
3822 | 3867 | ||
3868 | ret = perf_output_begin(&handle, event, | ||
3869 | task_event->event_id.header.size, 0, 0); | ||
3823 | if (ret) | 3870 | if (ret) |
3824 | return; | 3871 | goto out; |
3825 | 3872 | ||
3826 | task_event->event_id.pid = perf_event_pid(event, task); | 3873 | task_event->event_id.pid = perf_event_pid(event, task); |
3827 | task_event->event_id.ppid = perf_event_pid(event, current); | 3874 | task_event->event_id.ppid = perf_event_pid(event, current); |
@@ -3831,7 +3878,11 @@ static void perf_event_task_output(struct perf_event *event, | |||
3831 | 3878 | ||
3832 | perf_output_put(&handle, task_event->event_id); | 3879 | perf_output_put(&handle, task_event->event_id); |
3833 | 3880 | ||
3881 | perf_event__output_id_sample(event, &handle, &sample); | ||
3882 | |||
3834 | perf_output_end(&handle); | 3883 | perf_output_end(&handle); |
3884 | out: | ||
3885 | task_event->event_id.header.size = size; | ||
3835 | } | 3886 | } |
3836 | 3887 | ||
3837 | static int perf_event_task_match(struct perf_event *event) | 3888 | static int perf_event_task_match(struct perf_event *event) |
@@ -3944,11 +3995,16 @@ static void perf_event_comm_output(struct perf_event *event, | |||
3944 | struct perf_comm_event *comm_event) | 3995 | struct perf_comm_event *comm_event) |
3945 | { | 3996 | { |
3946 | struct perf_output_handle handle; | 3997 | struct perf_output_handle handle; |
3998 | struct perf_sample_data sample; | ||
3947 | int size = comm_event->event_id.header.size; | 3999 | int size = comm_event->event_id.header.size; |
3948 | int ret = perf_output_begin(&handle, event, size, 0, 0); | 4000 | int ret; |
4001 | |||
4002 | perf_event_header__init_id(&comm_event->event_id.header, &sample, event); | ||
4003 | ret = perf_output_begin(&handle, event, | ||
4004 | comm_event->event_id.header.size, 0, 0); | ||
3949 | 4005 | ||
3950 | if (ret) | 4006 | if (ret) |
3951 | return; | 4007 | goto out; |
3952 | 4008 | ||
3953 | comm_event->event_id.pid = perf_event_pid(event, comm_event->task); | 4009 | comm_event->event_id.pid = perf_event_pid(event, comm_event->task); |
3954 | comm_event->event_id.tid = perf_event_tid(event, comm_event->task); | 4010 | comm_event->event_id.tid = perf_event_tid(event, comm_event->task); |
@@ -3956,7 +4012,12 @@ static void perf_event_comm_output(struct perf_event *event, | |||
3956 | perf_output_put(&handle, comm_event->event_id); | 4012 | perf_output_put(&handle, comm_event->event_id); |
3957 | perf_output_copy(&handle, comm_event->comm, | 4013 | perf_output_copy(&handle, comm_event->comm, |
3958 | comm_event->comm_size); | 4014 | comm_event->comm_size); |
4015 | |||
4016 | perf_event__output_id_sample(event, &handle, &sample); | ||
4017 | |||
3959 | perf_output_end(&handle); | 4018 | perf_output_end(&handle); |
4019 | out: | ||
4020 | comm_event->event_id.header.size = size; | ||
3960 | } | 4021 | } |
3961 | 4022 | ||
3962 | static int perf_event_comm_match(struct perf_event *event) | 4023 | static int perf_event_comm_match(struct perf_event *event) |
@@ -4001,7 +4062,6 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) | |||
4001 | comm_event->comm_size = size; | 4062 | comm_event->comm_size = size; |
4002 | 4063 | ||
4003 | comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; | 4064 | comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; |
4004 | |||
4005 | rcu_read_lock(); | 4065 | rcu_read_lock(); |
4006 | list_for_each_entry_rcu(pmu, &pmus, entry) { | 4066 | list_for_each_entry_rcu(pmu, &pmus, entry) { |
4007 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); | 4067 | cpuctx = get_cpu_ptr(pmu->pmu_cpu_context); |
@@ -4080,11 +4140,15 @@ static void perf_event_mmap_output(struct perf_event *event, | |||
4080 | struct perf_mmap_event *mmap_event) | 4140 | struct perf_mmap_event *mmap_event) |
4081 | { | 4141 | { |
4082 | struct perf_output_handle handle; | 4142 | struct perf_output_handle handle; |
4143 | struct perf_sample_data sample; | ||
4083 | int size = mmap_event->event_id.header.size; | 4144 | int size = mmap_event->event_id.header.size; |
4084 | int ret = perf_output_begin(&handle, event, size, 0, 0); | 4145 | int ret; |
4085 | 4146 | ||
4147 | perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); | ||
4148 | ret = perf_output_begin(&handle, event, | ||
4149 | mmap_event->event_id.header.size, 0, 0); | ||
4086 | if (ret) | 4150 | if (ret) |
4087 | return; | 4151 | goto out; |
4088 | 4152 | ||
4089 | mmap_event->event_id.pid = perf_event_pid(event, current); | 4153 | mmap_event->event_id.pid = perf_event_pid(event, current); |
4090 | mmap_event->event_id.tid = perf_event_tid(event, current); | 4154 | mmap_event->event_id.tid = perf_event_tid(event, current); |
@@ -4092,7 +4156,12 @@ static void perf_event_mmap_output(struct perf_event *event, | |||
4092 | perf_output_put(&handle, mmap_event->event_id); | 4156 | perf_output_put(&handle, mmap_event->event_id); |
4093 | perf_output_copy(&handle, mmap_event->file_name, | 4157 | perf_output_copy(&handle, mmap_event->file_name, |
4094 | mmap_event->file_size); | 4158 | mmap_event->file_size); |
4159 | |||
4160 | perf_event__output_id_sample(event, &handle, &sample); | ||
4161 | |||
4095 | perf_output_end(&handle); | 4162 | perf_output_end(&handle); |
4163 | out: | ||
4164 | mmap_event->event_id.header.size = size; | ||
4096 | } | 4165 | } |
4097 | 4166 | ||
4098 | static int perf_event_mmap_match(struct perf_event *event, | 4167 | static int perf_event_mmap_match(struct perf_event *event, |
@@ -4245,6 +4314,7 @@ void perf_event_mmap(struct vm_area_struct *vma) | |||
4245 | static void perf_log_throttle(struct perf_event *event, int enable) | 4314 | static void perf_log_throttle(struct perf_event *event, int enable) |
4246 | { | 4315 | { |
4247 | struct perf_output_handle handle; | 4316 | struct perf_output_handle handle; |
4317 | struct perf_sample_data sample; | ||
4248 | int ret; | 4318 | int ret; |
4249 | 4319 | ||
4250 | struct { | 4320 | struct { |
@@ -4266,11 +4336,15 @@ static void perf_log_throttle(struct perf_event *event, int enable) | |||
4266 | if (enable) | 4336 | if (enable) |
4267 | throttle_event.header.type = PERF_RECORD_UNTHROTTLE; | 4337 | throttle_event.header.type = PERF_RECORD_UNTHROTTLE; |
4268 | 4338 | ||
4269 | ret = perf_output_begin(&handle, event, sizeof(throttle_event), 1, 0); | 4339 | perf_event_header__init_id(&throttle_event.header, &sample, event); |
4340 | |||
4341 | ret = perf_output_begin(&handle, event, | ||
4342 | throttle_event.header.size, 1, 0); | ||
4270 | if (ret) | 4343 | if (ret) |
4271 | return; | 4344 | return; |
4272 | 4345 | ||
4273 | perf_output_put(&handle, throttle_event); | 4346 | perf_output_put(&handle, throttle_event); |
4347 | perf_event__output_id_sample(event, &handle, &sample); | ||
4274 | perf_output_end(&handle); | 4348 | perf_output_end(&handle); |
4275 | } | 4349 | } |
4276 | 4350 | ||