aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-06-25 05:27:12 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-25 15:39:08 -0400
commite6e18ec79b023d5fe84226cef533cf0e3770ce93 (patch)
tree6fc1bd9afd21454864abe2aec6a0e35e17d47f04
parentbfbd3381e63aa2a14c6706afb50ce4630aa0d9a2 (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.h10
-rw-r--r--kernel/perf_counter.c36
-rw-r--r--tools/perf/builtin-annotate.c8
-rw-r--r--tools/perf/builtin-report.c32
-rw-r--r--tools/perf/builtin-top.c11
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
267struct perf_event_header { 266struct 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
373enum perf_callchain_context { 373enum 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
857static int 857static int
858process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 858process_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)
1013static int 1013static int
1014process_event(event_t *event, unsigned long offset, unsigned long head) 1014process_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
54static int exclude_other = 1; 54static int exclude_other = 1;
55 55
56static u64 sample_type;
57
56struct ip_event { 58struct 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
1137static int 1139static int
1138process_overflow_event(event_t *event, unsigned long offset, unsigned long head) 1140process_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
1389static struct perf_header *header; 1391static struct perf_header *header;
1390 1392
1391static int perf_header__has_sample(u64 sample_mask) 1393static 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
1405static int __cmd_report(void) 1410static 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
395static void process_event(u64 ip, int counter) 395static 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