Skip to contentSkip to conversation

hrtimer group events

RFC PATCH In review Matt Fleming 3 participants 15 messages Aug 30, 2010 – Aug 31, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover hrtimer group events

This series is an attempt to link perf group events with a hrtimer, so that when the hrtimer fires all counters in the group are sampled. The reason this functionality is needed is because some performance counters cannot generate any form of interrupts, such as on SH or the power consumption counters on x86.

Peter, I'm sending this as an RFC because I'm not convinced I've got this patch series completely right. I've run it a few times on SH and the results seem sensible, e.g. monitoring L1-dcache-load-misses has flush_dcache_all() near the top of the list, but I just wanted to get this out so that people could review it early before I go any further.

One thing worth noting is that I've essentially hijacked group events so that they only work specifically for the hrtimer case. That's probably not right, in which case, we'll need some more flags to distinguish hrtimer-backed group from non-hrtimer-backed group.

Matt Fleming (5):
perf: Check if we should exclude idle thread in perf_exclude_event()
perf: Turn the group counter values into delta values
perf: Add hrtimer code for PMI-less hardware counters
sh: Add support for sampling counters
perf: Add support for PERF_SAMPLE_READ samples

 arch/sh/kernel/perf_event.c |    3 +-
 include/linux/perf_event.h  |    4 ++
 kernel/perf_event.c         |  111 +++++++++++++++++++++++++++++++++++++++++-
 tools/perf/builtin-record.c |   70 ++++++++++++++++++++++++---
 tools/perf/builtin-report.c |   19 +++++++-
 tools/perf/util/event.c     |    7 ++-
 tools/perf/util/event.h     |   15 ++++++
 7 files changed, 213 insertions(+), 16 deletions(-)
#1 lore raw

RFC PATCH 1/5 perf: Check if we should exclude idle thread in perf_exclude_event()

Don't open code the event check for excluding the idle thread. Instead include the check in perf_exclude_event().

---
 kernel/perf_event.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)
kernel/perf_event.c +5 -3
index 0d38f27..16b0476 100644
@@ -4310,6 +4310,9 @@ static int perf_exclude_event(struct perf_event *event,
 
 		if (event->attr.exclude_kernel && !user_mode(regs))
 			return 1;
+
+		if (event->attr.exclude_idle && current->pid == 0)
+			return 1;
 	}
 
 	return 0;
@@ -4512,9 +4515,8 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 	regs = get_irq_regs();
 
 	if (regs && !perf_exclude_event(event, regs)) {
-		if (!(event->attr.exclude_idle && current->pid == 0))
-			if (perf_event_overflow(event, 0, &data, regs))
-				ret = HRTIMER_NORESTART;
+		if (perf_event_overflow(event, 0, &data, regs))
+			ret = HRTIMER_NORESTART;
 	}
 
 	period = max_t(u64, 10000, event->hw.sample_period);
Signature · 1 line
1.7.1
#2 lore raw

Re: [RFC][PATCH 1/5] perf: Check if we should exclude idle thread in perf_exclude_event()

Quoted 13 lines · Matt Fleming

Don't open code the event check for excluding the idle thread. Instead include the check in perf_exclude_event().

---
 kernel/perf_event.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)
kernel/perf_event.c +0 -0
index 0d38f27..16b0476 100644

kernel/perf_event.c static int perf_exclude_event(struct perf_event *event, · line 4315

Quoted 6 lines
kernel/perf_event.c +3 -0
@@ -4310,6 +4310,9 @@ static int perf_exclude_event(struct perf_event *event,
 
 		if (event->attr.exclude_kernel && !user_mode(regs))
 			return 1;
+
+		if (event->attr.exclude_idle && current->pid == 0)
+			return 1;

Right.

But one of the problems people have reported is that they can miss interrupts samples if they happen in idle. Hence we have decided that exclude_idle should exclude events that happen in idle process context but not in interrupts interrupting idle.

So adding an in_interrupt() check would perhaps be better.

I plan to do this exclusion using the per context exclusion, which is a patchset I have in queue. But until then, having this patch is better.

kernel/perf_event.c static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) · line 4519

Quoted 12 lines
kernel/perf_event.c +2 -3
 	}
 
 	return 0;
@@ -4512,9 +4515,8 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 	regs = get_irq_regs();
 
 	if (regs && !perf_exclude_event(event, regs)) {
-		if (!(event->attr.exclude_idle && current->pid == 0))
-			if (perf_event_overflow(event, 0, &data, regs))
-				ret = HRTIMER_NORESTART;
+		if (perf_event_overflow(event, 0, &data, regs))
+			ret = HRTIMER_NORESTART;

But yeah if we add an in_interrupt() check in perf_exclude_event(), it won't work here. This one needs to check if irqs are nesting :)

Bah, checking we interrupted softirqs is probably enough. I guess we don't care about nesting hardirqs.

#3 lore raw

Re: [RFC][PATCH 1/5] perf: Check if we should exclude idle thread in perf_exclude_event()

Quoted 55 lines · Frederic Weisbecker
Quoted 13 lines · Matt Fleming

Don't open code the event check for excluding the idle thread. Instead include the check in perf_exclude_event().

---
 kernel/perf_event.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)
kernel/perf_event.c +0 -0
index 0d38f27..16b0476 100644

kernel/perf_event.c static int perf_exclude_event(struct perf_event *event, · line 4315

Quoted 6 lines
kernel/perf_event.c +3 -0
@@ -4310,6 +4310,9 @@ static int perf_exclude_event(struct perf_event *event,
 
 		if (event->attr.exclude_kernel && !user_mode(regs))
 			return 1;
+
+		if (event->attr.exclude_idle && current->pid == 0)
+			return 1;

Right.

But one of the problems people have reported is that they can miss interrupts samples if they happen in idle. Hence we have decided that exclude_idle should exclude events that happen in idle process context but not in interrupts interrupting idle.

So adding an in_interrupt() check would perhaps be better.

I plan to do this exclusion using the per context exclusion, which is a patchset I have in queue. But until then, having this patch is better.

kernel/perf_event.c static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) · line 4519

Quoted 12 lines
kernel/perf_event.c +2 -3
 	}
 
 	return 0;
@@ -4512,9 +4515,8 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 	regs = get_irq_regs();
 
 	if (regs && !perf_exclude_event(event, regs)) {
-		if (!(event->attr.exclude_idle && current->pid == 0))
-			if (perf_event_overflow(event, 0, &data, regs))
-				ret = HRTIMER_NORESTART;
+		if (perf_event_overflow(event, 0, &data, regs))
+			ret = HRTIMER_NORESTART;

But yeah if we add an in_interrupt() check in perf_exclude_event(), it won't work here. This one needs to check if irqs are nesting :)

Quoted 2 lines

Bah, checking we interrupted softirqs is probably enough. I guess we don't care about nesting hardirqs.

This patch isn't really worth it on its own, I only grouped the idle check into perf_exclude_event() because patch 3/5 introduced a new caller. As you've said, the semantics at the various callsites are quite complex. It's probably best to wait for your patchset :)

#4 lore raw

Re: [RFC][PATCH 1/5] perf: Check if we should exclude idle thread in perf_exclude_event()

Quoted 56 lines · Matt Fleming
Quoted 55 lines · Frederic Weisbecker
Quoted 13 lines · Matt Fleming

Don't open code the event check for excluding the idle thread. Instead include the check in perf_exclude_event().

---
 kernel/perf_event.c |    8 +++++---
 1 files changed, 5 insertions(+), 3 deletions(-)
kernel/perf_event.c +0 -0
index 0d38f27..16b0476 100644

kernel/perf_event.c static int perf_exclude_event(struct perf_event *event, · line 4315

Quoted 6 lines
kernel/perf_event.c +3 -0
@@ -4310,6 +4310,9 @@ static int perf_exclude_event(struct perf_event *event,
 
 		if (event->attr.exclude_kernel && !user_mode(regs))
 			return 1;
+
+		if (event->attr.exclude_idle && current->pid == 0)
+			return 1;

Right.

But one of the problems people have reported is that they can miss interrupts samples if they happen in idle. Hence we have decided that exclude_idle should exclude events that happen in idle process context but not in interrupts interrupting idle.

So adding an in_interrupt() check would perhaps be better.

I plan to do this exclusion using the per context exclusion, which is a patchset I have in queue. But until then, having this patch is better.

kernel/perf_event.c static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) · line 4519

Quoted 12 lines
kernel/perf_event.c +2 -3
 	}
 
 	return 0;
@@ -4512,9 +4515,8 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 	regs = get_irq_regs();
 
 	if (regs && !perf_exclude_event(event, regs)) {
-		if (!(event->attr.exclude_idle && current->pid == 0))
-			if (perf_event_overflow(event, 0, &data, regs))
-				ret = HRTIMER_NORESTART;
+		if (perf_event_overflow(event, 0, &data, regs))
+			ret = HRTIMER_NORESTART;

But yeah if we add an in_interrupt() check in perf_exclude_event(), it won't work here. This one needs to check if irqs are nesting :)

Quoted 7 lines
Quoted 2 lines

Bah, checking we interrupted softirqs is probably enough. I guess we don't care about nesting hardirqs.

This patch isn't really worth it on its own, I only grouped the idle check into perf_exclude_event() because patch 3/5 introduced a new caller. As you've said, the semantics at the various callsites are quite complex. It's probably best to wait for your patchset :)

Ok :)

#5 lore raw

RFC PATCH 2/5 perf: Turn the group counter values into delta values

In reply to Matt Fleming

Change the semantics of the PERF_FORMAT_GROUP records and make them delta values, i.e. the difference in value between consecutive reads of the hardware counters. These delta values will be used in a subsequent patch to calculate weighted values (by multiplying the deltas with the time difference between reads of the counters). Calculating these deltas is easiest to do in the kernel (as opposed to the userland tools) because we can reset the counter whenever we read from it.

Note that even though this patch changes the semantics of PERF_FORMAT_GROUP records there were no users of them anyway (the tools didn't even understand them).

---
 kernel/perf_event.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)
kernel/perf_event.c +10 -0
index 16b0476..2cda375 100644
@@ -3450,7 +3450,14 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 	if (leader != event)
 		leader->pmu->read(leader);
 
+	/*
+	 * Reset the counter value so that ->count contains a delta from
+	 * the previous value.
+	 */
 	values[n++] = perf_event_count(leader);
+	local64_set(&leader->count, 0);
+	atomic64_set(&leader->child_count, 0);
+
 	if (read_format & PERF_FORMAT_ID)
 		values[n++] = primary_event_id(leader);
 
@@ -3463,6 +3470,9 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 			sub->pmu->read(sub);
 
 		values[n++] = perf_event_count(sub);
+		local64_set(&sub->count, 0);
+		atomic64_set(&sub->child_count, 0);
+
 		if (read_format & PERF_FORMAT_ID)
 			values[n++] = primary_event_id(sub);
 
Signature · 1 line
1.7.1
maintainer
#6 lore raw

Re: [RFC][PATCH 2/5] perf: Turn the group counter values into delta values

Quoted 11 lines · Matt Fleming

Change the semantics of the PERF_FORMAT_GROUP records and make them delta values, i.e. the difference in value between consecutive reads of the hardware counters. These delta values will be used in a subsequent patch to calculate weighted values (by multiplying the deltas with the time difference between reads of the counters). Calculating these deltas is easiest to do in the kernel (as opposed to the userland tools) because we can reset the counter whenever we read from it.

Note that even though this patch changes the semantics of PERF_FORMAT_GROUP records there were no users of them anyway (the tools didn't even understand them).

libpfmon might be using it,.. I know some people occasionally reported bugs for this so there are users.

Also, there's no real synchonization between read,read and read,sample so its racy to do this, simply generate deltas in post-processing.

Quoted 34 lines
---
 kernel/perf_event.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)
kernel/perf_event.c +10 -0
index 16b0476..2cda375 100644
@@ -3450,7 +3450,14 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 	if (leader != event)
 		leader->pmu->read(leader);
 
+	/*
+	 * Reset the counter value so that ->count contains a delta from
+	 * the previous value.
+	 */
 	values[n++] = perf_event_count(leader);
+	local64_set(&leader->count, 0);
+	atomic64_set(&leader->child_count, 0);
+
 	if (read_format & PERF_FORMAT_ID)
 		values[n++] = primary_event_id(leader);
 
@@ -3463,6 +3470,9 @@ static void perf_output_read_group(struct perf_output_handle *handle,
 			sub->pmu->read(sub);
 
 		values[n++] = perf_event_count(sub);
+		local64_set(&sub->count, 0);
+		atomic64_set(&sub->child_count, 0);
+
 		if (read_format & PERF_FORMAT_ID)
 			values[n++] = primary_event_id(sub);
 
#7 lore raw

Re: [RFC][PATCH 2/5] perf: Turn the group counter values into delta values

Quoted 13 lines · Peter Zijlstra
Quoted 11 lines · Matt Fleming

Change the semantics of the PERF_FORMAT_GROUP records and make them delta values, i.e. the difference in value between consecutive reads of the hardware counters. These delta values will be used in a subsequent patch to calculate weighted values (by multiplying the deltas with the time difference between reads of the counters). Calculating these deltas is easiest to do in the kernel (as opposed to the userland tools) because we can reset the counter whenever we read from it.

Note that even though this patch changes the semantics of PERF_FORMAT_GROUP records there were no users of them anyway (the tools didn't even understand them).

Quoted 5 lines

libpfmon might be using it,.. I know some people occasionally reported bugs for this so there are users.

Also, there's no real synchonization between read,read and read,sample so its racy to do this, simply generate deltas in post-processing.

Ah, fair enough. Thanks, I'll do this with post-processing.

#8 lore raw

RFC PATCH 3/5 perf: Add hrtimer code for PMI-less hardware counters

In reply to Matt Fleming

Currently, it's impossible to periodically sample hardware counters that lack performance monitoring interrupt (PMI) support. In order to sample these counters we can create an event group which is backed by a hrtimer, thereby simulating a PMI.

When the hrtimer goes off we sample the values in the hardware counters. Because we obviously can't rely on the hrtimer going off at exactly the sample period (say, every 1000 cache misses) the values need to be weighted by the variable period since the last hrtimer went off. This is so that we can compensate for the variability in hrtimer period.

If perf record tries to create a sampling counter and the hardware doesn't support it then we'll fall back to creating an event group with a hrtimer.

---
 include/linux/perf_event.h |    4 ++
 kernel/perf_event.c        |   93 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 0 deletions(-)
include/linux/perf_event.h +4 -0
index 000610c..57d4aa0 100644
@@ -755,6 +755,10 @@ struct perf_event {
 
 	perf_overflow_handler_t		overflow_handler;
 
+	/* timer for sampling event group */
+	struct hrtimer			group_hrtimer;
+	s64				group_remaining;
+
 #ifdef CONFIG_EVENT_TRACING
 	struct ftrace_event_call	*tp_event;
 	struct event_filter		*filter;
kernel/perf_event.c +93 -0

117 lines not on this page · raw message

Signature · 1 line
1.7.1
maintainer
#9 lore raw

Re: [RFC][PATCH 3/5] perf: Add hrtimer code for PMI-less hardware counters

Quoted 12 lines · Matt Fleming

Currently, it's impossible to periodically sample hardware counters that lack performance monitoring interrupt (PMI) support. In order to sample these counters we can create an event group which is backed by a hrtimer, thereby simulating a PMI.

When the hrtimer goes off we sample the values in the hardware counters. Because we obviously can't rely on the hrtimer going off at exactly the sample period (say, every 1000 cache misses) the values need to be weighted by the variable period since the last hrtimer went off. This is so that we can compensate for the variability in hrtimer period.

Quoted 3 lines

If perf record tries to create a sampling counter and the hardware doesn't support it then we'll fall back to creating an event group with a hrtimer.

Why is this changing kernel code?

You can create those groups in userspace..

#10 lore raw

Re: [RFC][PATCH 3/5] perf: Add hrtimer code for PMI-less hardware counters

Quoted 13 lines · Peter Zijlstra
Quoted 12 lines · Matt Fleming

Currently, it's impossible to periodically sample hardware counters that lack performance monitoring interrupt (PMI) support. In order to sample these counters we can create an event group which is backed by a hrtimer, thereby simulating a PMI.

When the hrtimer goes off we sample the values in the hardware counters. Because we obviously can't rely on the hrtimer going off at exactly the sample period (say, every 1000 cache misses) the values need to be weighted by the variable period since the last hrtimer went off. This is so that we can compensate for the variability in hrtimer period.

Quoted 8 lines
Quoted 3 lines

If perf record tries to create a sampling counter and the hardware doesn't support it then we'll fall back to creating an event group with a hrtimer.

Why is this changing kernel code?

You can create those groups in userspace..

I'm lost. Is it possible to do this patch entirely in userspace? How do we periodically sample the counters if it's not being done in the kernel?

maintainer
#11 lore raw

Re: [RFC][PATCH 3/5] perf: Add hrtimer code for PMI-less hardware counters

Quoted 3 lines · Matt Fleming

I'm lost. Is it possible to do this patch entirely in userspace? How do we periodically sample the counters if it's not being done in the kernel?

perf_event_attr leader = {
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_TASK_CLOCK,
.sample_period = xxx,
.sample_type = PERF_SAMPLE_READ|...,
.read_format = PERF_FORMAT_GROUP,
};

perf_event_attr counter = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
};

leader_fd = sys_perf_event_open(&leader, pid, cpu, 0, 0); counter_fd = sys_perf_event_open(&counter, pid, cpu, leader_fd, 0);

Which gives you a group of 2 events, one software timer that samples, one hardware counter that only counts.

#12 lore raw

Re: [RFC][PATCH 3/5] perf: Add hrtimer code for PMI-less hardware counters

Quoted 19 lines · Peter Zijlstra
Quoted 3 lines · Matt Fleming

I'm lost. Is it possible to do this patch entirely in userspace? How do we periodically sample the counters if it's not being done in the kernel?

perf_event_attr leader = {
.type = PERF_TYPE_SOFTWARE,
.config = PERF_COUNT_SW_TASK_CLOCK,
.sample_period = xxx,
.sample_type = PERF_SAMPLE_READ|...,
.read_format = PERF_FORMAT_GROUP,
};

perf_event_attr counter = {
.type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES,
};

Quoted 5 lines

leader_fd = sys_perf_event_open(&leader, pid, cpu, 0, 0); counter_fd = sys_perf_event_open(&counter, pid, cpu, leader_fd, 0);

Which gives you a group of 2 events, one software timer that samples, one hardware counter that only counts.

Aha. OK, thanks! I'll respin this.

#13 lore raw

RFC PATCH 4/5 sh: Add support for sampling counters

In reply to Matt Fleming

SH performance counters cannot generate any form of interrupt and so require hrtimer assistance for sampling counter values. Event groups periodically sample counters when a hrtimer fires which allows the use of sampling counters on SH.

---
 arch/sh/kernel/perf_event.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
arch/sh/kernel/perf_event.c +2 -1
index 7a3dc35..1f77de6 100644
@@ -114,7 +114,8 @@ static int __hw_perf_event_init(struct perf_event *event)
 	 * no interrupts, and are therefore unable to do sampling without
 	 * further work and timer assistance.
 	 */
-	if (hwc->sample_period)
+	if (!(attr->read_format & PERF_FORMAT_GROUP) &&
+	    hwc->sample_period && event->group_leader == event)
 		return -EINVAL;
 
 	/*
Signature · 1 line
1.7.1
#14 lore raw

RFC PATCH 5/5 perf: Add support for PERF_SAMPLE_READ samples

In reply to Matt Fleming

Using the counter values from PERF_SAMPLE_READ samples and weighting them by the hrtimer period we can approximate a counter with a PMI. By following how fast a counter varies over a hrtimer period we can figure out which functions are causing the counters to change the fastest.

Suppose you have a workload consisting of two main parts:

  my_important_work()
  {
     load_my_data();
     compute_me_silly();
  }

Now, lets assume that both these functions take the same time to complete for each part of work. In that case a periodic timer generate samples that are about 50/50 distributed between these two functions.

Now, let us further assume that load_my_data() is so slow because its missing all the caches and compute_me_silly() is slow because its defeating the branch predictor.

So what we end up with, is that when we sample for cache-misses we get load_my_data() as the predominant function, not a nice 50/50 relation. Idem for branch misses and compute_me_silly().

By weighting the samples by the hw counter delta we get this, if we assume that the sampling frequency is not a harmonic of the runtime of these functions, then statistics will dtrt.

---
 tools/perf/builtin-record.c |   70 ++++++++++++++++++++++++++++++++++++++-----
 tools/perf/builtin-report.c |   19 ++++++++++-
 tools/perf/util/event.c     |    7 +++-
 tools/perf/util/event.h     |   15 +++++++++
 4 files changed, 99 insertions(+), 12 deletions(-)
tools/perf/builtin-record.c +62 -8
index b530bee..4bd7c4a 100644
@@ -224,20 +224,43 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
 	return h_attr;
 }
 
+struct read_format_single {
+	u64 count;
+	u64 time_enabled;
+	u64 time_running;
+	u64 id;
+};
+
+struct group_entry {
+	u64 value;
+	u64 id;
+};
+
+struct read_format_group {
+	u64 nr;
+	u64 time_enabled;
+	u64 time_running;
+	struct group_entry cntr[0];
+};
+
 static void create_counter(int counter, int cpu)
 {
 	char *filter = filters[counter];
 	struct perf_event_attr *attr = attrs + counter;
 	struct perf_header_attr *h_attr;
 	int track = !counter; /* only the first counter needs these */
+	size_t read_data_sz;
+	void *read_data;
 	int thread_index;
 	int ret;
-	struct {
-		u64 count;
-		u64 time_enabled;
-		u64 time_running;
-		u64 id;
-	} read_data;
+	u64 id;
+
+	read_data_sz = sizeof(struct read_format_single);
+	read_data = malloc(read_data_sz);
+	if (!read_data) {
+		perror("Unable to allocate read data");
+		return;
+	}
 
 	attr->read_format	= PERF_FORMAT_TOTAL_TIME_ENABLED |
 				  PERF_FORMAT_TOTAL_TIME_RUNNING |
@@ -325,6 +348,32 @@ try_again:
 				attr->config = PERF_COUNT_SW_CPU_CLOCK;
 				goto try_again;
 			}
+
+			/*
+			 * If we requested a sampling counter but the
+			 * hardware doesn't support it, create an
+			 * event group.
+			 */
+			if (err == EINVAL && attr->sample_period && !group) {
+				size_t sz = sizeof(struct read_format_group);
+
+				attr->read_format |= PERF_FORMAT_GROUP;
+				attr->sample_type |= PERF_SAMPLE_READ;
+
+				free(read_data);
+
+				read_data_sz = sz + (sizeof(struct group_entry) * nr_counters);
+				read_data = malloc(read_data_sz);
+				if (!read_data) {
+					perror("Unable to allocate read_data");
+					exit(-1);
+				}
+
+				/* Only try to fallback to a group once. */
+				group = 1;
+				goto try_again;
+			}
+
 			printf("\n");
 			error("perfcounter syscall returned with %d (%s)\n",
 					fd[nr_cpu][counter][thread_index], strerror(err));
@@ -352,12 +401,17 @@ try_again:
 			}
 		}
 
-		if (read(fd[nr_cpu][counter][thread_index], &read_data, sizeof(read_data)) == -1) {
+		if (read(fd[nr_cpu][counter][thread_index], read_data, read_data_sz) == -1) {
 			perror("Unable to read perf file descriptor");
 			exit(-1);
 		}
 
-		if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
+		if (attr->read_format & PERF_FORMAT_GROUP)
+			id = ((struct read_format_group *)read_data)->cntr[0].id;
+		else
+			id = ((struct read_format_single *)read_data)->id;
+
+		if (perf_header_attr__add_id(h_attr, id) < 0) {
 			pr_warning("Not enough memory to add id\n");
 			exit(-1);
 		}
tools/perf/builtin-report.c +17 -2
index 5de405d..44772fb 100644
@@ -139,14 +139,29 @@ static int add_event_total(struct perf_session *session,
 	if (!hists)
 		return -ENOMEM;
 
-	hists->stats.total_period += data->period;
+	if (attr && attr->type & PERF_SAMPLE_READ) {
+		u64 value;
+		unsigned int i;
+
+		for (i = 0; i < data->group->nr; i++) {
+			struct read_group_entry *entry = &data->group->entries[i];
+
+			value = entry->value * data->group->time_running;
+			hists->stats.total_period += value;
+			session->hists.stats.total_period += value;
+		}
+	} else {
+		hists->stats.total_period += data->period;
+		session->hists.stats.total_period += data->period;
+	}
+
 	/*
 	 * FIXME: add_event_total should be moved from here to
 	 * perf_session__process_event so that the proper hist is passed to
 	 * the event_op methods.
 	 */
 	hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
-	session->hists.stats.total_period += data->period;
+
 	return 0;
 }
 
tools/perf/util/event.c +5 -2
index dab9e75..c52b3ef 100644
@@ -816,8 +816,11 @@ int event__parse_sample(const event_t *event, u64 type, struct sample_data *data
 	}
 
 	if (type & PERF_SAMPLE_READ) {
-		pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
-		return -1;
+		/* FIXME assume group read event for now. */
+		size_t entry_sz = sizeof(struct read_group_entry);
+
+		data->group = (struct read_group *)array;
+		array += sizeof(struct read_group) + (data->group->nr * entry_sz);
 	}
 
 	if (type & PERF_SAMPLE_CALLCHAIN) {
tools/perf/util/event.h +15 -0
index 8e790da..e7cadaa 100644
@@ -56,6 +56,20 @@ struct read_event {
 	u64 id;
 };
 
+struct read_group_entry {
+	u64 value;
+	u64 id;
+};
+
+struct read_group {
+	struct perf_event_header header;
+	u32 pid, tid;
+	u64 nr;
+	u64 time_enabled;
+	u64 time_running;
+	struct read_group_entry entries[0];
+};
+
 struct sample_event {
 	struct perf_event_header        header;
 	u64 array[];
@@ -73,6 +87,7 @@ struct sample_data {
 	u32 raw_size;
 	void *raw_data;
 	struct ip_callchain *callchain;
+	struct read_group *group;
 };
 
 #define BUILD_ID_SIZE 20
Signature · 1 line
1.7.1