aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r--kernel/perf_counter.c123
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)
1404static void perf_swcounter_interrupt(struct perf_counter *counter, 1404static 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
1427static 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
1452static 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
1429static int perf_swcounter_match(struct perf_counter *counter, 1459static 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
1481static 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
1451static void perf_swcounter_ctx_event(struct perf_counter_context *ctx, 1489static 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
1516static 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
1524static void cpu_clock_perf_counter_update(struct perf_counter *counter) 1550static 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
1562static 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
1536static void cpu_clock_perf_counter_disable(struct perf_counter *counter) 1579static 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
1583static 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
1590static int task_clock_perf_counter_enable(struct perf_counter *counter) 1627static 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
1599static void task_clock_perf_counter_disable(struct perf_counter *counter) 1643static 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); 1650static 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
1606static const struct hw_perf_counter_ops perf_ops_task_clock = { 1656static 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: