aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-10-08 05:56:07 -0400
committerIngo Molnar <mingo@elte.hu>2009-10-09 09:56:14 -0400
commitfe9081cc9bdabb0be953a39ad977cea14e35bce5 (patch)
treee4b18495cbbade72da915b825dd39aef0cefd5d5 /arch
parentb690081d4d3f6a23541493f1682835c3cd5c54a1 (diff)
perf, x86: Add simple group validation
Refuse to add events when the group wouldn't fit onto the PMU anymore. Naive implementation. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@gmail.com> LKML-Reference: <1254911461.26976.239.camel@twins> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/cpu/perf_event.c90
1 files changed, 69 insertions, 21 deletions
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 9c758548a0e6..9961d845719d 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -114,7 +114,8 @@ struct x86_pmu {
114 u64 intel_ctrl; 114 u64 intel_ctrl;
115 void (*enable_bts)(u64 config); 115 void (*enable_bts)(u64 config);
116 void (*disable_bts)(void); 116 void (*disable_bts)(void);
117 int (*get_event_idx)(struct hw_perf_event *hwc); 117 int (*get_event_idx)(struct cpu_hw_events *cpuc,
118 struct hw_perf_event *hwc);
118}; 119};
119 120
120static struct x86_pmu x86_pmu __read_mostly; 121static struct x86_pmu x86_pmu __read_mostly;
@@ -523,7 +524,7 @@ static u64 intel_pmu_raw_event(u64 hw_event)
523#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL 524#define CORE_EVNTSEL_UNIT_MASK 0x0000FF00ULL
524#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL 525#define CORE_EVNTSEL_EDGE_MASK 0x00040000ULL
525#define CORE_EVNTSEL_INV_MASK 0x00800000ULL 526#define CORE_EVNTSEL_INV_MASK 0x00800000ULL
526#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL 527#define CORE_EVNTSEL_REG_MASK 0xFF000000ULL
527 528
528#define CORE_EVNTSEL_MASK \ 529#define CORE_EVNTSEL_MASK \
529 (CORE_EVNTSEL_EVENT_MASK | \ 530 (CORE_EVNTSEL_EVENT_MASK | \
@@ -1390,8 +1391,7 @@ static void amd_pmu_enable_event(struct hw_perf_event *hwc, int idx)
1390 x86_pmu_enable_event(hwc, idx); 1391 x86_pmu_enable_event(hwc, idx);
1391} 1392}
1392 1393
1393static int 1394static int fixed_mode_idx(struct hw_perf_event *hwc)
1394fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
1395{ 1395{
1396 unsigned int hw_event; 1396 unsigned int hw_event;
1397 1397
@@ -1424,9 +1424,9 @@ fixed_mode_idx(struct perf_event *event, struct hw_perf_event *hwc)
1424/* 1424/*
1425 * generic counter allocator: get next free counter 1425 * generic counter allocator: get next free counter
1426 */ 1426 */
1427static int gen_get_event_idx(struct hw_perf_event *hwc) 1427static int
1428gen_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
1428{ 1429{
1429 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
1430 int idx; 1430 int idx;
1431 1431
1432 idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events); 1432 idx = find_first_zero_bit(cpuc->used_mask, x86_pmu.num_events);
@@ -1436,16 +1436,16 @@ static int gen_get_event_idx(struct hw_perf_event *hwc)
1436/* 1436/*
1437 * intel-specific counter allocator: check event constraints 1437 * intel-specific counter allocator: check event constraints
1438 */ 1438 */
1439static int intel_get_event_idx(struct hw_perf_event *hwc) 1439static int
1440intel_get_event_idx(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
1440{ 1441{
1441 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
1442 const struct event_constraint *event_constraint; 1442 const struct event_constraint *event_constraint;
1443 int i, code; 1443 int i, code;
1444 1444
1445 if (!event_constraint) 1445 if (!event_constraint)
1446 goto skip; 1446 goto skip;
1447 1447
1448 code = hwc->config & 0xff; 1448 code = hwc->config & CORE_EVNTSEL_EVENT_MASK;
1449 1449
1450 for_each_event_constraint(event_constraint, event_constraint) { 1450 for_each_event_constraint(event_constraint, event_constraint) {
1451 if (code == event_constraint->code) { 1451 if (code == event_constraint->code) {
@@ -1457,26 +1457,22 @@ static int intel_get_event_idx(struct hw_perf_event *hwc)
1457 } 1457 }
1458 } 1458 }
1459skip: 1459skip:
1460 return gen_get_event_idx(hwc); 1460 return gen_get_event_idx(cpuc, hwc);
1461} 1461}
1462 1462
1463/* 1463static int
1464 * Find a PMC slot for the freshly enabled / scheduled in event: 1464x86_schedule_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc)
1465 */
1466static int x86_pmu_enable(struct perf_event *event)
1467{ 1465{
1468 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
1469 struct hw_perf_event *hwc = &event->hw;
1470 int idx; 1466 int idx;
1471 1467
1472 idx = fixed_mode_idx(event, hwc); 1468 idx = fixed_mode_idx(hwc);
1473 if (idx == X86_PMC_IDX_FIXED_BTS) { 1469 if (idx == X86_PMC_IDX_FIXED_BTS) {
1474 /* BTS is already occupied. */ 1470 /* BTS is already occupied. */
1475 if (test_and_set_bit(idx, cpuc->used_mask)) 1471 if (test_and_set_bit(idx, cpuc->used_mask))
1476 return -EAGAIN; 1472 return -EAGAIN;
1477 1473
1478 hwc->config_base = 0; 1474 hwc->config_base = 0;
1479 hwc->event_base = 0; 1475 hwc->event_base = 0;
1480 hwc->idx = idx; 1476 hwc->idx = idx;
1481 } else if (idx >= 0) { 1477 } else if (idx >= 0) {
1482 /* 1478 /*
@@ -1499,17 +1495,33 @@ static int x86_pmu_enable(struct perf_event *event)
1499 /* Try to get the previous generic event again */ 1495 /* Try to get the previous generic event again */
1500 if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) { 1496 if (idx == -1 || test_and_set_bit(idx, cpuc->used_mask)) {
1501try_generic: 1497try_generic:
1502 idx = x86_pmu.get_event_idx(hwc); 1498 idx = x86_pmu.get_event_idx(cpuc, hwc);
1503 if (idx == -1) 1499 if (idx == -1)
1504 return -EAGAIN; 1500 return -EAGAIN;
1505 1501
1506 set_bit(idx, cpuc->used_mask); 1502 set_bit(idx, cpuc->used_mask);
1507 hwc->idx = idx; 1503 hwc->idx = idx;
1508 } 1504 }
1509 hwc->config_base = x86_pmu.eventsel; 1505 hwc->config_base = x86_pmu.eventsel;
1510 hwc->event_base = x86_pmu.perfctr; 1506 hwc->event_base = x86_pmu.perfctr;
1511 } 1507 }
1512 1508
1509 return idx;
1510}
1511
1512/*
1513 * Find a PMC slot for the freshly enabled / scheduled in event:
1514 */
1515static int x86_pmu_enable(struct perf_event *event)
1516{
1517 struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
1518 struct hw_perf_event *hwc = &event->hw;
1519 int idx;
1520
1521 idx = x86_schedule_event(cpuc, hwc);
1522 if (idx < 0)
1523 return idx;
1524
1513 perf_events_lapic_init(); 1525 perf_events_lapic_init();
1514 1526
1515 x86_pmu.disable(hwc, idx); 1527 x86_pmu.disable(hwc, idx);
@@ -2212,11 +2224,47 @@ static const struct pmu pmu = {
2212 .unthrottle = x86_pmu_unthrottle, 2224 .unthrottle = x86_pmu_unthrottle,
2213}; 2225};
2214 2226
2227static int
2228validate_event(struct cpu_hw_events *cpuc, struct perf_event *event)
2229{
2230 struct hw_perf_event fake_event = event->hw;
2231
2232 if (event->pmu != &pmu)
2233 return 0;
2234
2235 return x86_schedule_event(cpuc, &fake_event);
2236}
2237
2238static int validate_group(struct perf_event *event)
2239{
2240 struct perf_event *sibling, *leader = event->group_leader;
2241 struct cpu_hw_events fake_pmu;
2242
2243 memset(&fake_pmu, 0, sizeof(fake_pmu));
2244
2245 if (!validate_event(&fake_pmu, leader))
2246 return -ENOSPC;
2247
2248 list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
2249 if (!validate_event(&fake_pmu, sibling))
2250 return -ENOSPC;
2251 }
2252
2253 if (!validate_event(&fake_pmu, event))
2254 return -ENOSPC;
2255
2256 return 0;
2257}
2258
2215const struct pmu *hw_perf_event_init(struct perf_event *event) 2259const struct pmu *hw_perf_event_init(struct perf_event *event)
2216{ 2260{
2217 int err; 2261 int err;
2218 2262
2219 err = __hw_perf_event_init(event); 2263 err = __hw_perf_event_init(event);
2264 if (!err) {
2265 if (event->group_leader != event)
2266 err = validate_group(event);
2267 }
2220 if (err) { 2268 if (err) {
2221 if (event->destroy) 2269 if (event->destroy)
2222 event->destroy(event); 2270 event->destroy(event);