diff options
-rw-r--r-- | include/linux/perf_event.h | 12 | ||||
-rw-r--r-- | kernel/perf_event.c | 108 |
2 files changed, 102 insertions, 18 deletions
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index b9950b1620d8..2814ead4adb8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -215,8 +215,9 @@ struct perf_event_attr { | |||
215 | */ | 215 | */ |
216 | precise_ip : 2, /* skid constraint */ | 216 | precise_ip : 2, /* skid constraint */ |
217 | mmap_data : 1, /* non-exec mmap data */ | 217 | mmap_data : 1, /* non-exec mmap data */ |
218 | sample_id_all : 1, /* sample_type all events */ | ||
218 | 219 | ||
219 | __reserved_1 : 46; | 220 | __reserved_1 : 45; |
220 | 221 | ||
221 | union { | 222 | union { |
222 | __u32 wakeup_events; /* wakeup every n events */ | 223 | __u32 wakeup_events; /* wakeup every n events */ |
@@ -327,6 +328,15 @@ struct perf_event_header { | |||
327 | enum perf_event_type { | 328 | enum perf_event_type { |
328 | 329 | ||
329 | /* | 330 | /* |
331 | * If perf_event_attr.sample_id_all is set then all event types will | ||
332 | * have the sample_type selected fields related to where/when | ||
333 | * (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID) | ||
334 | * described in PERF_RECORD_SAMPLE below, it will be stashed just after | ||
335 | * the perf_event_header and the fields already present for the existing | ||
336 | * fields, i.e. at the end of the payload. That way a newer perf.data | ||
337 | * file will be supported by older perf tools, with these new optional | ||
338 | * fields being ignored. | ||
339 | * | ||
330 | * The MMAP events record the PROT_EXEC mappings so that we can | 340 | * The MMAP events record the PROT_EXEC mappings so that we can |
331 | * correlate userspace IPs to code. They have the following structure: | 341 | * correlate userspace IPs to code. They have the following structure: |
332 | * | 342 | * |
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 | ||