aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-07-21 07:19:40 -0400
committerPeter Zijlstra <a.p.zijlstra@chello.nl>2009-07-22 12:05:56 -0400
commit7f453c24b95a085fc7bd35d53b33abc4dc5a048b (patch)
tree63d2b80acb3095a3e1a56c69d20a8137a1337aed
parent573402db02746179b3f95f83a11a787501f52d0a (diff)
perf_counter: PERF_SAMPLE_ID and inherited counters
Anton noted that for inherited counters the counter-id as provided by PERF_SAMPLE_ID isn't mappable to the id found through PERF_RECORD_ID because each inherited counter gets its own id. His suggestion was to always return the parent counter id, since that is the primary counter id as exposed. However, these inherited counters have a unique identifier so that events like PERF_EVENT_PERIOD and PERF_EVENT_THROTTLE can be specific about which counter gets modified, which is important when trying to normalize the sample streams. This patch removes PERF_EVENT_PERIOD in favour of PERF_SAMPLE_PERIOD, which is more useful anyway, since changing periods became a lot more common than initially thought -- rendering PERF_EVENT_PERIOD the less useful solution (also, PERF_SAMPLE_PERIOD reports the more accurate value, since it reports the value used to trigger the overflow, whereas PERF_EVENT_PERIOD simply reports the requested period changed, which might only take effect on the next cycle). This still leaves us PERF_EVENT_THROTTLE to consider, but since that _should_ be a rare occurrence, and linking it to a primary id is the most useful bit to diagnose the problem, we introduce a PERF_SAMPLE_STREAM_ID, for those few cases where the full reconstruction is important. [Does change the ABI a little, but I see no other way out] Suggested-by: Anton Blanchard <anton@samba.org> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1248095846.15751.8781.camel@twins>
-rw-r--r--include/linux/perf_counter.h15
-rw-r--r--kernel/perf_counter.c92
-rw-r--r--tools/perf/builtin-annotate.c24
-rw-r--r--tools/perf/builtin-report.c24
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 */
161static 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
1298static void perf_log_throttle(struct perf_counter *counter, int enable); 1312static void perf_log_throttle(struct perf_counter *counter, int enable);
1299static void perf_log_period(struct perf_counter *counter, u64 period);
1300 1313
1301static void perf_adjust_period(struct perf_counter *counter, u64 events) 1314static 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
3198struct freq_event {
3199 struct perf_event_header header;
3200 u64 time;
3201 u64 id;
3202 u64 period;
3203};
3204
3205static 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
77struct period_event {
78 struct perf_event_header header;
79 u64 time;
80 u64 id;
81 u64 sample_period;
82};
83
84typedef union event_union { 77typedef 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
1000static int 992static int
1001process_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
1013static int
1014process_event(event_t *event, unsigned long offset, unsigned long head) 993process_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
104struct period_event {
105 struct perf_event_header header;
106 u64 time;
107 u64 id;
108 u64 sample_period;
109};
110
111struct lost_event { 104struct 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
1638static int 1630static int
1639process_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
1651static int
1652process_lost_event(event_t *event, unsigned long offset, unsigned long head) 1631process_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