Commit e6e18ec7 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar

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: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <new-submission>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent bfbd3381
...@@ -262,7 +262,6 @@ struct perf_counter_mmap_page { ...@@ -262,7 +262,6 @@ struct perf_counter_mmap_page {
#define PERF_EVENT_MISC_KERNEL (1 << 0) #define PERF_EVENT_MISC_KERNEL (1 << 0)
#define PERF_EVENT_MISC_USER (2 << 0) #define PERF_EVENT_MISC_USER (2 << 0)
#define PERF_EVENT_MISC_HYPERVISOR (3 << 0) #define PERF_EVENT_MISC_HYPERVISOR (3 << 0)
#define PERF_EVENT_MISC_OVERFLOW (1 << 2)
struct perf_event_header { struct perf_event_header {
__u32 type; __u32 type;
...@@ -348,9 +347,6 @@ enum perf_event_type { ...@@ -348,9 +347,6 @@ enum perf_event_type {
PERF_EVENT_READ = 8, PERF_EVENT_READ = 8,
/* /*
* When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field
* will be PERF_SAMPLE_*
*
* struct { * struct {
* struct perf_event_header header; * struct perf_event_header header;
* *
...@@ -358,8 +354,9 @@ enum perf_event_type { ...@@ -358,8 +354,9 @@ enum perf_event_type {
* { u32 pid, tid; } && PERF_SAMPLE_TID * { u32 pid, tid; } && PERF_SAMPLE_TID
* { u64 time; } && PERF_SAMPLE_TIME * { u64 time; } && PERF_SAMPLE_TIME
* { u64 addr; } && PERF_SAMPLE_ADDR * { u64 addr; } && PERF_SAMPLE_ADDR
* { u64 config; } && PERF_SAMPLE_CONFIG * { u64 id; } && PERF_SAMPLE_ID
* { u32 cpu, res; } && PERF_SAMPLE_CPU * { u32 cpu, res; } && PERF_SAMPLE_CPU
* { u64 period; } && PERF_SAMPLE_PERIOD
* *
* { u64 nr; * { u64 nr;
* { u64 id, val; } cnt[nr]; } && PERF_SAMPLE_GROUP * { u64 id, val; } cnt[nr]; } && PERF_SAMPLE_GROUP
...@@ -368,6 +365,9 @@ enum perf_event_type { ...@@ -368,6 +365,9 @@ enum perf_event_type {
* u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
* }; * };
*/ */
PERF_EVENT_SAMPLE = 9,
PERF_EVENT_MAX, /* non-ABI */
}; };
enum perf_callchain_context { enum perf_callchain_context {
......
...@@ -2575,15 +2575,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, ...@@ -2575,15 +2575,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
u32 cpu, reserved; u32 cpu, reserved;
} cpu_entry; } cpu_entry;
header.type = 0; header.type = PERF_EVENT_SAMPLE;
header.size = sizeof(header); header.size = sizeof(header);
header.misc = PERF_EVENT_MISC_OVERFLOW; header.misc = 0;
header.misc |= perf_misc_flags(data->regs); header.misc |= perf_misc_flags(data->regs);
if (sample_type & PERF_SAMPLE_IP) { if (sample_type & PERF_SAMPLE_IP) {
ip = perf_instruction_pointer(data->regs); ip = perf_instruction_pointer(data->regs);
header.type |= PERF_SAMPLE_IP;
header.size += sizeof(ip); header.size += sizeof(ip);
} }
...@@ -2592,7 +2591,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, ...@@ -2592,7 +2591,6 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
tid_entry.pid = perf_counter_pid(counter, current); tid_entry.pid = perf_counter_pid(counter, current);
tid_entry.tid = perf_counter_tid(counter, current); tid_entry.tid = perf_counter_tid(counter, current);
header.type |= PERF_SAMPLE_TID;
header.size += sizeof(tid_entry); header.size += sizeof(tid_entry);
} }
...@@ -2602,34 +2600,25 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, ...@@ -2602,34 +2600,25 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
*/ */
time = sched_clock(); time = sched_clock();
header.type |= PERF_SAMPLE_TIME;
header.size += sizeof(u64); header.size += sizeof(u64);
} }
if (sample_type & PERF_SAMPLE_ADDR) { if (sample_type & PERF_SAMPLE_ADDR)
header.type |= PERF_SAMPLE_ADDR;
header.size += sizeof(u64); header.size += sizeof(u64);
}
if (sample_type & PERF_SAMPLE_ID) { if (sample_type & PERF_SAMPLE_ID)
header.type |= PERF_SAMPLE_ID;
header.size += sizeof(u64); header.size += sizeof(u64);
}
if (sample_type & PERF_SAMPLE_CPU) { if (sample_type & PERF_SAMPLE_CPU) {
header.type |= PERF_SAMPLE_CPU;
header.size += sizeof(cpu_entry); header.size += sizeof(cpu_entry);
cpu_entry.cpu = raw_smp_processor_id(); cpu_entry.cpu = raw_smp_processor_id();
} }
if (sample_type & PERF_SAMPLE_PERIOD) { if (sample_type & PERF_SAMPLE_PERIOD)
header.type |= PERF_SAMPLE_PERIOD;
header.size += sizeof(u64); header.size += sizeof(u64);
}
if (sample_type & PERF_SAMPLE_GROUP) { if (sample_type & PERF_SAMPLE_GROUP) {
header.type |= PERF_SAMPLE_GROUP;
header.size += sizeof(u64) + header.size += sizeof(u64) +
counter->nr_siblings * sizeof(group_entry); counter->nr_siblings * sizeof(group_entry);
} }
...@@ -2639,10 +2628,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi, ...@@ -2639,10 +2628,9 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
if (callchain) { if (callchain) {
callchain_size = (1 + callchain->nr) * sizeof(u64); callchain_size = (1 + callchain->nr) * sizeof(u64);
header.type |= PERF_SAMPLE_CALLCHAIN;
header.size += callchain_size; header.size += callchain_size;
} } else
header.size += sizeof(u64);
} }
ret = perf_output_begin(&handle, counter, header.size, nmi, 1); 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,8 +2681,14 @@ static void perf_counter_output(struct perf_counter *counter, int nmi,
} }
} }
if (sample_type & PERF_SAMPLE_CALLCHAIN) {
if (callchain) if (callchain)
perf_output_copy(&handle, callchain, callchain_size); perf_output_copy(&handle, callchain, callchain_size);
else {
u64 nr = 0;
perf_output_put(&handle, nr);
}
}
perf_output_end(&handle); perf_output_end(&handle);
} }
......
...@@ -855,7 +855,7 @@ static unsigned long total = 0, ...@@ -855,7 +855,7 @@ static unsigned long total = 0,
total_unknown = 0; total_unknown = 0;
static int static int
process_overflow_event(event_t *event, unsigned long offset, unsigned long head) process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{ {
char level; char level;
int show = 0; int show = 0;
...@@ -1013,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -1013,10 +1013,10 @@ process_period_event(event_t *event, unsigned long offset, unsigned long head)
static int static int
process_event(event_t *event, unsigned long offset, unsigned long head) process_event(event_t *event, unsigned long offset, unsigned long head)
{ {
if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
return process_overflow_event(event, offset, head);
switch (event->header.type) { switch (event->header.type) {
case PERF_EVENT_SAMPLE:
return process_sample_event(event, offset, head);
case PERF_EVENT_MMAP: case PERF_EVENT_MMAP:
return process_mmap_event(event, offset, head); return process_mmap_event(event, offset, head);
......
...@@ -53,6 +53,8 @@ static regex_t parent_regex; ...@@ -53,6 +53,8 @@ static regex_t parent_regex;
static int exclude_other = 1; static int exclude_other = 1;
static u64 sample_type;
struct ip_event { struct ip_event {
struct perf_event_header header; struct perf_event_header header;
u64 ip; u64 ip;
...@@ -1135,7 +1137,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event) ...@@ -1135,7 +1137,7 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)
} }
static int static int
process_overflow_event(event_t *event, unsigned long offset, unsigned long head) process_sample_event(event_t *event, unsigned long offset, unsigned long head)
{ {
char level; char level;
int show = 0; int show = 0;
...@@ -1147,12 +1149,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -1147,12 +1149,12 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
void *more_data = event->ip.__more_data; void *more_data = event->ip.__more_data;
struct ip_callchain *chain = NULL; struct ip_callchain *chain = NULL;
if (event->header.type & PERF_SAMPLE_PERIOD) { if (sample_type & PERF_SAMPLE_PERIOD) {
period = *(u64 *)more_data; period = *(u64 *)more_data;
more_data += sizeof(u64); more_data += sizeof(u64);
} }
dprintf("%p [%p]: PERF_EVENT (IP, %d): %d: %p period: %Ld\n", dprintf("%p [%p]: PERF_EVENT_SAMPLE (IP, %d): %d: %p period: %Ld\n",
(void *)(offset + head), (void *)(offset + head),
(void *)(long)(event->header.size), (void *)(long)(event->header.size),
event->header.misc, event->header.misc,
...@@ -1160,7 +1162,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -1160,7 +1162,7 @@ process_overflow_event(event_t *event, unsigned long offset, unsigned long head)
(void *)(long)ip, (void *)(long)ip,
(long long)period); (long long)period);
if (event->header.type & PERF_SAMPLE_CALLCHAIN) { if (sample_type & PERF_SAMPLE_CALLCHAIN) {
int i; int i;
chain = (void *)more_data; chain = (void *)more_data;
...@@ -1352,10 +1354,10 @@ process_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -1352,10 +1354,10 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
{ {
trace_event(event); trace_event(event);
if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
return process_overflow_event(event, offset, head);
switch (event->header.type) { switch (event->header.type) {
case PERF_EVENT_SAMPLE:
return process_sample_event(event, offset, head);
case PERF_EVENT_MMAP: case PERF_EVENT_MMAP:
return process_mmap_event(event, offset, head); return process_mmap_event(event, offset, head);
...@@ -1388,18 +1390,21 @@ process_event(event_t *event, unsigned long offset, unsigned long head) ...@@ -1388,18 +1390,21 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
static struct perf_header *header; static struct perf_header *header;
static int perf_header__has_sample(u64 sample_mask) static u64 perf_header__sample_type(void)
{ {
u64 sample_type = 0;
int i; int i;
for (i = 0; i < header->attrs; i++) { for (i = 0; i < header->attrs; i++) {
struct perf_header_attr *attr = header->attr[i]; struct perf_header_attr *attr = header->attr[i];
if (!(attr->attr.sample_type & sample_mask)) if (!sample_type)
return 0; sample_type = attr->attr.sample_type;
else if (sample_type != attr->attr.sample_type)
die("non matching sample_type");
} }
return 1; return sample_type;
} }
static int __cmd_report(void) static int __cmd_report(void)
...@@ -1437,8 +1442,9 @@ static int __cmd_report(void) ...@@ -1437,8 +1442,9 @@ static int __cmd_report(void)
header = perf_header__read(input); header = perf_header__read(input);
head = header->data_offset; head = header->data_offset;
if (sort__has_parent && sample_type = perf_header__sample_type();
!perf_header__has_sample(PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
fprintf(stderr, "selected --sort parent, but no callchain data\n"); fprintf(stderr, "selected --sort parent, but no callchain data\n");
exit(-1); exit(-1);
} }
......
...@@ -392,11 +392,11 @@ static void record_ip(u64 ip, int counter) ...@@ -392,11 +392,11 @@ static void record_ip(u64 ip, int counter)
samples--; samples--;
} }
static void process_event(u64 ip, int counter) static void process_event(u64 ip, int counter, int user)
{ {
samples++; samples++;
if (ip < min_ip || ip > max_ip) { if (user) {
userspace_samples++; userspace_samples++;
return; return;
} }
...@@ -509,9 +509,10 @@ static void mmap_read_counter(struct mmap_data *md) ...@@ -509,9 +509,10 @@ static void mmap_read_counter(struct mmap_data *md)
old += size; old += size;
if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { if (event->header.type == PERF_EVENT_SAMPLE) {
if (event->header.type & PERF_SAMPLE_IP) int user =
process_event(event->ip.ip, md->counter); (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER;
process_event(event->ip.ip, md->counter, user);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment