perf_events: improve x86 event scheduling (v5)
Subsystems (2)
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
@@ -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
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?
Peter Zijlstra
maintainerQuoted 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?
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.
Peter Zijlstra
maintainerQuoted 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.
Peter Zijlstra
maintainerQuoted 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)inthw_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 untilhw_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 theevent_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.
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)inthw_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?
Peter Zijlstra
maintainerQuoted 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 fromhw_perf_group_sched_in()that callsx86_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.
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 fromhw_perf_group_sched_in()that callsx86_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.
Peter Zijlstra
maintainerQuoted 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.
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.
Peter Zijlstra
maintainerQuoted 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.
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.
Peter Zijlstra
maintainerQuoted 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 betweenperf_disable()andperf_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.
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 betweenperf_disable()andperf_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.
Peter Zijlstra
maintainerQuoted 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 betweenperf_disable()andperf_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.
Peter Zijlstra
maintainerQuoted 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.
Peter Zijlstra
maintainerQuoted 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_hwstate. So if yourhw_breakpointpmu 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.
Quoted 3 lines · Peter Zijlstra
Hrmph, so I read some of that
hw_breakpointstuff, 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 :)
Peter Zijlstra
maintainerQuoted 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.
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.
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_hwstate. So if yourhw_breakpointpmu 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.
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.
Peter Zijlstra
maintainerQuoted 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.
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.
Peter Zijlstra
maintainerQuoted 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.
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 thegroup_sched_in()andevent_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
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. Whathw_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_eventmodel, 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.
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
- activateQuoted 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().
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 :)
Peter Zijlstra
maintainerQuoted 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.
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 :)
Peter Zijlstra
maintainerQuoted 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.
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.
Peter Zijlstra
maintainerarch/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();}
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.
Peter Zijlstra
maintainerQuoted 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 inx86_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).
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 inx86_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.
[tip:perf/urgent] perf: x86: Add support for the ANY bit
In reply to Stephane EranianCommit-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
@@ -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
@@ -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 );
[tip:perf/core] perf_events, x86: Improve x86 event scheduling
In reply to Stephane EranianCommit-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().
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
@@ -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