diff options
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r-- | kernel/perf_counter.c | 123 |
1 files changed, 86 insertions, 37 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c index 68950a3a52bf..f9330d5827cf 100644 --- a/kernel/perf_counter.c +++ b/kernel/perf_counter.c | |||
@@ -1395,7 +1395,7 @@ static void perf_swcounter_handle_group(struct perf_counter *sibling) | |||
1395 | struct perf_counter *counter, *group_leader = sibling->group_leader; | 1395 | struct perf_counter *counter, *group_leader = sibling->group_leader; |
1396 | 1396 | ||
1397 | list_for_each_entry(counter, &group_leader->sibling_list, list_entry) { | 1397 | list_for_each_entry(counter, &group_leader->sibling_list, list_entry) { |
1398 | perf_swcounter_update(counter); | 1398 | counter->hw_ops->read(counter); |
1399 | perf_swcounter_store_irq(sibling, counter->hw_event.type); | 1399 | perf_swcounter_store_irq(sibling, counter->hw_event.type); |
1400 | perf_swcounter_store_irq(sibling, atomic64_read(&counter->count)); | 1400 | perf_swcounter_store_irq(sibling, atomic64_read(&counter->count)); |
1401 | } | 1401 | } |
@@ -1404,8 +1404,6 @@ static void perf_swcounter_handle_group(struct perf_counter *sibling) | |||
1404 | static void perf_swcounter_interrupt(struct perf_counter *counter, | 1404 | static void perf_swcounter_interrupt(struct perf_counter *counter, |
1405 | int nmi, struct pt_regs *regs) | 1405 | int nmi, struct pt_regs *regs) |
1406 | { | 1406 | { |
1407 | perf_swcounter_save_and_restart(counter); | ||
1408 | |||
1409 | switch (counter->hw_event.record_type) { | 1407 | switch (counter->hw_event.record_type) { |
1410 | case PERF_RECORD_SIMPLE: | 1408 | case PERF_RECORD_SIMPLE: |
1411 | break; | 1409 | break; |
@@ -1426,6 +1424,38 @@ static void perf_swcounter_interrupt(struct perf_counter *counter, | |||
1426 | wake_up(&counter->waitq); | 1424 | wake_up(&counter->waitq); |
1427 | } | 1425 | } |
1428 | 1426 | ||
1427 | static enum hrtimer_restart perf_swcounter_hrtimer(struct hrtimer *hrtimer) | ||
1428 | { | ||
1429 | struct perf_counter *counter; | ||
1430 | struct pt_regs *regs; | ||
1431 | |||
1432 | counter = container_of(hrtimer, struct perf_counter, hw.hrtimer); | ||
1433 | counter->hw_ops->read(counter); | ||
1434 | |||
1435 | regs = get_irq_regs(); | ||
1436 | /* | ||
1437 | * In case we exclude kernel IPs or are somehow not in interrupt | ||
1438 | * context, provide the next best thing, the user IP. | ||
1439 | */ | ||
1440 | if ((counter->hw_event.exclude_kernel || !regs) && | ||
1441 | !counter->hw_event.exclude_user) | ||
1442 | regs = task_pt_regs(current); | ||
1443 | |||
1444 | if (regs) | ||
1445 | perf_swcounter_interrupt(counter, 0, regs); | ||
1446 | |||
1447 | hrtimer_forward_now(hrtimer, ns_to_ktime(counter->hw.irq_period)); | ||
1448 | |||
1449 | return HRTIMER_RESTART; | ||
1450 | } | ||
1451 | |||
1452 | static void perf_swcounter_overflow(struct perf_counter *counter, | ||
1453 | int nmi, struct pt_regs *regs) | ||
1454 | { | ||
1455 | perf_swcounter_save_and_restart(counter); | ||
1456 | perf_swcounter_interrupt(counter, nmi, regs); | ||
1457 | } | ||
1458 | |||
1429 | static int perf_swcounter_match(struct perf_counter *counter, | 1459 | static int perf_swcounter_match(struct perf_counter *counter, |
1430 | enum hw_event_types event, | 1460 | enum hw_event_types event, |
1431 | struct pt_regs *regs) | 1461 | struct pt_regs *regs) |
@@ -1448,13 +1478,20 @@ static int perf_swcounter_match(struct perf_counter *counter, | |||
1448 | return 1; | 1478 | return 1; |
1449 | } | 1479 | } |
1450 | 1480 | ||
1481 | static void perf_swcounter_add(struct perf_counter *counter, u64 nr, | ||
1482 | int nmi, struct pt_regs *regs) | ||
1483 | { | ||
1484 | int neg = atomic64_add_negative(nr, &counter->hw.count); | ||
1485 | if (counter->hw.irq_period && !neg) | ||
1486 | perf_swcounter_overflow(counter, nmi, regs); | ||
1487 | } | ||
1488 | |||
1451 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, | 1489 | static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, |
1452 | enum hw_event_types event, u64 nr, | 1490 | enum hw_event_types event, u64 nr, |
1453 | int nmi, struct pt_regs *regs) | 1491 | int nmi, struct pt_regs *regs) |
1454 | { | 1492 | { |
1455 | struct perf_counter *counter; | 1493 | struct perf_counter *counter; |
1456 | unsigned long flags; | 1494 | unsigned long flags; |
1457 | int neg; | ||
1458 | 1495 | ||
1459 | if (list_empty(&ctx->counter_list)) | 1496 | if (list_empty(&ctx->counter_list)) |
1460 | return; | 1497 | return; |
@@ -1465,11 +1502,8 @@ static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, | |||
1465 | * XXX: make counter_list RCU safe | 1502 | * XXX: make counter_list RCU safe |
1466 | */ | 1503 | */ |
1467 | list_for_each_entry(counter, &ctx->counter_list, list_entry) { | 1504 | list_for_each_entry(counter, &ctx->counter_list, list_entry) { |
1468 | if (perf_swcounter_match(counter, event, regs)) { | 1505 | if (perf_swcounter_match(counter, event, regs)) |
1469 | neg = atomic64_add_negative(nr, &counter->hw.count); | 1506 | perf_swcounter_add(counter, nr, nmi, regs); |
1470 | if (counter->hw.irq_period && !neg) | ||
1471 | perf_swcounter_interrupt(counter, nmi, regs); | ||
1472 | } | ||
1473 | } | 1507 | } |
1474 | 1508 | ||
1475 | spin_unlock_irqrestore(&ctx->lock, flags); | 1509 | spin_unlock_irqrestore(&ctx->lock, flags); |
@@ -1513,14 +1547,6 @@ static const struct hw_perf_counter_ops perf_ops_generic = { | |||
1513 | * Software counter: cpu wall time clock | 1547 | * Software counter: cpu wall time clock |
1514 | */ | 1548 | */ |
1515 | 1549 | ||
1516 | static int cpu_clock_perf_counter_enable(struct perf_counter *counter) | ||
1517 | { | ||
1518 | int cpu = raw_smp_processor_id(); | ||
1519 | |||
1520 | atomic64_set(&counter->hw.prev_count, cpu_clock(cpu)); | ||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | static void cpu_clock_perf_counter_update(struct perf_counter *counter) | 1550 | static void cpu_clock_perf_counter_update(struct perf_counter *counter) |
1525 | { | 1551 | { |
1526 | int cpu = raw_smp_processor_id(); | 1552 | int cpu = raw_smp_processor_id(); |
@@ -1533,8 +1559,26 @@ static void cpu_clock_perf_counter_update(struct perf_counter *counter) | |||
1533 | atomic64_add(now - prev, &counter->count); | 1559 | atomic64_add(now - prev, &counter->count); |
1534 | } | 1560 | } |
1535 | 1561 | ||
1562 | static int cpu_clock_perf_counter_enable(struct perf_counter *counter) | ||
1563 | { | ||
1564 | struct hw_perf_counter *hwc = &counter->hw; | ||
1565 | int cpu = raw_smp_processor_id(); | ||
1566 | |||
1567 | atomic64_set(&hwc->prev_count, cpu_clock(cpu)); | ||
1568 | if (hwc->irq_period) { | ||
1569 | hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
1570 | hwc->hrtimer.function = perf_swcounter_hrtimer; | ||
1571 | __hrtimer_start_range_ns(&hwc->hrtimer, | ||
1572 | ns_to_ktime(hwc->irq_period), 0, | ||
1573 | HRTIMER_MODE_REL, 0); | ||
1574 | } | ||
1575 | |||
1576 | return 0; | ||
1577 | } | ||
1578 | |||
1536 | static void cpu_clock_perf_counter_disable(struct perf_counter *counter) | 1579 | static void cpu_clock_perf_counter_disable(struct perf_counter *counter) |
1537 | { | 1580 | { |
1581 | hrtimer_cancel(&counter->hw.hrtimer); | ||
1538 | cpu_clock_perf_counter_update(counter); | 1582 | cpu_clock_perf_counter_update(counter); |
1539 | } | 1583 | } |
1540 | 1584 | ||
@@ -1580,27 +1624,33 @@ static void task_clock_perf_counter_update(struct perf_counter *counter, u64 now | |||
1580 | atomic64_add(delta, &counter->count); | 1624 | atomic64_add(delta, &counter->count); |
1581 | } | 1625 | } |
1582 | 1626 | ||
1583 | static void task_clock_perf_counter_read(struct perf_counter *counter) | ||
1584 | { | ||
1585 | u64 now = task_clock_perf_counter_val(counter, 1); | ||
1586 | |||
1587 | task_clock_perf_counter_update(counter, now); | ||
1588 | } | ||
1589 | |||
1590 | static int task_clock_perf_counter_enable(struct perf_counter *counter) | 1627 | static int task_clock_perf_counter_enable(struct perf_counter *counter) |
1591 | { | 1628 | { |
1592 | if (counter->prev_state <= PERF_COUNTER_STATE_OFF) | 1629 | struct hw_perf_counter *hwc = &counter->hw; |
1593 | atomic64_set(&counter->hw.prev_count, | 1630 | |
1594 | task_clock_perf_counter_val(counter, 0)); | 1631 | atomic64_set(&hwc->prev_count, task_clock_perf_counter_val(counter, 0)); |
1632 | if (hwc->irq_period) { | ||
1633 | hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
1634 | hwc->hrtimer.function = perf_swcounter_hrtimer; | ||
1635 | __hrtimer_start_range_ns(&hwc->hrtimer, | ||
1636 | ns_to_ktime(hwc->irq_period), 0, | ||
1637 | HRTIMER_MODE_REL, 0); | ||
1638 | } | ||
1595 | 1639 | ||
1596 | return 0; | 1640 | return 0; |
1597 | } | 1641 | } |
1598 | 1642 | ||
1599 | static void task_clock_perf_counter_disable(struct perf_counter *counter) | 1643 | static void task_clock_perf_counter_disable(struct perf_counter *counter) |
1600 | { | 1644 | { |
1601 | u64 now = task_clock_perf_counter_val(counter, 0); | 1645 | hrtimer_cancel(&counter->hw.hrtimer); |
1646 | task_clock_perf_counter_update(counter, | ||
1647 | task_clock_perf_counter_val(counter, 0)); | ||
1648 | } | ||
1602 | 1649 | ||
1603 | task_clock_perf_counter_update(counter, now); | 1650 | static void task_clock_perf_counter_read(struct perf_counter *counter) |
1651 | { | ||
1652 | task_clock_perf_counter_update(counter, | ||
1653 | task_clock_perf_counter_val(counter, 1)); | ||
1604 | } | 1654 | } |
1605 | 1655 | ||
1606 | static const struct hw_perf_counter_ops perf_ops_task_clock = { | 1656 | static const struct hw_perf_counter_ops perf_ops_task_clock = { |
@@ -1729,16 +1779,12 @@ sw_perf_counter_init(struct perf_counter *counter) | |||
1729 | */ | 1779 | */ |
1730 | switch (counter->hw_event.type) { | 1780 | switch (counter->hw_event.type) { |
1731 | case PERF_COUNT_CPU_CLOCK: | 1781 | case PERF_COUNT_CPU_CLOCK: |
1732 | if (!(counter->hw_event.exclude_user || | 1782 | hw_ops = &perf_ops_cpu_clock; |
1733 | counter->hw_event.exclude_kernel || | 1783 | |
1734 | counter->hw_event.exclude_hv)) | 1784 | if (hw_event->irq_period && hw_event->irq_period < 10000) |
1735 | hw_ops = &perf_ops_cpu_clock; | 1785 | hw_event->irq_period = 10000; |
1736 | break; | 1786 | break; |
1737 | case PERF_COUNT_TASK_CLOCK: | 1787 | case PERF_COUNT_TASK_CLOCK: |
1738 | if (counter->hw_event.exclude_user || | ||
1739 | counter->hw_event.exclude_kernel || | ||
1740 | counter->hw_event.exclude_hv) | ||
1741 | break; | ||
1742 | /* | 1788 | /* |
1743 | * If the user instantiates this as a per-cpu counter, | 1789 | * If the user instantiates this as a per-cpu counter, |
1744 | * use the cpu_clock counter instead. | 1790 | * use the cpu_clock counter instead. |
@@ -1747,6 +1793,9 @@ sw_perf_counter_init(struct perf_counter *counter) | |||
1747 | hw_ops = &perf_ops_task_clock; | 1793 | hw_ops = &perf_ops_task_clock; |
1748 | else | 1794 | else |
1749 | hw_ops = &perf_ops_cpu_clock; | 1795 | hw_ops = &perf_ops_cpu_clock; |
1796 | |||
1797 | if (hw_event->irq_period && hw_event->irq_period < 10000) | ||
1798 | hw_event->irq_period = 10000; | ||
1750 | break; | 1799 | break; |
1751 | case PERF_COUNT_PAGE_FAULTS: | 1800 | case PERF_COUNT_PAGE_FAULTS: |
1752 | case PERF_COUNT_PAGE_FAULTS_MIN: | 1801 | case PERF_COUNT_PAGE_FAULTS_MIN: |