diff options
| -rw-r--r-- | include/linux/perf_counter.h | 15 | ||||
| -rw-r--r-- | kernel/perf_counter.c | 92 | ||||
| -rw-r--r-- | tools/perf/builtin-annotate.c | 24 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 24 |
4 files changed, 35 insertions, 120 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index 5e970c7d3fd5..bd15d7a5f5ce 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
| @@ -120,8 +120,9 @@ enum perf_counter_sample_format { | |||
| 120 | PERF_SAMPLE_ID = 1U << 6, | 120 | PERF_SAMPLE_ID = 1U << 6, |
| 121 | PERF_SAMPLE_CPU = 1U << 7, | 121 | PERF_SAMPLE_CPU = 1U << 7, |
| 122 | PERF_SAMPLE_PERIOD = 1U << 8, | 122 | PERF_SAMPLE_PERIOD = 1U << 8, |
| 123 | PERF_SAMPLE_STREAM_ID = 1U << 9, | ||
| 123 | 124 | ||
| 124 | PERF_SAMPLE_MAX = 1U << 9, /* non-ABI */ | 125 | PERF_SAMPLE_MAX = 1U << 10, /* non-ABI */ |
| 125 | }; | 126 | }; |
| 126 | 127 | ||
| 127 | /* | 128 | /* |
| @@ -312,16 +313,7 @@ enum perf_event_type { | |||
| 312 | * struct perf_event_header header; | 313 | * struct perf_event_header header; |
| 313 | * u64 time; | 314 | * u64 time; |
| 314 | * u64 id; | 315 | * u64 id; |
| 315 | * u64 sample_period; | 316 | * u64 stream_id; |
| 316 | * }; | ||
| 317 | */ | ||
| 318 | PERF_EVENT_PERIOD = 4, | ||
| 319 | |||
| 320 | /* | ||
| 321 | * struct { | ||
| 322 | * struct perf_event_header header; | ||
| 323 | * u64 time; | ||
| 324 | * u64 id; | ||
| 325 | * }; | 317 | * }; |
| 326 | */ | 318 | */ |
| 327 | PERF_EVENT_THROTTLE = 5, | 319 | PERF_EVENT_THROTTLE = 5, |
| @@ -356,6 +348,7 @@ enum perf_event_type { | |||
| 356 | * { u64 time; } && PERF_SAMPLE_TIME | 348 | * { u64 time; } && PERF_SAMPLE_TIME |
| 357 | * { u64 addr; } && PERF_SAMPLE_ADDR | 349 | * { u64 addr; } && PERF_SAMPLE_ADDR |
| 358 | * { u64 id; } && PERF_SAMPLE_ID | 350 | * { u64 id; } && PERF_SAMPLE_ID |
| 351 | * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID | ||
| 359 | * { u32 cpu, res; } && PERF_SAMPLE_CPU | 352 | * { u32 cpu, res; } && PERF_SAMPLE_CPU |
| 360 | * { u64 period; } && PERF_SAMPLE_PERIOD | 353 | * { u64 period; } && PERF_SAMPLE_PERIOD |
| 361 | * | 354 | * |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index e1d6a3aa1333..7530588fa5c5 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
| @@ -155,6 +155,20 @@ static void unclone_ctx(struct perf_counter_context *ctx) | |||
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /* | 157 | /* |
| 158 | * If we inherit counters we want to return the parent counter id | ||
| 159 | * to userspace. | ||
| 160 | */ | ||
| 161 | static u64 primary_counter_id(struct perf_counter *counter) | ||
| 162 | { | ||
| 163 | u64 id = counter->id; | ||
| 164 | |||
| 165 | if (counter->parent) | ||
| 166 | id = counter->parent->id; | ||
| 167 | |||
| 168 | return id; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 158 | * Get the perf_counter_context for a task and lock it. | 172 | * Get the perf_counter_context for a task and lock it. |
| 159 | * This has to cope with with the fact that until it is locked, | 173 | * This has to cope with with the fact that until it is locked, |
| 160 | * the context could get moved to another task. | 174 | * the context could get moved to another task. |
| @@ -1296,7 +1310,6 @@ static void perf_counter_cpu_sched_in(struct perf_cpu_context *cpuctx, int cpu) | |||
| 1296 | #define MAX_INTERRUPTS (~0ULL) | 1310 | #define MAX_INTERRUPTS (~0ULL) |
| 1297 | 1311 | ||
| 1298 | static void perf_log_throttle(struct perf_counter *counter, int enable); | 1312 | static void perf_log_throttle(struct perf_counter *counter, int enable); |
| 1299 | static void perf_log_period(struct perf_counter *counter, u64 period); | ||
| 1300 | 1313 | ||
| 1301 | static void perf_adjust_period(struct perf_counter *counter, u64 events) | 1314 | static void perf_adjust_period(struct perf_counter *counter, u64 events) |
| 1302 | { | 1315 | { |
| @@ -1315,8 +1328,6 @@ static void perf_adjust_period(struct perf_counter *counter, u64 events) | |||
| 1315 | if (!sample_period) | 1328 | if (!sample_period) |
| 1316 | sample_period = 1; | 1329 | sample_period = 1; |
| 1317 | 1330 | ||
| 1318 | perf_log_period(counter, sample_period); | ||
| 1319 | |||
| 1320 | hwc->sample_period = sample_period; | 1331 | hwc->sample_period = sample_period; |
| 1321 | } | 1332 | } |
| 1322 | 1333 | ||
| @@ -1705,7 +1716,7 @@ perf_read_hw(struct perf_counter *counter, char __user *buf, size_t count) | |||
| 1705 | values[n++] = counter->total_time_running + | 1716 | values[n++] = counter->total_time_running + |
| 1706 | atomic64_read(&counter->child_total_time_running); | 1717 | atomic64_read(&counter->child_total_time_running); |
| 1707 | if (counter->attr.read_format & PERF_FORMAT_ID) | 1718 | if (counter->attr.read_format & PERF_FORMAT_ID) |
| 1708 | values[n++] = counter->id; | 1719 | values[n++] = primary_counter_id(counter); |
| 1709 | mutex_unlock(&counter->child_mutex); | 1720 | mutex_unlock(&counter->child_mutex); |
| 1710 | 1721 | ||
| 1711 | if (count < n * sizeof(u64)) | 1722 | if (count < n * sizeof(u64)) |
| @@ -1812,8 +1823,6 @@ static int perf_counter_period(struct perf_counter *counter, u64 __user *arg) | |||
| 1812 | 1823 | ||
| 1813 | counter->attr.sample_freq = value; | 1824 | counter->attr.sample_freq = value; |
| 1814 | } else { | 1825 | } else { |
| 1815 | perf_log_period(counter, value); | ||
| 1816 | |||
| 1817 | counter->attr.sample_period = value; | 1826 | counter->attr.sample_period = value; |
| 1818 | counter->hw.sample_period = value; | 1827 | counter->hw.sample_period = value; |
| 1819 | } | 1828 | } |
| @@ -2662,6 +2671,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
| 2662 | if (sample_type & PERF_SAMPLE_ID) | 2671 | if (sample_type & PERF_SAMPLE_ID) |
| 2663 | header.size += sizeof(u64); | 2672 | header.size += sizeof(u64); |
| 2664 | 2673 | ||
| 2674 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 2675 | header.size += sizeof(u64); | ||
| 2676 | |||
| 2665 | if (sample_type & PERF_SAMPLE_CPU) { | 2677 | if (sample_type & PERF_SAMPLE_CPU) { |
| 2666 | header.size += sizeof(cpu_entry); | 2678 | header.size += sizeof(cpu_entry); |
| 2667 | 2679 | ||
| @@ -2705,7 +2717,13 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
| 2705 | if (sample_type & PERF_SAMPLE_ADDR) | 2717 | if (sample_type & PERF_SAMPLE_ADDR) |
| 2706 | perf_output_put(&handle, data->addr); | 2718 | perf_output_put(&handle, data->addr); |
| 2707 | 2719 | ||
| 2708 | if (sample_type & PERF_SAMPLE_ID) | 2720 | if (sample_type & PERF_SAMPLE_ID) { |
| 2721 | u64 id = primary_counter_id(counter); | ||
| 2722 | |||
| 2723 | perf_output_put(&handle, id); | ||
| 2724 | } | ||
| 2725 | |||
| 2726 | if (sample_type & PERF_SAMPLE_STREAM_ID) | ||
| 2709 | perf_output_put(&handle, counter->id); | 2727 | perf_output_put(&handle, counter->id); |
| 2710 | 2728 | ||
| 2711 | if (sample_type & PERF_SAMPLE_CPU) | 2729 | if (sample_type & PERF_SAMPLE_CPU) |
| @@ -2728,7 +2746,7 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
| 2728 | if (sub != counter) | 2746 | if (sub != counter) |
| 2729 | sub->pmu->read(sub); | 2747 | sub->pmu->read(sub); |
| 2730 | 2748 | ||
| 2731 | group_entry.id = sub->id; | 2749 | group_entry.id = primary_counter_id(sub); |
| 2732 | group_entry.counter = atomic64_read(&sub->count); | 2750 | group_entry.counter = atomic64_read(&sub->count); |
| 2733 | 2751 | ||
| 2734 | perf_output_put(&handle, group_entry); | 2752 | perf_output_put(&handle, group_entry); |
| @@ -2788,15 +2806,8 @@ perf_counter_read_event(struct perf_counter *counter, | |||
| 2788 | } | 2806 | } |
| 2789 | 2807 | ||
| 2790 | if (counter->attr.read_format & PERF_FORMAT_ID) { | 2808 | if (counter->attr.read_format & PERF_FORMAT_ID) { |
| 2791 | u64 id; | ||
| 2792 | |||
| 2793 | event.header.size += sizeof(u64); | 2809 | event.header.size += sizeof(u64); |
| 2794 | if (counter->parent) | 2810 | event.format[i++] = primary_counter_id(counter); |
| 2795 | id = counter->parent->id; | ||
| 2796 | else | ||
| 2797 | id = counter->id; | ||
| 2798 | |||
| 2799 | event.format[i++] = id; | ||
| 2800 | } | 2811 | } |
| 2801 | 2812 | ||
| 2802 | ret = perf_output_begin(&handle, counter, event.header.size, 0, 0); | 2813 | ret = perf_output_begin(&handle, counter, event.header.size, 0, 0); |
| @@ -3191,49 +3202,6 @@ void __perf_counter_mmap(struct vm_area_struct *vma) | |||
| 3191 | } | 3202 | } |
| 3192 | 3203 | ||
| 3193 | /* | 3204 | /* |
| 3194 | * Log sample_period changes so that analyzing tools can re-normalize the | ||
| 3195 | * event flow. | ||
| 3196 | */ | ||
| 3197 | |||
| 3198 | struct freq_event { | ||
| 3199 | struct perf_event_header header; | ||
| 3200 | u64 time; | ||
| 3201 | u64 id; | ||
| 3202 | u64 period; | ||
| 3203 | }; | ||
| 3204 | |||
| 3205 | static void perf_log_period(struct perf_counter *counter, u64 period) | ||
| 3206 | { | ||
| 3207 | struct perf_output_handle handle; | ||
| 3208 | struct freq_event event; | ||
| 3209 | int ret; | ||
| 3210 | |||
| 3211 | if (counter->hw.sample_period == period) | ||
| 3212 | return; | ||
| 3213 | |||
| 3214 | if (counter->attr.sample_type & PERF_SAMPLE_PERIOD) | ||
| 3215 | return; | ||
| 3216 | |||
| 3217 | event = (struct freq_event) { | ||
| 3218 | .header = { | ||
| 3219 | .type = PERF_EVENT_PERIOD, | ||
| 3220 | .misc = 0, | ||
| 3221 | .size = sizeof(event), | ||
| 3222 | }, | ||
| 3223 | .time = sched_clock(), | ||
| 3224 | .id = counter->id, | ||
| 3225 | .period = period, | ||
| 3226 | }; | ||
| 3227 | |||
| 3228 | ret = perf_output_begin(&handle, counter, sizeof(event), 1, 0); | ||
| 3229 | if (ret) | ||
| 3230 | return; | ||
| 3231 | |||
| 3232 | perf_output_put(&handle, event); | ||
| 3233 | perf_output_end(&handle); | ||
| 3234 | } | ||
| 3235 | |||
| 3236 | /* | ||
| 3237 | * IRQ throttle logging | 3205 | * IRQ throttle logging |
| 3238 | */ | 3206 | */ |
| 3239 | 3207 | ||
| @@ -3246,14 +3214,16 @@ static void perf_log_throttle(struct perf_counter *counter, int enable) | |||
| 3246 | struct perf_event_header header; | 3214 | struct perf_event_header header; |
| 3247 | u64 time; | 3215 | u64 time; |
| 3248 | u64 id; | 3216 | u64 id; |
| 3217 | u64 stream_id; | ||
| 3249 | } throttle_event = { | 3218 | } throttle_event = { |
| 3250 | .header = { | 3219 | .header = { |
| 3251 | .type = PERF_EVENT_THROTTLE + 1, | 3220 | .type = PERF_EVENT_THROTTLE + 1, |
| 3252 | .misc = 0, | 3221 | .misc = 0, |
| 3253 | .size = sizeof(throttle_event), | 3222 | .size = sizeof(throttle_event), |
| 3254 | }, | 3223 | }, |
| 3255 | .time = sched_clock(), | 3224 | .time = sched_clock(), |
| 3256 | .id = counter->id, | 3225 | .id = primary_counter_id(counter), |
| 3226 | .stream_id = counter->id, | ||
| 3257 | }; | 3227 | }; |
| 3258 | 3228 | ||
| 3259 | ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 1, 0); | 3229 | ret = perf_output_begin(&handle, counter, sizeof(throttle_event), 1, 0); |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5f9eefecc574..1dba568e1941 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -74,20 +74,12 @@ struct fork_event { | |||
| 74 | u32 pid, ppid; | 74 | u32 pid, ppid; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | struct period_event { | ||
| 78 | struct perf_event_header header; | ||
| 79 | u64 time; | ||
| 80 | u64 id; | ||
| 81 | u64 sample_period; | ||
| 82 | }; | ||
| 83 | |||
| 84 | typedef union event_union { | 77 | typedef union event_union { |
| 85 | struct perf_event_header header; | 78 | struct perf_event_header header; |
| 86 | struct ip_event ip; | 79 | struct ip_event ip; |
| 87 | struct mmap_event mmap; | 80 | struct mmap_event mmap; |
| 88 | struct comm_event comm; | 81 | struct comm_event comm; |
| 89 | struct fork_event fork; | 82 | struct fork_event fork; |
| 90 | struct period_event period; | ||
| 91 | } event_t; | 83 | } event_t; |
| 92 | 84 | ||
| 93 | 85 | ||
| @@ -998,19 +990,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 998 | } | 990 | } |
| 999 | 991 | ||
| 1000 | static int | 992 | static int |
| 1001 | process_period_event(event_t *event, unsigned long offset, unsigned long head) | ||
| 1002 | { | ||
| 1003 | dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", | ||
| 1004 | (void *)(offset + head), | ||
| 1005 | (void *)(long)(event->header.size), | ||
| 1006 | event->period.time, | ||
| 1007 | event->period.id, | ||
| 1008 | event->period.sample_period); | ||
| 1009 | |||
| 1010 | return 0; | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static int | ||
| 1014 | process_event(event_t *event, unsigned long offset, unsigned long head) | 993 | process_event(event_t *event, unsigned long offset, unsigned long head) |
| 1015 | { | 994 | { |
| 1016 | switch (event->header.type) { | 995 | switch (event->header.type) { |
| @@ -1025,9 +1004,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1025 | 1004 | ||
| 1026 | case PERF_EVENT_FORK: | 1005 | case PERF_EVENT_FORK: |
| 1027 | return process_fork_event(event, offset, head); | 1006 | return process_fork_event(event, offset, head); |
| 1028 | |||
| 1029 | case PERF_EVENT_PERIOD: | ||
| 1030 | return process_period_event(event, offset, head); | ||
| 1031 | /* | 1007 | /* |
| 1032 | * We dont process them right now but they are fine: | 1008 | * We dont process them right now but they are fine: |
| 1033 | */ | 1009 | */ |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index a118bc77286d..b20a4b6e31b7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -101,13 +101,6 @@ struct fork_event { | |||
| 101 | u32 pid, ppid; | 101 | u32 pid, ppid; |
| 102 | }; | 102 | }; |
| 103 | 103 | ||
| 104 | struct period_event { | ||
| 105 | struct perf_event_header header; | ||
| 106 | u64 time; | ||
| 107 | u64 id; | ||
| 108 | u64 sample_period; | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct lost_event { | 104 | struct lost_event { |
| 112 | struct perf_event_header header; | 105 | struct perf_event_header header; |
| 113 | u64 id; | 106 | u64 id; |
| @@ -127,7 +120,6 @@ typedef union event_union { | |||
| 127 | struct mmap_event mmap; | 120 | struct mmap_event mmap; |
| 128 | struct comm_event comm; | 121 | struct comm_event comm; |
| 129 | struct fork_event fork; | 122 | struct fork_event fork; |
| 130 | struct period_event period; | ||
| 131 | struct lost_event lost; | 123 | struct lost_event lost; |
| 132 | struct read_event read; | 124 | struct read_event read; |
| 133 | } event_t; | 125 | } event_t; |
| @@ -1636,19 +1628,6 @@ process_fork_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1636 | } | 1628 | } |
| 1637 | 1629 | ||
| 1638 | static int | 1630 | static int |
| 1639 | process_period_event(event_t *event, unsigned long offset, unsigned long head) | ||
| 1640 | { | ||
| 1641 | dprintf("%p [%p]: PERF_EVENT_PERIOD: time:%Ld, id:%Ld: period:%Ld\n", | ||
| 1642 | (void *)(offset + head), | ||
| 1643 | (void *)(long)(event->header.size), | ||
| 1644 | event->period.time, | ||
| 1645 | event->period.id, | ||
| 1646 | event->period.sample_period); | ||
| 1647 | |||
| 1648 | return 0; | ||
| 1649 | } | ||
| 1650 | |||
| 1651 | static int | ||
| 1652 | process_lost_event(event_t *event, unsigned long offset, unsigned long head) | 1631 | process_lost_event(event_t *event, unsigned long offset, unsigned long head) |
| 1653 | { | 1632 | { |
| 1654 | dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", | 1633 | dprintf("%p [%p]: PERF_EVENT_LOST: id:%Ld: lost:%Ld\n", |
| @@ -1729,9 +1708,6 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
| 1729 | case PERF_EVENT_FORK: | 1708 | case PERF_EVENT_FORK: |
| 1730 | return process_fork_event(event, offset, head); | 1709 | return process_fork_event(event, offset, head); |
| 1731 | 1710 | ||
| 1732 | case PERF_EVENT_PERIOD: | ||
| 1733 | return process_period_event(event, offset, head); | ||
| 1734 | |||
| 1735 | case PERF_EVENT_LOST: | 1711 | case PERF_EVENT_LOST: |
| 1736 | return process_lost_event(event, offset, head); | 1712 | return process_lost_event(event, offset, head); |
| 1737 | 1713 | ||
