diff options
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 0fe22c916e29..eeb1b46cf707 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1328,6 +1328,185 @@ static const struct file_operations perf_fops = { | |||
1328 | .compat_ioctl = perf_ioctl, | 1328 | .compat_ioctl = perf_ioctl, |
1329 | }; | 1329 | }; |
1330 | 1330 | ||
1331 | /* | ||
1332 | * Generic software counter infrastructure | ||
1333 | */ | ||
1334 | |||
1335 | static void perf_swcounter_update(struct perf_counter *counter) | ||
1336 | { | ||
1337 | struct hw_perf_counter *hwc = &counter->hw; | ||
1338 | u64 prev, now; | ||
1339 | s64 delta; | ||
1340 | |||
1341 | again: | ||
1342 | prev = atomic64_read(&hwc->prev_count); | ||
1343 | now = atomic64_read(&hwc->count); | ||
1344 | if (atomic64_cmpxchg(&hwc->prev_count, prev, now) != prev) | ||
1345 | goto again; | ||
1346 | |||
1347 | delta = now - prev; | ||
1348 | |||
1349 | atomic64_add(delta, &counter->count); | ||
1350 | atomic64_sub(delta, &hwc->period_left); | ||
1351 | } | ||
1352 | |||
1353 | static void perf_swcounter_set_period(struct perf_counter *counter) | ||
1354 | { | ||
1355 | struct hw_perf_counter *hwc = &counter->hw; | ||
1356 | s64 left = atomic64_read(&hwc->period_left); | ||
1357 | s64 period = hwc->irq_period; | ||
1358 | |||
1359 | if (unlikely(left <= -period)) { | ||
1360 | left = period; | ||
1361 | atomic64_set(&hwc->period_left, left); | ||
1362 | } | ||
1363 | |||
1364 | if (unlikely(left <= 0)) { | ||
1365 | left += period; | ||
1366 | atomic64_add(period, &hwc->period_left); | ||
1367 | } | ||
1368 | |||
1369 | atomic64_set(&hwc->prev_count, -left); | ||
1370 | atomic64_set(&hwc->count, -left); | ||
1371 | } | ||
1372 | |||
1373 | static void perf_swcounter_save_and_restart(struct perf_counter *counter) | ||
1374 | { | ||
1375 | perf_swcounter_update(counter); | ||
1376 | perf_swcounter_set_period(counter); | ||
1377 | } | ||
1378 | |||
1379 | static void perf_swcounter_store_irq(struct perf_counter *counter, u64 data) | ||
1380 | { | ||
1381 | struct perf_data *irqdata = counter->irqdata; | ||
1382 | |||
1383 | if (irqdata->len > PERF_DATA_BUFLEN - sizeof(u64)) { | ||
1384 | irqdata->overrun++; | ||
1385 | } else { | ||
1386 | u64 *p = (u64 *) &irqdata->data[irqdata->len]; | ||
1387 | |||
1388 | *p = data; | ||
1389 | irqdata->len += sizeof(u64); | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | static void perf_swcounter_handle_group(struct perf_counter *sibling) | ||
1394 | { | ||
1395 | struct perf_counter *counter, *group_leader = sibling->group_leader; | ||
1396 | |||
1397 | list_for_each_entry(counter, &group_leader->sibling_list, list_entry) { | ||
1398 | perf_swcounter_update(counter); | ||
1399 | perf_swcounter_store_irq(sibling, counter->hw_event.type); | ||
1400 | perf_swcounter_store_irq(sibling, atomic64_read(&counter->count)); | ||
1401 | } | ||
1402 | } | ||
1403 | |||
1404 | static void perf_swcounter_interrupt(struct perf_counter *counter, | ||
1405 | int nmi, struct pt_regs *regs) | ||
1406 | { | ||
1407 | perf_swcounter_save_and_restart(counter); | ||
1408 | |||
1409 | switch (counter->hw_event.record_type) { | ||
1410 | case PERF_RECORD_SIMPLE: | ||
1411 | break; | ||
1412 | |||
1413 | case PERF_RECORD_IRQ: | ||
1414 | perf_swcounter_store_irq(counter, instruction_pointer(regs)); | ||
1415 | break; | ||
1416 | |||
1417 | case PERF_RECORD_GROUP: | ||
1418 | perf_swcounter_handle_group(counter); | ||
1419 | break; | ||
1420 | } | ||
1421 | |||
1422 | if (nmi) { | ||
1423 | counter->wakeup_pending = 1; | ||
1424 | set_tsk_thread_flag(current, TIF_PERF_COUNTERS); | ||
1425 | } else | ||
1426 | wake_up(&counter->waitq); | ||
1427 | } | ||
1428 | |||
1429 | static int perf_swcounter_match(struct perf_counter *counter, | ||
1430 | enum hw_event_types event, | ||
1431 | struct pt_regs *regs) | ||
1432 | { | ||
1433 | if (counter->state != PERF_COUNTER_STATE_ACTIVE) | ||
1434 | return 0; | ||
1435 | |||
1436 | if (counter->hw_event.raw) | ||
1437 | return 0; | ||
1438 | |||
1439 | if (counter->hw_event.type != event) | ||
1440 | return 0; | ||
1441 | |||
1442 | if (counter->hw_event.exclude_user && user_mode(regs)) | ||
1443 | return 0; | ||
1444 | |||
1445 | if (counter->hw_event.exclude_kernel && !user_mode(regs)) | ||
1446 | return 0; | ||
1447 | |||
1448 | return 1; | ||
1449 | } | ||
1450 | |||
1451 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, | ||
1452 | enum hw_event_types event, u64 nr, | ||
1453 | int nmi, struct pt_regs *regs) | ||
1454 | { | ||
1455 | struct perf_counter *counter; | ||
1456 | unsigned long flags; | ||
1457 | int neg; | ||
1458 | |||
1459 | if (list_empty(&ctx->counter_list)) | ||
1460 | return; | ||
1461 | |||
1462 | spin_lock_irqsave(&ctx->lock, flags); | ||
1463 | |||
1464 | /* | ||
1465 | * XXX: make counter_list RCU safe | ||
1466 | */ | ||
1467 | list_for_each_entry(counter, &ctx->counter_list, list_entry) { | ||
1468 | if (perf_swcounter_match(counter, event, regs)) { | ||
1469 | neg = atomic64_add_negative(nr, &counter->hw.count); | ||
1470 | if (counter->hw.irq_period && !neg) | ||
1471 | perf_swcounter_interrupt(counter, nmi, regs); | ||
1472 | } | ||
1473 | } | ||
1474 | |||
1475 | spin_unlock_irqrestore(&ctx->lock, flags); | ||
1476 | } | ||
1477 | |||
1478 | void perf_swcounter_event(enum hw_event_types event, u64 nr, | ||
1479 | int nmi, struct pt_regs *regs) | ||
1480 | { | ||
1481 | struct perf_cpu_context *cpuctx = &get_cpu_var(perf_cpu_context); | ||
1482 | |||
1483 | perf_swcounter_ctx_event(&cpuctx->ctx, event, nr, nmi, regs); | ||
1484 | if (cpuctx->task_ctx) | ||
1485 | perf_swcounter_ctx_event(cpuctx->task_ctx, event, nr, nmi, regs); | ||
1486 | |||
1487 | put_cpu_var(perf_cpu_context); | ||
1488 | } | ||
1489 | |||
1490 | static void perf_swcounter_read(struct perf_counter *counter) | ||
1491 | { | ||
1492 | perf_swcounter_update(counter); | ||
1493 | } | ||
1494 | |||
1495 | static int perf_swcounter_enable(struct perf_counter *counter) | ||
1496 | { | ||
1497 | perf_swcounter_set_period(counter); | ||
1498 | return 0; | ||
1499 | } | ||
1500 | |||
1501 | static void perf_swcounter_disable(struct perf_counter *counter) | ||
1502 | { | ||
1503 | perf_swcounter_update(counter); | ||
1504 | } | ||
1505 | |||
1506 | /* | ||
1507 | * Software counter: cpu wall time clock | ||
1508 | */ | ||
1509 | |||
1331 | static int cpu_clock_perf_counter_enable(struct perf_counter *counter) | 1510 | static int cpu_clock_perf_counter_enable(struct perf_counter *counter) |
1332 | { | 1511 | { |
1333 | int cpu = raw_smp_processor_id(); | 1512 | int cpu = raw_smp_processor_id(); |
@@ -1365,6 +1544,10 @@ static const struct hw_perf_counter_ops perf_ops_cpu_clock = { | |||
1365 | }; | 1544 | }; |
1366 | 1545 | ||
1367 | /* | 1546 | /* |
1547 | * Software counter: task time clock | ||
1548 | */ | ||
1549 | |||
1550 | /* | ||
1368 | * Called from within the scheduler: | 1551 | * Called from within the scheduler: |
1369 | */ | 1552 | */ |
1370 | static u64 task_clock_perf_counter_val(struct perf_counter *counter, int update) | 1553 | static u64 task_clock_perf_counter_val(struct perf_counter *counter, int update) |
@@ -1420,6 +1603,10 @@ static const struct hw_perf_counter_ops perf_ops_task_clock = { | |||
1420 | .read = task_clock_perf_counter_read, | 1603 | .read = task_clock_perf_counter_read, |
1421 | }; | 1604 | }; |
1422 | 1605 | ||
1606 | /* | ||
1607 | * Software counter: page faults | ||
1608 | */ | ||
1609 | |||
1423 | #ifdef CONFIG_VM_EVENT_COUNTERS | 1610 | #ifdef CONFIG_VM_EVENT_COUNTERS |
1424 | #define cpu_page_faults() __get_cpu_var(vm_event_states).event[PGFAULT] | 1611 | #define cpu_page_faults() __get_cpu_var(vm_event_states).event[PGFAULT] |
1425 | #else | 1612 | #else |
@@ -1473,6 +1660,10 @@ static const struct hw_perf_counter_ops perf_ops_page_faults = { | |||
1473 | .read = page_faults_perf_counter_read, | 1660 | .read = page_faults_perf_counter_read, |
1474 | }; | 1661 | }; |
1475 | 1662 | ||
1663 | /* | ||
1664 | * Software counter: context switches | ||
1665 | */ | ||
1666 | |||
1476 | static u64 get_context_switches(struct perf_counter *counter) | 1667 | static u64 get_context_switches(struct perf_counter *counter) |
1477 | { | 1668 | { |
1478 | struct task_struct *curr = counter->ctx->task; | 1669 | struct task_struct *curr = counter->ctx->task; |
@@ -1521,6 +1712,10 @@ static const struct hw_perf_counter_ops perf_ops_context_switches = { | |||
1521 | .read = context_switches_perf_counter_read, | 1712 | .read = context_switches_perf_counter_read, |
1522 | }; | 1713 | }; |
1523 | 1714 | ||
1715 | /* | ||
1716 | * Software counter: cpu migrations | ||
1717 | */ | ||
1718 | |||
1524 | static inline u64 get_cpu_migrations(struct perf_counter *counter) | 1719 | static inline u64 get_cpu_migrations(struct perf_counter *counter) |
1525 | { | 1720 | { |
1526 | struct task_struct *curr = counter->ctx->task; | 1721 | struct task_struct *curr = counter->ctx->task; |
@@ -1572,7 +1767,9 @@ static const struct hw_perf_counter_ops perf_ops_cpu_migrations = { | |||
1572 | static const struct hw_perf_counter_ops * | 1767 | static const struct hw_perf_counter_ops * |
1573 | sw_perf_counter_init(struct perf_counter *counter) | 1768 | sw_perf_counter_init(struct perf_counter *counter) |
1574 | { | 1769 | { |
1770 | struct perf_counter_hw_event *hw_event = &counter->hw_event; | ||
1575 | const struct hw_perf_counter_ops *hw_ops = NULL; | 1771 | const struct hw_perf_counter_ops *hw_ops = NULL; |
1772 | struct hw_perf_counter *hwc = &counter->hw; | ||
1576 | 1773 | ||
1577 | /* | 1774 | /* |
1578 | * Software counters (currently) can't in general distinguish | 1775 | * Software counters (currently) can't in general distinguish |
@@ -1618,6 +1815,10 @@ sw_perf_counter_init(struct perf_counter *counter) | |||
1618 | default: | 1815 | default: |
1619 | break; | 1816 | break; |
1620 | } | 1817 | } |
1818 | |||
1819 | if (hw_ops) | ||
1820 | hwc->irq_period = hw_event->irq_period; | ||
1821 | |||
1621 | return hw_ops; | 1822 | return hw_ops; |
1622 | } | 1823 | } |
1623 | 1824 | ||