Skip to contentSkip to conversation

perf_events: improve x86 event scheduling (v5)

PATCH In review Stephane Eranian 3 participants 40 messages Jan 18, 2010 – Feb 27, 2010

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

PATCH 1/1 perf_events: improve x86 event scheduling (v5)

This patch improves event scheduling by maximizing the use of PMU registers regardless of the order in which events are created in a group.

The algorithm takes into account the list of counter constraints for each event. It assigns events to counters from the most constrained, i.e., works on only one counter, to the least constrained, i.e., works on any counter.

Intel Fixed counter events and the BTS special event are also handled via this algorithm which is designed to be fairly generic.

The patch also updates the validation of an event to use the scheduling algorithm. This will cause early failure in perf_event_open().

The 2nd version of this patch follows the model used by PPC, by running the scheduling algorithm and the actual assignment separately. Actual assignment takes place in hw_perf_enable() whereas scheduling is implemented in hw_perf_group_sched_in() and x86_pmu_enable().

The 3rd version does:
- correct handling of pmu->enable() error in hw_perf_group_sched_in()
- simplified event scheduling
- constraint storage in x86_schedule_events() (dynamic constraints)
- new put_event_constraints() callback to release a dynamic constraint

The 4th version does:
- remove leftover debug code in x86_perf_event_set_period()

The 5th version does:
- fix missing bitmask initialization in intel_get_event_constraints()
- use bitmap_copy() instead of memcpy() to copy bitmasks
- call pmu->disable() in x86_event_sched_out()

--

 include/asm/perf_event.h |   17 -
 kernel/cpu/perf_event.c  |  771 +++++++++++++++++++++++++++++++++--------------
 2 files changed, 571 insertions(+), 217 deletions(-)
arch/x86/include/asm/perf_event.h +15 -2
index 8d9f854..16beb34 100644
@@ -19,6 +19,7 @@
 #define MSR_ARCH_PERFMON_EVENTSEL1			     0x187
 
 #define ARCH_PERFMON_EVENTSEL0_ENABLE			  (1 << 22)
+#define ARCH_PERFMON_EVENTSEL_ANY			  (1 << 21)
 #define ARCH_PERFMON_EVENTSEL_INT			  (1 << 20)
 #define ARCH_PERFMON_EVENTSEL_OS			  (1 << 17)
 #define ARCH_PERFMON_EVENTSEL_USR			  (1 << 16)
@@ -26,7 +27,14 @@
 /*
  * Includes eventsel and unit mask as well:
  */
-#define ARCH_PERFMON_EVENT_MASK				    0xffff
+
+
+#define INTEL_ARCH_EVTSEL_MASK		0x000000FFULL
+#define INTEL_ARCH_UNIT_MASK		0x0000FF00ULL
+#define INTEL_ARCH_EDGE_MASK		0x00040000ULL
+#define INTEL_ARCH_INV_MASK		0x00800000ULL
+#define INTEL_ARCH_CNT_MASK		0xFF000000ULL
+#define INTEL_ARCH_EVENT_MASK	(INTEL_ARCH_UNIT_MASK|INTEL_ARCH_EVTSEL_MASK)
 
 /*
  * filter mask to validate fixed counter events.
@@ -37,7 +45,12 @@
  *  The other filters are supported by fixed counters.
  *  The any-thread option is supported starting with v3.
  */
-#define ARCH_PERFMON_EVENT_FILTER_MASK			0xff840000
+#define INTEL_ARCH_FIXED_MASK \
+	(INTEL_ARCH_CNT_MASK| \
+	 INTEL_ARCH_INV_MASK| \
+	 INTEL_ARCH_EDGE_MASK|\
+	 INTEL_ARCH_UNIT_MASK|\
+	 INTEL_ARCH_EVENT_MASK)
 
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL		      0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK		(0x00 << 8)
arch/x86/kernel/cpu/perf_event.c +556 -215

956 lines not on this page · raw message

#1 lore raw
Quoted 50 lines · Stephane Eranian
arch/x86/kernel/cpu/perf_event.c +50 -0
+int hw_perf_group_sched_in(struct perf_event *leader,
+	       struct perf_cpu_context *cpuctx,
+	       struct perf_event_context *ctx, int cpu)
+{
+	struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+	struct perf_event *sub;
+	int assign[X86_PMC_IDX_MAX];
+	int n0, n1, ret;
+
+	/* n0 = total number of events */
+	n0 = collect_events(cpuc, leader, true);
+	if (n0 < 0)
+		return n0;
+
+	ret = x86_schedule_events(cpuc, n0, assign);
+	if (ret)
+		return ret;
+
+	ret = x86_event_sched_in(leader, cpuctx, cpu);
+	if (ret)
+		return ret;
+
+	n1 = 1;
+	list_for_each_entry(sub, &leader->sibling_list, group_entry) {
+		if (sub->state != PERF_EVENT_STATE_OFF) {
+			ret = x86_event_sched_in(sub, cpuctx, cpu);
+			if (ret)
+				goto undo;
+			++n1;
+		}
+	}
+	/*
+	 * copy new assignment, now we know it is possible
+	 * will be used by hw_perf_enable()
+	 */
+	memcpy(cpuc->assign, assign, n0*sizeof(int));
+
+	cpuc->n_events  = n0;
+	cpuc->n_added   = n1;
+	ctx->nr_active += n1;
+
+	/*
+	 * 1 means successful and events are active
+	 * This is not quite true because we defer
+	 * actual activation until hw_perf_enable() but
+	 * this way we* ensure caller won't try to enable
+	 * individual events
+	 */
+	return 1;
+undo:

arch/x86/kernel/cpu/perf_event.c perf_event_nmi_handler(struct notifier_block *self, · line 2292

Quoted 10 lines
arch/x86/kernel/cpu/perf_event.c +10 -0
+	x86_event_sched_out(leader, cpuctx, cpu);
+	n0  = 1;
+	list_for_each_entry(sub, &leader->sibling_list, group_entry) {
+		if (sub->state == PERF_EVENT_STATE_ACTIVE) {
+			x86_event_sched_out(sub, cpuctx, cpu);
+			if (++n0 == n1)
+				break;
+		}
+	}
+	return ret;

Looking at all these numerous places where this whole constraint and ad hoc scheduling machine tries to catch up with what the core can already do (handle non-x86 events, revert in failure, first handle leader, then handle the rest, etc...), I wonder if this hw_group_sched_in() based design is a good idea.

Shouldn't we actually use the core based pmu->enable(),disable() model called from kernel/perf_event.c:event_sched_in(), like every other events, where we can fill up the queue of hardware events to be scheduled, and then call a hw_check_constraints() when we finish a group scheduling?

I guess this would simplify all this code, avoid it to run through the list of events, handle software events, revert partial enabled by itself etc...

Hm?

maintainer
#2 lore raw
Quoted 6 lines · Frederic Weisbecker

Shouldn't we actually use the core based pmu->enable(),disable() model called from kernel/perf_event.c:event_sched_in(), like every other events, where we can fill up the queue of hardware events to be scheduled, and then call a hw_check_constraints() when we finish a group scheduling?

Well the thing that makes hw_perf_group_sched_in() useful is that you can add a bunch of events and not have to reschedule for each one, but instead do a single schedule pass.

That said you do have a point, maybe we can express this particular thing differently.. maybe a pre and post group call like:

void hw_perf_group_sched_in_begin(struct pmu *pmu) int hw_perf_group_sched_in_end(struct pmu *pmu)

That way we know we need to track more state for rollback and can give the pmu implementation leeway to delay scheduling/availablility tests.

Paul, would that work for you too?

Then there's still the question of having events of multiple hw pmus in a single group, I'd be perfectly fine with saying that's not allowed, what to others think?

#3 lore raw
Quoted 8 lines · Peter Zijlstra
Quoted 6 lines · Frederic Weisbecker

Shouldn't we actually use the core based pmu->enable(),disable() model called from kernel/perf_event.c:event_sched_in(), like every other events, where we can fill up the queue of hardware events to be scheduled, and then call a hw_check_constraints() when we finish a group scheduling?

Quoted 4 lines

Well the thing that makes hw_perf_group_sched_in() useful is that you can add a bunch of events and not have to reschedule for each one, but instead do a single schedule pass.

That's right.

Quoted 6 lines

That said you do have a point, maybe we can express this particular thing differently.. maybe a pre and post group call like:

 void hw_perf_group_sched_in_begin(struct pmu *pmu) int  hw_perf_group_sched_in_end(struct pmu *pmu)

The issue with hw_perf_group_sched_in() is that because we do not know when we are done scheduling, we have to defer actual activation until hw_perf_enable(). But we have to still mark the events as ACTIVE, otherwise things go wrong in the generic layer and for non-PMU events. That leads to partial duplication of event_sched_in()/event_sched_out() in the PMU specific layer.

As Frederic pointed out, the more natural way would be to simply rely on event_sched_in()/event_sched_out() and the rollback logic and just drop hw_perf_group_sched_in() which is there as an optimization and not for correctness. Scheduling can be done incrementally from the event_sched_in() function.

Quoted 3 lines

That way we know we need to track more state for rollback and can give the pmu implementation leeway to delay scheduling/availablility tests.

Rollback would still be handled by the generic code, wouldn't it?

Quoted 6 lines

Paul, would that work for you too?

Then there's still the question of having events of multiple hw pmus in a single group, I'd be perfectly fine with saying that's not allowed, what to others think?

I have seen requests for measuring both core and uncore PMU events together for instance. It all depends on how uncore PMU will be managed.

maintainer
#4 lore raw
Quoted 7 lines · Stephane Eranian
Quoted 5 lines

Then there's still the question of having events of multiple hw pmus in a single group, I'd be perfectly fine with saying that's not allowed, what to others think?

I have seen requests for measuring both core and uncore PMU events together for instance. It all depends on how uncore PMU will be managed.

OK, hard to correlate those two though, it would basically mean only running that one task on the socket.

maintainer
#5 lore raw
In reply to Stephane Eranian
Quoted 19 lines · Stephane Eranian
Quoted 6 lines

That said you do have a point, maybe we can express this particular thing differently.. maybe a pre and post group call like:

void hw_perf_group_sched_in_begin(struct pmu *pmu) int hw_perf_group_sched_in_end(struct pmu *pmu)

The issue with hw_perf_group_sched_in() is that because we do not know when we are done scheduling, we have to defer actual activation until hw_perf_enable(). But we have to still mark the events as ACTIVE, otherwise things go wrong in the generic layer and for non-PMU events. That leads to partial duplication of event_sched_in()/event_sched_out() in the PMU specific layer.

As Frederic pointed out, the more natural way would be to simply rely on event_sched_in()/event_sched_out() and the rollback logic and just drop hw_perf_group_sched_in() which is there as an optimization and not for correctness. Scheduling can be done incrementally from the event_sched_in() function.

Quoted 4 lines
Quoted 3 lines

That way we know we need to track more state for rollback and can give the pmu implementation leeway to delay scheduling/availablility tests.

Rollback would still be handled by the generic code, wouldn't it?

I'm not sure I understand your reply. Sure dropping hw_perf_group_sched_in() is still correct, but its also less optimal, since we have to determine schedulability for each incremental event.

#6 lore raw
In reply to Peter Zijlstra
Quoted 11 lines · Peter Zijlstra
Quoted 6 lines · Frederic Weisbecker

Shouldn't we actually use the core based pmu->enable(),disable() model called from kernel/perf_event.c:event_sched_in(), like every other events, where we can fill up the queue of hardware events to be scheduled, and then call a hw_check_constraints() when we finish a group scheduling?

Well the thing that makes hw_perf_group_sched_in() useful is that you can add a bunch of events and not have to reschedule for each one, but instead do a single schedule pass.

Well in appearance, things go through one pass.

But actually not, there is a first iteration that collects the events (walking trhough the group list, filtering soft events), a second iteration that check the constraints and schedule (but not apply) the events.

And thereafter we schedule soft events (and revert the whole if needed).

This is a one pass from group_sched_in() POV but at the cost of reimplementating what the core does wrt soft events and iterations. And not only is it reinventing the wheel, it also produces more iterations than we need.

If we were using the common pmu->enable() from group/event_sched_in(), that would build the collection, with only one iteration through the group list (instead of one to collect, and one for the software events).

And the constraints can be validated in a second explicit iteration through hw_check_constraint(), like it's currently done explicitly from hw_perf_group_sched_in() that calls x86_schedule_event().

The fact is we have with this patch a _lot_ of iterations each time x86 get scheduled. This is really a lot for a fast path. But considering the dynamic cpu events / task events series we can have, I don't see other alternatives.

But still there are wasteful iterations that can be avoided with the above statements.

Quoted 9 lines

That said you do have a point, maybe we can express this particular thing differently.. maybe a pre and post group call like:

void hw_perf_group_sched_in_begin(struct pmu *pmu) int hw_perf_group_sched_in_end(struct pmu *pmu)

That way we know we need to track more state for rollback and can give the pmu implementation leeway to delay scheduling/availablility tests.

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
	event->enable();	//do the collection here
}
if (hw_perf_group_sched_in_end(&x86_pmu)) {
	rollback...
}

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Quoted 3 lines

Then there's still the question of having events of multiple hw pmus in a single group, I'd be perfectly fine with saying that's not allowed, what to others think?

I guess we need that. It can be insteresting to couple hardware counters with memory accesses...or whatever. Perf stat combines cache miss counting with page faults, cpu clock counters.
We shouldn't limit such possibilities for technical/cleanliness reasons. We should rather adapt.

Hm?

maintainer
#7 lore raw
Quoted 17 lines · Frederic Weisbecker

Well in appearance, things go through one pass.

But actually not, there is a first iteration that collects the events (walking trhough the group list, filtering soft events), a second iteration that check the constraints and schedule (but not apply) the events.

And thereafter we schedule soft events (and revert the whole if needed).

This is a one pass from group_sched_in() POV but at the cost of reimplementating what the core does wrt soft events and iterations. And not only is it reinventing the wheel, it also produces more iterations than we need.

Quoted 8 lines

If we were using the common pmu->enable() from group/event_sched_in(), that would build the collection, with only one iteration through the group list (instead of one to collect, and one for the software events).

And the constraints can be validated in a second explicit iteration through hw_check_constraint(), like it's currently done explicitly from hw_perf_group_sched_in() that calls x86_schedule_event().

Thing is, we cannot do that, because we currently require ->enable() to report schedulability. Now we could add an argument to ->enable, or add callbacks like I suggested to convey that state.

Quoted 4 lines

The fact is we have with this patch a _lot_ of iterations each time x86 get scheduled. This is really a lot for a fast path. But considering the dynamic cpu events / task events series we can have, I don't see other alternatives.

Luckily it tries to use a previous configuration, so in practise the schedule phase is real quick amortized O(1) as long as we don't change the set.

Quoted 9 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here
}
Quoted 6 lines
if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Good point, but your proposed hw_check_constraint() call needs to know the exact same.

#8 lore raw
Quoted 23 lines · Peter Zijlstra
Quoted 22 lines · Frederic Weisbecker

Well in appearance, things go through one pass.

But actually not, there is a first iteration that collects the events (walking trhough the group list, filtering soft events), a second iteration that check the constraints and schedule (but not apply) the events.

And thereafter we schedule soft events (and revert the whole if needed).

This is a one pass from group_sched_in() POV but at the cost of reimplementating what the core does wrt soft events and iterations. And not only is it reinventing the wheel, it also produces more iterations than we need.

If we were using the common pmu->enable() from group/event_sched_in(), that would build the collection, with only one iteration through the group list (instead of one to collect, and one for the software events).

Quoted 7 lines
Quoted 3 lines

And the constraints can be validated in a second explicit iteration through hw_check_constraint(), like it's currently done explicitly from hw_perf_group_sched_in() that calls x86_schedule_event().

Thing is, we cannot do that, because we currently require ->enable() to report schedulability. Now we could add an argument to ->enable, or add callbacks like I suggested to convey that state.

Hmm, but the schedulability status can be overriden in this case by the callbacks you mentioned. The thing is I'm not sure how you mean to use these. Is it like I did in the previous mockup, by calling hw_perf_group_sched_in_begin() in the beginning of a group scheduling and hw_perf_group_sched_in_end() in the end?

Quoted 8 lines
Quoted 4 lines

The fact is we have with this patch a _lot_ of iterations each time x86 get scheduled. This is really a lot for a fast path. But considering the dynamic cpu events / task events series we can have, I don't see other alternatives.

Luckily it tries to use a previous configuration, so in practise the schedule phase is real quick amortized O(1) as long as we don't change the set.

Yeah.

Quoted 13 lines
Quoted 13 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here
}
if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}
Quoted 5 lines
Quoted 2 lines

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Good point, but your proposed hw_check_constraint() call needs to know the exact same.

True. Whatever model we use anyway, both implement the same idea.

maintainer
#9 lore raw
Quoted 9 lines · Frederic Weisbecker
Quoted 6 lines
Quoted 3 lines

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Good point, but your proposed hw_check_constraint() call needs to know the exact same.

True. Whatever model we use anyway, both implement the same idea.

Hmm, we seem to already have that problem (which would indicate another bug in the hw-breakpoint stuff), how do you deal with hw_perf_{enable,disable}() for the breakpoints?

We could fix this by making these pmu state functions into a callback list visiting all registered PMUs.

#10 lore raw
Quoted 9 lines · Peter Zijlstra
Quoted 8 lines · Frederic Weisbecker
Quoted 6 lines
Quoted 3 lines

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Good point, but your proposed hw_check_constraint() call needs to know the exact same.

Quoted 5 lines
Quoted 1 line

True. Whatever model we use anyway, both implement the same idea.

Hmm, we seem to already have that problem (which would indicate another bug in the hw-breakpoint stuff), how do you deal with hw_perf_{enable,disable}() for the breakpoints?

We don't have ordering constraints for breakpoints, only constraints on the number of available registers.

So we check the constraints when a breakpoint registers. The enable/disable then (is supposed to) always succeed on breakpoint pmu, except for flexible breakpoints that can make it or not, but no need to overwrite group scheduling for that.

maintainer
#11 lore raw
Quoted 17 lines · Frederic Weisbecker
Quoted 9 lines · Peter Zijlstra
Quoted 8 lines · Frederic Weisbecker
Quoted 6 lines
Quoted 3 lines

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Good point, but your proposed hw_check_constraint() call needs to know the exact same.

Quoted 5 lines
Quoted 1 line

True. Whatever model we use anyway, both implement the same idea.

Hmm, we seem to already have that problem (which would indicate another bug in the hw-breakpoint stuff), how do you deal with hw_perf_{enable,disable}() for the breakpoints?

Quoted 7 lines

We don't have ordering constraints for breakpoints, only constraints on the number of available registers.

So we check the constraints when a breakpoint registers. The enable/disable then (is supposed to) always succeed on breakpoint pmu, except for flexible breakpoints that can make it or not, but no need to overwrite group scheduling for that.

hw_perf_{enable,disable} are unrelated to groups.

#12 lore raw
Quoted 21 lines · Peter Zijlstra
Quoted 20 lines · Frederic Weisbecker
Quoted 9 lines · Peter Zijlstra
Quoted 8 lines · Frederic Weisbecker
Quoted 6 lines
Quoted 3 lines

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

Good point, but your proposed hw_check_constraint() call needs to know the exact same.

Quoted 5 lines
Quoted 1 line

True. Whatever model we use anyway, both implement the same idea.

Hmm, we seem to already have that problem (which would indicate another bug in the hw-breakpoint stuff), how do you deal with hw_perf_{enable,disable}() for the breakpoints?

We don't have ordering constraints for breakpoints, only constraints on the number of available registers.

Quoted 6 lines
Quoted 4 lines

So we check the constraints when a breakpoint registers. The enable/disable then (is supposed to) always succeed on breakpoint pmu, except for flexible breakpoints that can make it or not, but no need to overwrite group scheduling for that.

hw_perf_{enable,disable} are unrelated to groups.

Right hw_perf_enable/disable have no action on breakpoint events. These were somehow considered as software events until now.

That raises the question: why perf_disable() only takes care of hardware events? Very few software events can trigger between perf_disable() and perf_enable() sections though.

May be I should handle breakpoints there.

maintainer
#13 lore raw
Quoted 8 lines · Frederic Weisbecker

Right hw_perf_enable/disable have no action on breakpoint events. These were somehow considered as software events until now.

That raises the question: why perf_disable() only takes care of hardware events? Very few software events can trigger between perf_disable() and perf_enable() sections though.

May be I should handle breakpoints there.

OK, so maybe I'm not understanding the breakpoint stuff correctly, why is it modeled as a software pmu? It has resource constraints like a hardware pmu.

#14 lore raw
Quoted 9 lines · Peter Zijlstra
Quoted 7 lines · Frederic Weisbecker

Right hw_perf_enable/disable have no action on breakpoint events. These were somehow considered as software events until now.

That raises the question: why perf_disable() only takes care of hardware events? Very few software events can trigger between perf_disable() and perf_enable() sections though.

Quoted 5 lines
Quoted 1 line

May be I should handle breakpoints there.

OK, so maybe I'm not understanding the breakpoint stuff correctly, why is it modeled as a software pmu? It has resource constraints like a hardware pmu.

It doesn't use the software pmu, it uses its own. But what kind of properties can it share with other hardware events?

It has constraints that only need to be checked when we register the event. It has also constraint on enable time but nothing tricky that requires an overwritten group scheduling.

And moreover it has no internal counters, it sensibly behaves much like a software pmu by just triggering events.

maintainer
#15 lore raw
Quoted 17 lines · Frederic Weisbecker
Quoted 9 lines · Peter Zijlstra
Quoted 7 lines · Frederic Weisbecker

Right hw_perf_enable/disable have no action on breakpoint events. These were somehow considered as software events until now.

That raises the question: why perf_disable() only takes care of hardware events? Very few software events can trigger between perf_disable() and perf_enable() sections though.

Quoted 5 lines
Quoted 1 line

May be I should handle breakpoints there.

OK, so maybe I'm not understanding the breakpoint stuff correctly, why is it modeled as a software pmu? It has resource constraints like a hardware pmu.

Quoted 6 lines

It doesn't use the software pmu, it uses its own. But what kind of properties can it share with other hardware events?

It has constraints that only need to be checked when we register the event. It has also constraint on enable time but nothing tricky that requires an overwritten group scheduling.

the only group scheduling bit is hw_perf_group_sched_in(), and I guess you can get away without hw_perf_disable() because it doesn't generate nmis, although I'd have to audit the code to verify a properly placed breakpoint won't trip things up, since the core code basically assumes counters won't trigger within perf_disable/enable sections.

maintainer
#16 lore raw
In reply to Frederic Weisbecker
Quoted 3 lines · Frederic Weisbecker

It has constraints that only need to be checked when we register the event. It has also constraint on enable time but nothing tricky that requires an overwritten group scheduling.

The fact that ->enable() can fail makes it a hardware counter. Software counters cannot fail enable.

Having multiple groups of failable events (multiple hardware pmus) can go wrong with the current core in interesting ways, look for example at __perf_event_sched_in():

It does:

	int can_add_hw = 1;

	...

	list_for_each_entry(event, &ctx->flexible_groups, group_entry) {
		/* Ignore events in OFF or ERROR state */
		if (event->state <= PERF_EVENT_STATE_OFF)
			continue;
		/*
		 * Listen to the 'cpu' scheduling filter constraint
		 * of events:
		 */
		if (event->cpu != -1 && event->cpu != cpu)
			continue;

		if (group_can_go_on(event, cpuctx, can_add_hw))
			if (group_sched_in(event, cpuctx, ctx, cpu))
				can_add_hw = 0;
	}

Now, if you look at that logic you'll see that it assumes there's one hw device since it only has one can_add_hw state. So if your hw_breakpoint pmu starts to fail we'll also stop adding counters to the cpu pmu (for lack of a better name) and vs.

This might be fixable by using per-cpu struct pmu variables.

I'm going to try and move all the weak hw_perf_* functions into struct pmu and create a notifier like callchain for them so we can have proper per pmu state, and then use that to fix these things up.

However I'm afraid its far to late to push any of that into .33, which means .33 will have rather funny behaviour once the breakpoints start getting used.

maintainer
#17 lore raw
Quoted 42 lines · Peter Zijlstra
Quoted 3 lines · Frederic Weisbecker

It has constraints that only need to be checked when we register the event. It has also constraint on enable time but nothing tricky that requires an overwritten group scheduling.

The fact that ->enable() can fail makes it a hardware counter. Software counters cannot fail enable.

Having multiple groups of failable events (multiple hardware pmus) can go wrong with the current core in interesting ways, look for example at __perf_event_sched_in():

It does:

	int can_add_hw = 1;

	...

	list_for_each_entry(event, &ctx->flexible_groups, group_entry) {
		/* Ignore events in OFF or ERROR state */
		if (event->state <= PERF_EVENT_STATE_OFF)
			continue;
		/*
		 * Listen to the 'cpu' scheduling filter constraint
		 * of events:
		 */
		if (event->cpu != -1 && event->cpu != cpu)
			continue;

		if (group_can_go_on(event, cpuctx, can_add_hw))
			if (group_sched_in(event, cpuctx, ctx, cpu))
				can_add_hw = 0;
	}

Now, if you look at that logic you'll see that it assumes there's one hw device since it only has one can_add_hw state. So if your hw_breakpoint pmu starts to fail we'll also stop adding counters to the cpu pmu (for lack of a better name) and vs.

This might be fixable by using per-cpu struct pmu variables.

Quoted 7 lines

I'm going to try and move all the weak hw_perf_* functions into struct pmu and create a notifier like callchain for them so we can have proper per pmu state, and then use that to fix these things up.

However I'm afraid its far to late to push any of that into .33, which means .33 will have rather funny behaviour once the breakpoints start getting used.

Hrmph, so I read some of that hw_breakpoint stuff, and now I'm sorta confused, it looks like ->enable should never fail, but that means you cannot overcommit breakpoints, which doesn't fit the perf model nicely.

Also, I see you set an ->unthrottle, but then don't implement it, but comment it as todo, which is strange because that implies its broken. If there's an ->unthrottle method it will throttle, so if its todo, the safest thing is to not set it.

/me mutters something and goes look at something else for a while.

#18 lore raw
Quoted 3 lines · Peter Zijlstra

Hrmph, so I read some of that hw_breakpoint stuff, and now I'm sorta confused, it looks like ->enable should never fail, but that means you cannot overcommit breakpoints, which doesn't fit the perf model nicely.

Yeah :)
I described this in my previous mail to you. Breakpoint events, for now, are not supposed to fail on enable().

But once we have the strict pinned -> flexible ordering, I'll rework this.

Quoted 4 lines

Also, I see you set an ->unthrottle, but then don't implement it, but comment it as todo, which is strange because that implies its broken. If there's an ->unthrottle method it will throttle, so if its todo, the safest thing is to not set it.

Yeah, that's because I have a too vague idea on what is the purpose of the unthrottle() callback.

I've read the concerned codes that call this, several times, and I still can't figure out what happens there, not sure what is meant by throttle or unthrottle there :-/

Quoted 1 line

/me mutters something and goes look at something else for a while.

Yeah, that's still a young code that needs improvement :)

maintainer
#19 lore raw
Quoted 6 lines · Frederic Weisbecker
Quoted 4 lines

Also, I see you set an ->unthrottle, but then don't implement it, but comment it as todo, which is strange because that implies its broken. If there's an ->unthrottle method it will throttle, so if its todo, the safest thing is to not set it.

Quoted 6 lines

Yeah, that's because I have a too vague idea on what is the purpose of the unthrottle() callback.

I've read the concerned codes that call this, several times, and I still can't figure out what happens there, not sure what is meant by throttle or unthrottle there :-/

OK, so not setting it is relatively safe.

As to what it does, it has to undo everything you do when perf_event_overflow() returns true, which happens when ->unthrottle is set and we get more than sysctl_perf_event_sample_rate/HZ events in a jiffy.

If you look at the x86 implementation, you'll see that we simply disable the hardware counter when the overflow call returns true, so the unthrottle() callback simply enables it again.

#20 lore raw

2010/1/19 Peter Zijlstra <[email protected]>:

Quoted 16 lines · Frederic Weisbecker
Quoted 6 lines
Quoted 4 lines

Also, I see you set an ->unthrottle, but then don't implement it, but comment it as todo, which is strange because that implies its broken. If there's an ->unthrottle method it will throttle, so if its todo, the safest thing is to not set it.

Quoted 6 lines

Yeah, that's because I have a too vague idea on what is the purpose of the unthrottle() callback.

I've read the concerned codes that call this, several times, and I still can't figure out what happens there, not sure what is meant by throttle or unthrottle there :-/

OK, so not setting it is relatively safe.

Quoted 8 lines

As to what it does, it has to undo everything you do when perf_event_overflow() returns true, which happens when ->unthrottle is set and we get more than sysctl_perf_event_sample_rate/HZ events in a jiffy.

If you look at the x86 implementation, you'll see that we simply disable the hardware counter when the overflow call returns true, so the unthrottle() callback simply enables it again.

Ok, I understand better now what mean "throttle" and "unthrottle" here.

But looking at what happens when we reach an event storm point, the pending and subsequent
overflows until the next tick are just cancelled and that's it (as it's using the software overflow
handler, not the x86 one). So we throttle and it's what we would want to avoid a hang. If I remove my
unthrottle stub, it won't throttle anymore.

Theorically, the best would be to implement a true unthrottle callback, which would just clear dr7,
really trivial. But I don't like this as ptrace events must always be reported. A userspace app
could be polling a watchpointed variable, causing a lot of events, may be that could trigger
a storm and then perf would throttle. Sure this is not supposed to happen, given the fact ptrace breakpoints
are signaled to a debugger, which reduces the possible storm windows. But just imagine a silly user sets sysctl_perf_event_sample_rate to 1, then we would throttle at
each events, breaking the ptrace determinism rules.

So for now, I guess I need to remove my unthrottle stub, breakpoints don't want to throttle because
of the ptrace determinism requirements.

#21 lore raw
In reply to Peter Zijlstra
Quoted 35 lines · Peter Zijlstra
Quoted 3 lines · Frederic Weisbecker

It has constraints that only need to be checked when we register the event. It has also constraint on enable time but nothing tricky that requires an overwritten group scheduling.

The fact that ->enable() can fail makes it a hardware counter. Software counters cannot fail enable.

Having multiple groups of failable events (multiple hardware pmus) can go wrong with the current core in interesting ways, look for example at __perf_event_sched_in():

It does:

	int can_add_hw = 1;

	...

	list_for_each_entry(event, &ctx->flexible_groups, group_entry) {
		/* Ignore events in OFF or ERROR state */
		if (event->state <= PERF_EVENT_STATE_OFF)
			continue;
		/*
		 * Listen to the 'cpu' scheduling filter constraint
		 * of events:
		 */
		if (event->cpu != -1 && event->cpu != cpu)
			continue;

		if (group_can_go_on(event, cpuctx, can_add_hw))
			if (group_sched_in(event, cpuctx, ctx, cpu))
				can_add_hw = 0;
	}
Quoted 4 lines

Now, if you look at that logic you'll see that it assumes there's one hw device since it only has one can_add_hw state. So if your hw_breakpoint pmu starts to fail we'll also stop adding counters to the cpu pmu (for lack of a better name) and vs.

Indeed.

Quoted 2 lines

This might be fixable by using per-cpu struct pmu variables.

Yeah or just a mask instead of can_add_hw that can testify a given pmu type couldn't be scheduled anymore?

We can extend struct perf_event:group_flags:

enum perf_group_flag {
	PERF_GROUP_NO_HARDWARE = 0x1,
	PERF_GROUP_NO_BREAKPOINT = 0x2
	PERF_GROUP_SOFTWARE = PERF_GROUP_NO_HARDWARE | PERF_GROUP_NO_BREAKPOINT;
};

Looks easy to maintain and to use for quick bitwise check on flexible groups scheduling.

Quoted 3 lines

However I'm afraid its far to late to push any of that into .33, which means .33 will have rather funny behaviour once the breakpoints start getting used.

No. Because for now it is not supposed to happen that a breakpoint can't be scheduled.

We have constraints that check whether a pinned breakpoint will always be able to go in, on registration. Similarly we have constraints for flexible ones, to ensure it's possible for these to be scheduled. But these are broken because of the non-strict ordering between pinned and non-pinned events.

Anyway, the point is that for now we treat flexible breakpoints as if these were pinned, so a breakpoint is not supposed to be unschedulable, ever. So .33 is not broken.

But we need to fix what you described for .34, because once we get a strict ordering between pinned and flexible, I'm going to reactivate the breakpoint constraints for flexibles.

#22 lore raw
In reply to Frederic Weisbecker
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here }

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

I don't think this model can work without scheduling for each event.

Imagine the situation where you have more events than you have counters. At each tick you:
- disable all events
- rotate the list
- collect events from the list
- schedule events
- activate

Collection is the accumulation of events until you have as many as you have counters
given you defer scheduling until the end (see loop above).

But that does not mean you can schedule what you have accumulated. And then what do you do, i.e., rollback to what?

With incremental, you can skip a group that is conflicting with the groups already
accumulated. What hw_perf_group_sched_in() gives you is simply a way to do incremental on a whole event group at once.

Given the perf_event model, I believe you have no other way but to do incremental
scheduling of events. That is the only way you guarantee you maximize the use of the PMU. Regardless of that, the scheduling model has a bias towards smaller and less constrained event groups.

maintainer
#23 lore raw
Quoted 13 lines · Stephane Eranian
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here
}
if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}
Quoted 8 lines
Quoted 3 lines
Quoted 3 lines
Quoted 2 lines

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

I don't think this model can work without scheduling for each event.

Imagine the situation where you have more events than you have counters. At each tick you:

No it wont indeed, but it will work for where we now use hw_perf_group_sched_in() without having to replicate lots of code.

For the cases you mention I see no other way than to try and schedule each event individually.

#24 lore raw
Quoted 20 lines · Peter Zijlstra
Quoted 19 lines · Stephane Eranian
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here }

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

I don't think this model can work without scheduling for each event.

Quoted 9 lines
Quoted 2 lines

Imagine the situation where you have more events than you have counters. At each tick you:

No it wont indeed, but it will work for where we now use hw_perf_group_sched_in() without having to replicate lots of code.

For the cases you mention I see no other way than to try and schedule each event individually.

Are you suggesting a speculative approach where you first try simply accumulate then schedule and if this fails, then restart the whole loop but this time adding and scheduling each event individually? For groups, you'd have to fail the group if one of its events fails.

maintainer
#25 lore raw
Quoted 4 lines · Stephane Eranian

Are you suggesting a speculative approach where you first try simply accumulate then schedule and if this fails, then restart the whole loop but this time adding and scheduling each event individually? For groups, you'd have to fail the group if one of its events fails.

No, I'm only talking about groups. The complaint from frederic was that current hw_perf_group_sched_in() implementations have to basically replicate all of the group_sched_in() and event_sched_in() stuff, which seems wasteful.

So I was thinking of an alternative interface that would give the same end result but not as much code replication.

I'm now leaning towards adding a parameter to ->enable() to postpone schedulability and add a hw_perf_validate() like call.

With that I'm also looking at what would be the sanest way to multiplex all the current weak hw_perf* functions in the light of multiple pmu implementations.

#26 lore raw
Quoted 7 lines · Peter Zijlstra
Quoted 4 lines · Stephane Eranian

Are you suggesting a speculative approach where you first try simply accumulate then schedule and if this fails, then restart the whole loop but this time adding and scheduling each event individually? For groups, you'd have to fail the group if one of its events fails.

Quoted 5 lines

No, I'm only talking about groups. The complaint from frederic was that current hw_perf_group_sched_in() implementations have to basically replicate all of the group_sched_in() and event_sched_in() stuff, which seems wasteful.

I agree about the replication problem. But this comes from the fact that if you call hw_perf_group_sched_in() and you succeed, you want to only execute part of what group_sched_in() normally does, namely mark the event as active, update timing but skip event_sched_in() stuff, incl. enable(). Actual activation is deferred until perf_enable() which avoids having some events actually measuring while you are still scheduling events.

Quoted 11 lines

So I was thinking of an alternative interface that would give the same end result but not as much code replication.

I'm now leaning towards adding a parameter to ->enable() to postpone schedulability and add a hw_perf_validate() like call.

With that I'm also looking at what would be the sanest way to multiplex all the current weak hw_perf* functions in the light of multiple pmu implementations.

Signature · 8 lines
Stephane Eranian  | EMEA Software Engineering
Google France | 38 avenue de l'Opéra | 75002 Paris
Tel : +33 (0) 1 42 68 53 00
This email may be confidential or privileged. If you received this
communication by mistake, please
don't forward it to anyone else, please erase all copies and
attachments, and please let me know that
it went to the wrong person. Thanks
#27 lore raw
In reply to Stephane Eranian
Quoted 27 lines · Stephane Eranian
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here }

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

I don't think this model can work without scheduling for each event.

Imagine the situation where you have more events than you have counters. At each tick you:
- disable all events
- rotate the list
- collect events from the list
- schedule events
- activate

Quoted 6 lines

Collection is the accumulation of events until you have as many as you have counters
given you defer scheduling until the end (see loop above).

But that does not mean you can schedule what you have accumulated. And then what do you do, i.e., rollback to what?

If the scheduling validation fails, then you just need to rollback the whole group.

That's sensibly what you did in your patch, right? Except the loop is now handled by the core code.

Quoted 5 lines

With incremental, you can skip a group that is conflicting with the groups already
accumulated. What hw_perf_group_sched_in() gives you is simply a way to do incremental on a whole event group at once.

I don't understand why that can't be done with the above model. In your patch we iterate through the whole group, collect events, and schedule them.

With the above, the collection is just done on enable(), and the scheduling is done with the new pmu callbacks.

The thing is sensibly the same, where is the obstacle?

Quoted 6 lines

Given the perf_event model, I believe you have no other way but to do incremental
scheduling of events. That is the only way you guarantee you maximize the use of the PMU. Regardless of that, the scheduling model has a bias towards smaller and less constrained event groups.

But the incremental is still the purpose of the above model. I feel confused.

#28 lore raw
Quoted 37 lines · Frederic Weisbecker
Quoted 27 lines · Stephane Eranian
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

Do you mean this:

hw_perf_group_sched_in_begin(&x86_pmu);

for_each_event(event, group) {
        event->enable();        //do the collection here }

Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

if (hw_perf_group_sched_in_end(&x86_pmu)) {
        rollback...
}

That requires to know in advance if we have hardware pmu in the list though (can be a flag in the group).

I don't think this model can work without scheduling for each event.

Imagine the situation where you have more events than you have counters. At each tick you:
   - disable all events
   - rotate the list
   - collect events from the list
   - schedule events
   - activate

Quoted 6 lines

Collection is the accumulation of events until you have as many as you have counters
given you defer scheduling until the end (see loop above).

But that does not mean you can schedule what you have accumulated. And then what do you do, i.e., rollback to what?

Quoted 7 lines

If the scheduling validation fails, then you just need to rollback the whole group.

That's sensibly what you did in your patch, right? Except the loop is now handled by the core code.

Ok, I think I missed where you were actually placing that loop. So you want to do this in group_sched_in(), right?

Quoted 10 lines

I don't understand why that can't be done with the above model. In your patch we iterate through the whole group, collect events, and schedule them.

With the above, the collection is just done on enable(), and the scheduling is done with the new pmu callbacks.

The thing is sensibly the same, where is the obstacle?

There is none. You've just hoisted the some of the code from hw_perf_group_sched_in().

#29 lore raw
Quoted 9 lines · Stephane Eranian
Quoted 7 lines

If the scheduling validation fails, then you just need to rollback the whole group.

That's sensibly what you did in your patch, right? Except the loop is now handled by the core code.

Ok, I think I missed where you were actually placing that loop. So you want to do this in group_sched_in(), right?

Exactly!

Quoted 5 lines
Quoted 5 lines

I don't understand why that can't be done with the above model. In your patch we iterate through the whole group, collect events, and schedule them.

Quoted 7 lines
Quoted 5 lines

With the above, the collection is just done on enable(), and the scheduling is done with the new pmu callbacks.

The thing is sensibly the same, where is the obstacle?

There is none. You've just hoisted the some of the code from hw_perf_group_sched_in().

Exactly :)

maintainer
#30 lore raw
In reply to Frederic Weisbecker
Quoted 8 lines · Frederic Weisbecker
Quoted 4 lines

Then there's still the question of having events of multiple hw pmus in a single group, I'd be perfectly fine with saying that's not allowed, what to others think?

I guess we need that. It can be insteresting to couple hardware counters with memory accesses...or whatever.

That really depends on how easy it is to correlate events from the various pmus. This case could indeed do that, but the core vs uncore tihng is a lot less clear.

Quoted 2 lines

Perf stat combines cache miss counting with page faults, cpu clock counters.

perf stat also doesn't use groups and it still works quite nicely.

Quoted 2 lines

We shouldn't limit such possibilities for technical/cleanliness reasons. We should rather adapt.

Maybe, I'm not a very big fan of groups myself, but they are clearly useful within a pmu, measuring cache misses through total-access for example, but the use between pmus is questionable.

But sure, if we can do it without too much pain, that's fine.

#31 lore raw
Quoted 7 lines · Peter Zijlstra
Quoted 6 lines · Frederic Weisbecker
Quoted 4 lines

Then there's still the question of having events of multiple hw pmus in a single group, I'd be perfectly fine with saying that's not allowed, what to others think?

Quoted 6 lines
Quoted 2 lines

I guess we need that. It can be insteresting to couple hardware counters with memory accesses...or whatever.

That really depends on how easy it is to correlate events from the various pmus. This case could indeed do that, but the core vs uncore tihng is a lot less clear.

Not sure what you both mean by this core VS uncore thing :) Is it about hardware counters that apply to single hardware threads or shared among them inside a same core?

Quoted 4 lines
Quoted 2 lines

Perf stat combines cache miss counting with page faults, cpu clock counters.

perf stat also doesn't use groups and it still works quite nicely.

Ah? I thought it does.

Quoted 6 lines
Quoted 2 lines

We shouldn't limit such possibilities for technical/cleanliness reasons. We should rather adapt.

Maybe, I'm not a very big fan of groups myself, but they are clearly useful within a pmu, measuring cache misses through total-access for example, but the use between pmus is questionable.

Cross pmu, these seem to only make sense for non pinned groups. If you want two non-pinned counters to be paired and not randomly and separately scheduled.

For other cases, indeed I'm not sure it is useful :)

maintainer
#32 lore raw
Quoted 3 lines · Frederic Weisbecker

Not sure what you both mean by this core VS uncore thing :) Is it about hardware counters that apply to single hardware threads or shared among them inside a same core?

Yeah intel has two PMUs, one per logical cpu and one per socket/node. We currently don't support the node one yet.

So the thing with these socket wide things is is that they are not able to tell where the event originated, so relating that back to a task is only possible when there's only one task running.

#33 lore raw
Quoted 6 lines · Peter Zijlstra
Quoted 3 lines · Frederic Weisbecker

Not sure what you both mean by this core VS uncore thing :) Is it about hardware counters that apply to single hardware threads or shared among them inside a same core?

Quoted 7 lines

Yeah intel has two PMUs, one per logical cpu and one per socket/node. We currently don't support the node one yet.

So the thing with these socket wide things is is that they are not able to tell where the event originated, so relating that back to a task is only possible when there's only one task running.

Ah ok.

maintainer
#34 lore raw
In reply to Stephane Eranian

arch/x86/kernel/cpu/perf_event.c static void amd_pmu_enable_all(void) · line 1441

Quoted 6 lines · Stephane Eranian

void hw_perf_enable(void)
{

arch/x86/kernel/cpu/perf_event.c +2 -0
+               cpuc->n_added = 0;
+               perf_events_lapic_init();

Just wondering, why do we need that lapic_init() there?

Quoted 3 lines

+ }

        x86_pmu.enable_all();

}

#35 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 6 lines · Stephane Eranian

 void hw_perf_enable(void)
 {

+               cpuc->n_added = 0;
+               perf_events_lapic_init();

Just wondering, why do we need that lapic_init() there?

I think I picked it up from x86_pmu_enable(). I don't think you necessarily need it here. Not clear to me why it was in x86_pmu_enable() to begin with.

I will post a new version of the patch which fixes some bugs and also implements true fast path (reuse of previous assignment). It turned out, things were a bit more complicated than what I had in v5.

maintainer
#36 lore raw
Quoted 6 lines · Stephane Eranian
Quoted 5 lines · Peter Zijlstra
Quoted 2 lines · Stephane Eranian

void hw_perf_enable(void)
{

Quoted 8 lines
Quoted 5 lines

arch/x86/kernel/cpu/perf_event.c static void amd_pmu_enable_all(void) · line 1441

Quoted 2 lines
arch/x86/kernel/cpu/perf_event.c +2 -0
+               cpuc->n_added = 0;
+               perf_events_lapic_init();

Just wondering, why do we need that lapic_init() there?

I think I picked it up from x86_pmu_enable(). I don't think you necessarily need it here. Not clear to me why it was in x86_pmu_enable() to begin with.

Right, wondering about the same ;-)

Quoted 3 lines

I will post a new version of the patch which fixes some bugs and also implements true fast path (reuse of previous assignment). It turned out, things were a bit more complicated than what I had in v5.

Could you post a diff against your previous version, I just picked up -v5 and tidied a few things up and send it mingo wards (although it appears he hasn't picked it up yet).

#37 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 9 lines · Stephane Eranian
Quoted 8 lines · Peter Zijlstra
Quoted 6 lines · Stephane Eranian

 void hw_perf_enable(void)
 {

+               cpuc->n_added = 0;
+               perf_events_lapic_init();

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

Just wondering, why do we need that lapic_init() there?

I think I picked it up from x86_pmu_enable(). I don't think you necessarily need it here. Not clear to me why it was in x86_pmu_enable() to begin with.

Right, wondering about the same ;-)

I suspect this is because on Intel, you need to re-initialize the APIC LVT entry on PMU interrupt. You don't have to do this on AMD.

But then, this should be done when you initialize the PMU for the first event and on every CPU and in the Intel interrupt handler.

Quoted 8 lines
Quoted 3 lines

I will post a new version of the patch which fixes some bugs and also implements true fast path (reuse of previous assignment). It turned out, things were a bit more complicated than what I had in v5.

Could you post a diff against your previous version, I just picked up -v5 and tidied a few things up and send it mingo wards (although it appears he hasn't picked it up yet).

Will do that shortly.

#38 lore raw

[tip:perf/urgent] perf: x86: Add support for the ANY bit

In reply to Stephane Eranian
Commit-ID:  b27d515a49169e5e2a92d621faac761074a8c5b1
Gitweb:     http://git.kernel.org/tip/b27d515a49169e5e2a92d621faac761074a8c5b1
Author:     Stephane Eranian <[email protected]>
AuthorDate: Mon, 18 Jan 2010 10:58:01 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Thu, 21 Jan 2010 13:40:41 +0100

perf: x86: Add support for the ANY bit

Propagate the ANY bit into the fixed counter config for v3 and higher.

LKML-Reference: <[email protected]>

---
 arch/x86/include/asm/perf_event.h |    1 +
 arch/x86/kernel/cpu/perf_event.c  |    7 +++++++
 2 files changed, 8 insertions(+), 0 deletions(-)
arch/x86/include/asm/perf_event.h +1 -0
index 8d9f854..1380367 100644
@@ -19,6 +19,7 @@
 #define MSR_ARCH_PERFMON_EVENTSEL1			     0x187
 
 #define ARCH_PERFMON_EVENTSEL0_ENABLE			  (1 << 22)
+#define ARCH_PERFMON_EVENTSEL_ANY			  (1 << 21)
 #define ARCH_PERFMON_EVENTSEL_INT			  (1 << 20)
 #define ARCH_PERFMON_EVENTSEL_OS			  (1 << 17)
 #define ARCH_PERFMON_EVENTSEL_USR			  (1 << 16)
arch/x86/kernel/cpu/perf_event.c +7 -0
index d616c06..8c1c070 100644
@@ -1343,6 +1343,13 @@ intel_pmu_enable_fixed(struct hw_perf_event *hwc, int __idx)
 		bits |= 0x2;
 	if (hwc->config & ARCH_PERFMON_EVENTSEL_OS)
 		bits |= 0x1;
+
+	/*
+	 * ANY bit is supported in v3 and up
+	 */
+	if (x86_pmu.version > 2 && hwc->config & ARCH_PERFMON_EVENTSEL_ANY)
+		bits |= 0x4;
+
 	bits <<= (idx * 4);
 	mask = 0xfULL << (idx * 4);
 
#39 lore raw

[tip:perf/core] perf_events, x86: Improve x86 event scheduling

In reply to Stephane Eranian
Commit-ID:  1da53e023029c067ba1277a33038c65d6e4c99b3
Gitweb:     http://git.kernel.org/tip/1da53e023029c067ba1277a33038c65d6e4c99b3
Author:     Stephane Eranian <[email protected]>
AuthorDate: Mon, 18 Jan 2010 10:58:01 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 29 Jan 2010 09:01:33 +0100

perf_events, x86: Improve x86 event scheduling

This patch improves event scheduling by maximizing the use of PMU registers regardless of the order in which events are created in a group.

The algorithm takes into account the list of counter constraints for each event. It assigns events to counters from the most constrained, i.e., works on only one counter, to the least constrained, i.e., works on any counter.

Intel Fixed counter events and the BTS special event are also handled via this algorithm which is designed to be fairly generic.

The patch also updates the validation of an event to use the scheduling algorithm. This will cause early failure in perf_event_open().

The 2nd version of this patch follows the model used by PPC, by running the scheduling algorithm and the actual assignment separately. Actual assignment takes place in hw_perf_enable() whereas scheduling is implemented in hw_perf_group_sched_in() and x86_pmu_enable().

[ fixup whitespace and style nits as well as adding is_x86_event() ]
Cc Mike Galbraith <[email protected]>
Cc Paul Mackerras <[email protected]>
Cc Arnaldo Carvalho de Melo <[email protected]>
Cc Frederic Weisbecker <[email protected]>

LKML-Reference: <[email protected]>

---
 arch/x86/include/asm/perf_event.h |   16 +-
 arch/x86/kernel/cpu/perf_event.c  |  775 +++++++++++++++++++++++++++----------
 2 files changed, 574 insertions(+), 217 deletions(-)
arch/x86/include/asm/perf_event.h +14 -2
index 8d9f854..dbc0826 100644
@@ -26,7 +26,14 @@
 /*
  * Includes eventsel and unit mask as well:
  */
-#define ARCH_PERFMON_EVENT_MASK				    0xffff
+
+
+#define INTEL_ARCH_EVTSEL_MASK		0x000000FFULL
+#define INTEL_ARCH_UNIT_MASK		0x0000FF00ULL
+#define INTEL_ARCH_EDGE_MASK		0x00040000ULL
+#define INTEL_ARCH_INV_MASK		0x00800000ULL
+#define INTEL_ARCH_CNT_MASK		0xFF000000ULL
+#define INTEL_ARCH_EVENT_MASK	(INTEL_ARCH_UNIT_MASK|INTEL_ARCH_EVTSEL_MASK)
 
 /*
  * filter mask to validate fixed counter events.
@@ -37,7 +44,12 @@
  *  The other filters are supported by fixed counters.
  *  The any-thread option is supported starting with v3.
  */
-#define ARCH_PERFMON_EVENT_FILTER_MASK			0xff840000
+#define INTEL_ARCH_FIXED_MASK \
+	(INTEL_ARCH_CNT_MASK| \
+	 INTEL_ARCH_INV_MASK| \
+	 INTEL_ARCH_EDGE_MASK|\
+	 INTEL_ARCH_UNIT_MASK|\
+	 INTEL_ARCH_EVENT_MASK)
 
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL		      0x3c
 #define ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK		(0x00 << 8)
arch/x86/kernel/cpu/perf_event.c +560 -215

951 lines not on this page · raw message