aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_event.c
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-12-04 20:02:20 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-12-04 20:02:20 -0500
commitc980d1091810df13f21aabbce545fd98f545bbf7 (patch)
treeccf26c6f97ac4965dee6daa7a91dde6b4108b94e /kernel/perf_event.c
parent6844c09d849aeb00e8ddfe9525e8567a531c22d0 (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/perf_event.c')
-rw-r--r--kernel/perf_event.c108
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
3391static void perf_event_header__init_id(struct perf_event_header *header, 3391static 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
3421static 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
3429static 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
3450static 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
3421int perf_output_begin(struct perf_output_handle *handle, 3458int 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);
3884out:
3885 task_event->event_id.header.size = size;
3835} 3886}
3836 3887
3837static int perf_event_task_match(struct perf_event *event) 3888static 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);
4019out:
4020 comm_event->event_id.header.size = size;
3960} 4021}
3961 4022
3962static int perf_event_comm_match(struct perf_event *event) 4023static 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);
4163out:
4164 mmap_event->event_id.header.size = size;
4096} 4165}
4097 4166
4098static int perf_event_mmap_match(struct perf_event *event, 4167static int perf_event_mmap_match(struct perf_event *event,
@@ -4245,6 +4314,7 @@ void perf_event_mmap(struct vm_area_struct *vma)
4245static void perf_log_throttle(struct perf_event *event, int enable) 4314static 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