diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-06-25 05:27:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-25 15:39:08 -0400 |
commit | e6e18ec79b023d5fe84226cef533cf0e3770ce93 (patch) | |
tree | 6fc1bd9afd21454864abe2aec6a0e35e17d47f04 | |
parent | bfbd3381e63aa2a14c6706afb50ce4630aa0d9a2 (diff) |
perf_counter: Rework the sample ABI
The PERF_EVENT_READ implementation made me realize we don't
actually need the sample_type int the output sample, since
we already have that in the perf_counter_attr information.
Therefore, remove the PERF_EVENT_MISC_OVERFLOW bit and the
event->type overloading, and imply put counter overflow
samples in a PERF_EVENT_SAMPLE type.
This also fixes the issue that event->type was only 32-bit
and sample_type had 64 usable bits.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | include/linux/perf_counter.h | 10 | ||||
-rw-r--r-- | kernel/perf_counter.c | 36 | ||||
-rw-r--r-- | tools/perf/builtin-annotate.c | 8 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 32 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 11 |
5 files changed, 49 insertions, 48 deletions
diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h index de70a10b5ec8..3078e23c91eb 100644 --- a/include/linux/perf_counter.h +++ b/include/linux/perf_counter.h | |||
@@ -262,7 +262,6 @@ struct perf_counter_mmap_page { | |||
262 | #define PERF_EVENT_MISC_KERNEL (1 << 0) | 262 | #define PERF_EVENT_MISC_KERNEL (1 << 0) |
263 | #define PERF_EVENT_MISC_USER (2 << 0) | 263 | #define PERF_EVENT_MISC_USER (2 << 0) |
264 | #define PERF_EVENT_MISC_HYPERVISOR (3 << 0) | 264 | #define PERF_EVENT_MISC_HYPERVISOR (3 << 0) |
265 | #define PERF_EVENT_MISC_OVERFLOW (1 << 2) | ||
266 | 265 | ||
267 | struct perf_event_header { | 266 | struct perf_event_header { |
268 | __u32 type; | 267 | __u32 type; |
@@ -348,9 +347,6 @@ enum perf_event_type { | |||
348 | PERF_EVENT_READ = 8, | 347 | PERF_EVENT_READ = 8, |
349 | 348 | ||
350 | /* | 349 | /* |
351 | * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field | ||
352 | * will be PERF_SAMPLE_* | ||
353 | * | ||
354 | * struct { | 350 | * struct { |
355 | * struct perf_event_header header; | 351 | * struct perf_event_header header; |
356 | * | 352 | * |
@@ -358,8 +354,9 @@ enum perf_event_type { | |||
358 | * { u32 pid, tid; } && PERF_SAMPLE_TID | 354 | * { u32 pid, tid; } && PERF_SAMPLE_TID |
359 | * { u64 time; } && PERF_SAMPLE_TIME | 355 | * { u64 time; } && PERF_SAMPLE_TIME |
360 | * { u64 addr; } && PERF_SAMPLE_ADDR | 356 | * { u64 addr; } && PERF_SAMPLE_ADDR |
361 | * { u64 config; } && PERF_SAMPLE_CONFIG | 357 | * { u64 id; } && PERF_SAMPLE_ID |
362 | * { u32 cpu, res; } && PERF_SAMPLE_CPU | 358 | * { u32 cpu, res; } && PERF_SAMPLE_CPU |
359 | * { u64 period; } && PERF_SAMPLE_PERIOD | ||
363 | * | 360 | * |
364 | * { u64 nr; | 361 | * { u64 nr; |
365 | * { u64 id, val; } cnt[nr]; } && PERF_SAMPLE_GROUP | 362 | * { u64 id, val; } cnt[nr]; } && PERF_SAMPLE_GROUP |
@@ -368,6 +365,9 @@ enum perf_event_type { | |||
368 | * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN | 365 | * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN |
369 | * }; | 366 | * }; |
370 | */ | 367 | */ |
368 | PERF_EVENT_SAMPLE = 9, | ||
369 | |||
370 | PERF_EVENT_MAX, /* non-ABI */ | ||
371 | }; | 371 | }; |
372 | 372 | ||
373 | enum perf_callchain_context { | 373 | enum perf_callchain_context { |
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 385ca51c6e60..f2f232696587 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -2575,15 +2575,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
2575 | u32 cpu, reserved; | 2575 | u32 cpu, reserved; |
2576 | } cpu_entry; | 2576 | } cpu_entry; |
2577 | 2577 | ||
2578 | header.type = 0; | 2578 | header.type = PERF_EVENT_SAMPLE; |
2579 | header.size = sizeof(header); | 2579 | header.size = sizeof(header); |
2580 | 2580 | ||
2581 | header.misc = PERF_EVENT_MISC_OVERFLOW; | 2581 | header.misc = 0; |
2582 | header.misc |= perf_misc_flags(data->regs); | 2582 | header.misc |= perf_misc_flags(data->regs); |
2583 | 2583 | ||
2584 | if (sample_type & PERF_SAMPLE_IP) { | 2584 | if (sample_type & PERF_SAMPLE_IP) { |
2585 | ip = perf_instruction_pointer(data->regs); | 2585 | ip = perf_instruction_pointer(data->regs); |
2586 | header.type |= PERF_SAMPLE_IP; | ||
2587 | header.size += sizeof(ip); | 2586 | header.size += sizeof(ip); |
2588 | } | 2587 | } |
2589 | 2588 | ||
@@ -2592,7 +2591,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
2592 | tid_entry.pid = perf_counter_pid(counter, current); | 2591 | tid_entry.pid = perf_counter_pid(counter, current); |
2593 | tid_entry.tid = perf_counter_tid(counter, current); | 2592 | tid_entry.tid = perf_counter_tid(counter, current); |
2594 | 2593 | ||
2595 | header.type |= PERF_SAMPLE_TID; | ||
2596 | header.size += sizeof(tid_entry); | 2594 | header.size += sizeof(tid_entry); |
2597 | } | 2595 | } |
2598 | 2596 | ||
@@ -2602,34 +2600,25 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
2602 | */ | 2600 | */ |
2603 | time = sched_clock(); | 2601 | time = sched_clock(); |
2604 | 2602 | ||
2605 | header.type |= PERF_SAMPLE_TIME; | ||
2606 | header.size += sizeof(u64); | 2603 | header.size += sizeof(u64); |
2607 | } | 2604 | } |
2608 | 2605 | ||
2609 | if (sample_type & PERF_SAMPLE_ADDR) { | 2606 | if (sample_type & PERF_SAMPLE_ADDR) |
2610 | header.type |= PERF_SAMPLE_ADDR; | ||
2611 | header.size += sizeof(u64); | 2607 | header.size += sizeof(u64); |
2612 | } | ||
2613 | 2608 | ||
2614 | if (sample_type & PERF_SAMPLE_ID) { | 2609 | if (sample_type & PERF_SAMPLE_ID) |
2615 | header.type |= PERF_SAMPLE_ID; | ||
2616 | header.size += sizeof(u64); | 2610 | header.size += sizeof(u64); |
2617 | } | ||
2618 | 2611 | ||
2619 | if (sample_type & PERF_SAMPLE_CPU) { | 2612 | if (sample_type & PERF_SAMPLE_CPU) { |
2620 | header.type |= PERF_SAMPLE_CPU; | ||
2621 | header.size += sizeof(cpu_entry); | 2613 | header.size += sizeof(cpu_entry); |
2622 | 2614 | ||
2623 | cpu_entry.cpu = raw_smp_processor_id(); | 2615 | cpu_entry.cpu = raw_smp_processor_id(); |
2624 | } | 2616 | } |
2625 | 2617 | ||
2626 | if (sample_type & PERF_SAMPLE_PERIOD) { | 2618 | if (sample_type & PERF_SAMPLE_PERIOD) |
2627 | header.type |= PERF_SAMPLE_PERIOD; | ||
2628 | header.size += sizeof(u64); | 2619 | header.size += sizeof(u64); |
2629 | } | ||
2630 | 2620 | ||
2631 | if (sample_type & PERF_SAMPLE_GROUP) { | 2621 | if (sample_type & PERF_SAMPLE_GROUP) { |
2632 | header.type |= PERF_SAMPLE_GROUP; | ||
2633 | header.size += sizeof(u64) + | 2622 | header.size += sizeof(u64) + |
2634 | counter->nr_siblings * sizeof(group_entry); | 2623 | counter->nr_siblings * sizeof(group_entry); |
2635 | } | 2624 | } |
@@ -2639,10 +2628,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
2639 | 2628 | ||
2640 | if (callchain) { | 2629 | if (callchain) { |
2641 | callchain_size = (1 + callchain->nr) * sizeof(u64); | 2630 | callchain_size = (1 + callchain->nr) * sizeof(u64); |
2642 | |||
2643 | header.type |= PERF_SAMPLE_CALLCHAIN; | ||
2644 | header.size += callchain_size; | 2631 | header.size += callchain_size; |
2645 | } | 2632 | } else |
2633 | header.size += sizeof(u64); | ||
2646 | } | 2634 | } |
2647 | 2635 | ||
2648 | ret = perf_output_begin(&handle, counter, header.size, nmi, 1); | 2636 | ret = perf_output_begin(&handle, counter, header.size, nmi, 1); |
@@ -2693,8 +2681,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, | |||
2693 | } | 2681 | } |
2694 | } | 2682 | } |
2695 | 2683 | ||
2696 | if (callchain) | 2684 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { |
2697 | perf_output_copy(&handle, callchain, callchain_size); | 2685 | if (callchain) |
2686 | perf_output_copy(&handle, callchain, callchain_size); | ||
2687 | else { | ||
2688 | u64 nr = 0; | ||
2689 | perf_output_put(&handle, nr); | ||
2690 | } | ||
2691 | } | ||
2698 | 2692 | ||
2699 | perf_output_end(&handle); | 2693 | perf_output_end(&handle); |
2700 | } | 2694 | } |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7e58e3ad1508..722c0f54e549 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -855,7 +855,7 @@ static unsigned long total = 0, | |||
855 | total_unknown = 0; | 855 | total_unknown = 0; |
856 | 856 | ||
857 | static int | 857 | static int |
858 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | 858 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) |
859 | { | 859 | { |
860 | char level; | 860 | char level; |
861 | int show = 0; | 861 | int show = 0; |
@@ -1013,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head) | |||
1013 | static int | 1013 | static int |
1014 | process_event(event_t *event, unsigned long offset, unsigned long head) | 1014 | process_event(event_t *event, unsigned long offset, unsigned long head) |
1015 | { | 1015 | { |
1016 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) | ||
1017 | return process_overflow_event(event, offset, head); | ||
1018 | |||
1019 | switch (event->header.type) { | 1016 | switch (event->header.type) { |
1017 | case PERF_EVENT_SAMPLE: | ||
1018 | return process_sample_event(event, offset, head); | ||
1019 | |||
1020 | case PERF_EVENT_MMAP: | 1020 | case PERF_EVENT_MMAP: |
1021 | return process_mmap_event(event, offset, head); | 1021 | return process_mmap_event(event, offset, head); |
1022 | 1022 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index e575f3039766..ec5361c67bf5 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -53,6 +53,8 @@ static regex_t parent_regex; | |||
53 | 53 | ||
54 | static int exclude_other = 1; | 54 | static int exclude_other = 1; |
55 | 55 | ||
56 | static u64 sample_type; | ||
57 | |||
56 | struct ip_event { | 58 | struct ip_event { |
57 | struct perf_event_header header; | 59 | struct perf_event_header header; |
58 | u64 ip; | 60 | u64 ip; |
@@ -1135,7 +1137,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) | |||
1135 | } | 1137 | } |
1136 | 1138 | ||
1137 | static int | 1139 | static int |
1138 | process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | 1140 | process_sample_event(event_t *event, unsigned long offset, unsigned long head) |
1139 | { | 1141 | { |
1140 | char level; | 1142 | char level; |
1141 | int show = 0; | 1143 | int show = 0; |
@@ -1147,12 +1149,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
1147 | void *more_data = event->ip.__more_data; | 1149 | void *more_data = event->ip.__more_data; |
1148 | struct ip_callchain *chain = NULL; | 1150 | struct ip_callchain *chain = NULL; |
1149 | 1151 | ||
1150 | if (event->header.type & PERF_SAMPLE_PERIOD) { | 1152 | if (sample_type & PERF_SAMPLE_PERIOD) { |
1151 | period = *(u64 *)more_data; | 1153 | period = *(u64 *)more_data; |
1152 | more_data += sizeof(u64); | 1154 | more_data += sizeof(u64); |
1153 | } | 1155 | } |
1154 | 1156 | ||
1155 | dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", | 1157 | dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n", |
1156 | (void *)(offset + head), | 1158 | (void *)(offset + head), |
1157 | (void *)(long)(event->header.size), | 1159 | (void *)(long)(event->header.size), |
1158 | event->header.misc, | 1160 | event->header.misc, |
@@ -1160,7 +1162,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) | |||
1160 | (void *)(long)ip, | 1162 | (void *)(long)ip, |
1161 | (long long)period); | 1163 | (long long)period); |
1162 | 1164 | ||
1163 | if (event->header.type & PERF_SAMPLE_CALLCHAIN) { | 1165 | if (sample_type & PERF_SAMPLE_CALLCHAIN) { |
1164 | int i; | 1166 | int i; |
1165 | 1167 | ||
1166 | chain = (void *)more_data; | 1168 | chain = (void *)more_data; |
@@ -1352,10 +1354,10 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1352 | { | 1354 | { |
1353 | trace_event(event); | 1355 | trace_event(event); |
1354 | 1356 | ||
1355 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) | ||
1356 | return process_overflow_event(event, offset, head); | ||
1357 | |||
1358 | switch (event->header.type) { | 1357 | switch (event->header.type) { |
1358 | case PERF_EVENT_SAMPLE: | ||
1359 | return process_sample_event(event, offset, head); | ||
1360 | |||
1359 | case PERF_EVENT_MMAP: | 1361 | case PERF_EVENT_MMAP: |
1360 | return process_mmap_event(event, offset, head); | 1362 | return process_mmap_event(event, offset, head); |
1361 | 1363 | ||
@@ -1388,18 +1390,21 @@ process_event(event_t *event, unsigned long offset, unsigned long head) | |||
1388 | 1390 | ||
1389 | static struct perf_header *header; | 1391 | static struct perf_header *header; |
1390 | 1392 | ||
1391 | static int perf_header__has_sample(u64 sample_mask) | 1393 | static u64 perf_header__sample_type(void) |
1392 | { | 1394 | { |
1395 | u64 sample_type = 0; | ||
1393 | int i; | 1396 | int i; |
1394 | 1397 | ||
1395 | for (i = 0; i < header->attrs; i++) { | 1398 | for (i = 0; i < header->attrs; i++) { |
1396 | struct perf_header_attr *attr = header->attr[i]; | 1399 | struct perf_header_attr *attr = header->attr[i]; |
1397 | 1400 | ||
1398 | if (!(attr->attr.sample_type & sample_mask)) | 1401 | if (!sample_type) |
1399 | return 0; | 1402 | sample_type = attr->attr.sample_type; |
1403 | else if (sample_type != attr->attr.sample_type) | ||
1404 | die("non matching sample_type"); | ||
1400 | } | 1405 | } |
1401 | 1406 | ||
1402 | return 1; | 1407 | return sample_type; |
1403 | } | 1408 | } |
1404 | 1409 | ||
1405 | static int __cmd_report(void) | 1410 | static int __cmd_report(void) |
@@ -1437,8 +1442,9 @@ static int __cmd_report(void) | |||
1437 | header = perf_header__read(input); | 1442 | header = perf_header__read(input); |
1438 | head = header->data_offset; | 1443 | head = header->data_offset; |
1439 | 1444 | ||
1440 | if (sort__has_parent && | 1445 | sample_type = perf_header__sample_type(); |
1441 | !perf_header__has_sample(PERF_SAMPLE_CALLCHAIN)) { | 1446 | |
1447 | if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { | ||
1442 | fprintf(stderr, "selected --sort parent, but no callchain data\n"); | 1448 | fprintf(stderr, "selected --sort parent, but no callchain data\n"); |
1443 | exit(-1); | 1449 | exit(-1); |
1444 | } | 1450 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5352b5e352ed..cf0d21f1ae10 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -392,11 +392,11 @@ static void record_ip(u64 ip, int counter) | |||
392 | samples--; | 392 | samples--; |
393 | } | 393 | } |
394 | 394 | ||
395 | static void process_event(u64 ip, int counter) | 395 | static void process_event(u64 ip, int counter, int user) |
396 | { | 396 | { |
397 | samples++; | 397 | samples++; |
398 | 398 | ||
399 | if (ip < min_ip || ip > max_ip) { | 399 | if (user) { |
400 | userspace_samples++; | 400 | userspace_samples++; |
401 | return; | 401 | return; |
402 | } | 402 | } |
@@ -509,9 +509,10 @@ static void mmap_read_counter(struct mmap_data *md) | |||
509 | 509 | ||
510 | old += size; | 510 | old += size; |
511 | 511 | ||
512 | if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { | 512 | if (event->header.type == PERF_EVENT_SAMPLE) { |
513 | if (event->header.type & PERF_SAMPLE_IP) | 513 | int user = |
514 | process_event(event->ip.ip, md->counter); | 514 | (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER; |
515 | process_event(event->ip.ip, md->counter, user); | ||
515 | } | 516 | } |
516 | } | 517 | } |
517 | 518 | ||