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 | ||
