aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/perf
diff options
context:
space:
mode:
authorAnshuman Khandual <khandual@linux.vnet.ibm.com>2013-04-22 15:42:44 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-04-26 02:13:02 -0400
commit3925f46bb5902ba9f227591584e27acb6a32c9b0 (patch)
tree8bffe0b3b134660b8afcd3e535328884187f52fc /arch/powerpc/perf
parentb1113557fb5f4d47d888572a7ffeac91fc692743 (diff)
powerpc/perf: Enable branch stack sampling framework
Provides basic enablement for perf branch stack sampling framework on POWER8 processor based platforms. Adds new BHRB related elements into cpu_hw_event structure to represent current BHRB config, BHRB filter configuration, manage context and to hold output BHRB buffer during PMU interrupt before passing to the user space. This also enables processing of BHRB data and converts them into generic perf branch stack data format. Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/perf')
-rw-r--r--arch/powerpc/perf/core-book3s.c167
1 files changed, 164 insertions, 3 deletions
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 4ac6e64a52ce..c627843c5b2e 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -19,6 +19,11 @@
19#include <asm/firmware.h> 19#include <asm/firmware.h>
20#include <asm/ptrace.h> 20#include <asm/ptrace.h>
21 21
22#define BHRB_MAX_ENTRIES 32
23#define BHRB_TARGET 0x0000000000000002
24#define BHRB_PREDICTION 0x0000000000000001
25#define BHRB_EA 0xFFFFFFFFFFFFFFFC
26
22struct cpu_hw_events { 27struct cpu_hw_events {
23 int n_events; 28 int n_events;
24 int n_percpu; 29 int n_percpu;
@@ -38,7 +43,15 @@ struct cpu_hw_events {
38 43
39 unsigned int group_flag; 44 unsigned int group_flag;
40 int n_txn_start; 45 int n_txn_start;
46
47 /* BHRB bits */
48 u64 bhrb_filter; /* BHRB HW branch filter */
49 int bhrb_users;
50 void *bhrb_context;
51 struct perf_branch_stack bhrb_stack;
52 struct perf_branch_entry bhrb_entries[BHRB_MAX_ENTRIES];
41}; 53};
54
42DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); 55DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
43 56
44struct power_pmu *ppmu; 57struct power_pmu *ppmu;
@@ -858,6 +871,9 @@ static void power_pmu_enable(struct pmu *pmu)
858 } 871 }
859 872
860 out: 873 out:
874 if (cpuhw->bhrb_users)
875 ppmu->config_bhrb(cpuhw->bhrb_filter);
876
861 local_irq_restore(flags); 877 local_irq_restore(flags);
862} 878}
863 879
@@ -888,6 +904,47 @@ static int collect_events(struct perf_event *group, int max_count,
888 return n; 904 return n;
889} 905}
890 906
907/* Reset all possible BHRB entries */
908static void power_pmu_bhrb_reset(void)
909{
910 asm volatile(PPC_CLRBHRB);
911}
912
913void power_pmu_bhrb_enable(struct perf_event *event)
914{
915 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
916
917 if (!ppmu->bhrb_nr)
918 return;
919
920 /* Clear BHRB if we changed task context to avoid data leaks */
921 if (event->ctx->task && cpuhw->bhrb_context != event->ctx) {
922 power_pmu_bhrb_reset();
923 cpuhw->bhrb_context = event->ctx;
924 }
925 cpuhw->bhrb_users++;
926}
927
928void power_pmu_bhrb_disable(struct perf_event *event)
929{
930 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
931
932 if (!ppmu->bhrb_nr)
933 return;
934
935 cpuhw->bhrb_users--;
936 WARN_ON_ONCE(cpuhw->bhrb_users < 0);
937
938 if (!cpuhw->disabled && !cpuhw->bhrb_users) {
939 /* BHRB cannot be turned off when other
940 * events are active on the PMU.
941 */
942
943 /* avoid stale pointer */
944 cpuhw->bhrb_context = NULL;
945 }
946}
947
891/* 948/*
892 * Add a event to the PMU. 949 * Add a event to the PMU.
893 * If all events are not already frozen, then we disable and 950 * If all events are not already frozen, then we disable and
@@ -947,6 +1004,9 @@ nocheck:
947 1004
948 ret = 0; 1005 ret = 0;
949 out: 1006 out:
1007 if (has_branch_stack(event))
1008 power_pmu_bhrb_enable(event);
1009
950 perf_pmu_enable(event->pmu); 1010 perf_pmu_enable(event->pmu);
951 local_irq_restore(flags); 1011 local_irq_restore(flags);
952 return ret; 1012 return ret;
@@ -999,6 +1059,9 @@ static void power_pmu_del(struct perf_event *event, int ef_flags)
999 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE); 1059 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
1000 } 1060 }
1001 1061
1062 if (has_branch_stack(event))
1063 power_pmu_bhrb_disable(event);
1064
1002 perf_pmu_enable(event->pmu); 1065 perf_pmu_enable(event->pmu);
1003 local_irq_restore(flags); 1066 local_irq_restore(flags);
1004} 1067}
@@ -1117,6 +1180,15 @@ int power_pmu_commit_txn(struct pmu *pmu)
1117 return 0; 1180 return 0;
1118} 1181}
1119 1182
1183/* Called from ctxsw to prevent one process's branch entries to
1184 * mingle with the other process's entries during context switch.
1185 */
1186void power_pmu_flush_branch_stack(void)
1187{
1188 if (ppmu->bhrb_nr)
1189 power_pmu_bhrb_reset();
1190}
1191
1120/* 1192/*
1121 * Return 1 if we might be able to put event on a limited PMC, 1193 * Return 1 if we might be able to put event on a limited PMC,
1122 * or 0 if not. 1194 * or 0 if not.
@@ -1231,9 +1303,11 @@ static int power_pmu_event_init(struct perf_event *event)
1231 if (!ppmu) 1303 if (!ppmu)
1232 return -ENOENT; 1304 return -ENOENT;
1233 1305
1234 /* does not support taken branch sampling */ 1306 if (has_branch_stack(event)) {
1235 if (has_branch_stack(event)) 1307 /* PMU has BHRB enabled */
1236 return -EOPNOTSUPP; 1308 if (!(ppmu->flags & PPMU_BHRB))
1309 return -EOPNOTSUPP;
1310 }
1237 1311
1238 switch (event->attr.type) { 1312 switch (event->attr.type) {
1239 case PERF_TYPE_HARDWARE: 1313 case PERF_TYPE_HARDWARE:
@@ -1314,6 +1388,15 @@ static int power_pmu_event_init(struct perf_event *event)
1314 1388
1315 cpuhw = &get_cpu_var(cpu_hw_events); 1389 cpuhw = &get_cpu_var(cpu_hw_events);
1316 err = power_check_constraints(cpuhw, events, cflags, n + 1); 1390 err = power_check_constraints(cpuhw, events, cflags, n + 1);
1391
1392 if (has_branch_stack(event)) {
1393 cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
1394 event->attr.branch_sample_type);
1395
1396 if(cpuhw->bhrb_filter == -1)
1397 return -EOPNOTSUPP;
1398 }
1399
1317 put_cpu_var(cpu_hw_events); 1400 put_cpu_var(cpu_hw_events);
1318 if (err) 1401 if (err)
1319 return -EINVAL; 1402 return -EINVAL;
@@ -1372,8 +1455,79 @@ struct pmu power_pmu = {
1372 .cancel_txn = power_pmu_cancel_txn, 1455 .cancel_txn = power_pmu_cancel_txn,
1373 .commit_txn = power_pmu_commit_txn, 1456 .commit_txn = power_pmu_commit_txn,
1374 .event_idx = power_pmu_event_idx, 1457 .event_idx = power_pmu_event_idx,
1458 .flush_branch_stack = power_pmu_flush_branch_stack,
1375}; 1459};
1376 1460
1461/* Processing BHRB entries */
1462void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
1463{
1464 u64 val;
1465 u64 addr;
1466 int r_index, u_index, target, pred;
1467
1468 r_index = 0;
1469 u_index = 0;
1470 while (r_index < ppmu->bhrb_nr) {
1471 /* Assembly read function */
1472 val = read_bhrb(r_index);
1473
1474 /* Terminal marker: End of valid BHRB entries */
1475 if (val == 0) {
1476 break;
1477 } else {
1478 /* BHRB field break up */
1479 addr = val & BHRB_EA;
1480 pred = val & BHRB_PREDICTION;
1481 target = val & BHRB_TARGET;
1482
1483 /* Probable Missed entry: Not applicable for POWER8 */
1484 if ((addr == 0) && (target == 0) && (pred == 1)) {
1485 r_index++;
1486 continue;
1487 }
1488
1489 /* Real Missed entry: Power8 based missed entry */
1490 if ((addr == 0) && (target == 1) && (pred == 1)) {
1491 r_index++;
1492 continue;
1493 }
1494
1495 /* Reserved condition: Not a valid entry */
1496 if ((addr == 0) && (target == 1) && (pred == 0)) {
1497 r_index++;
1498 continue;
1499 }
1500
1501 /* Is a target address */
1502 if (val & BHRB_TARGET) {
1503 /* First address cannot be a target address */
1504 if (r_index == 0) {
1505 r_index++;
1506 continue;
1507 }
1508
1509 /* Update target address for the previous entry */
1510 cpuhw->bhrb_entries[u_index - 1].to = addr;
1511 cpuhw->bhrb_entries[u_index - 1].mispred = pred;
1512 cpuhw->bhrb_entries[u_index - 1].predicted = ~pred;
1513
1514 /* Dont increment u_index */
1515 r_index++;
1516 } else {
1517 /* Update address, flags for current entry */
1518 cpuhw->bhrb_entries[u_index].from = addr;
1519 cpuhw->bhrb_entries[u_index].mispred = pred;
1520 cpuhw->bhrb_entries[u_index].predicted = ~pred;
1521
1522 /* Successfully popullated one entry */
1523 u_index++;
1524 r_index++;
1525 }
1526 }
1527 }
1528 cpuhw->bhrb_stack.nr = u_index;
1529 return;
1530}
1377 1531
1378/* 1532/*
1379 * A counter has overflowed; update its count and record 1533 * A counter has overflowed; update its count and record
@@ -1433,6 +1587,13 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
1433 if (event->attr.sample_type & PERF_SAMPLE_ADDR) 1587 if (event->attr.sample_type & PERF_SAMPLE_ADDR)
1434 perf_get_data_addr(regs, &data.addr); 1588 perf_get_data_addr(regs, &data.addr);
1435 1589
1590 if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) {
1591 struct cpu_hw_events *cpuhw;
1592 cpuhw = &__get_cpu_var(cpu_hw_events);
1593 power_pmu_bhrb_read(cpuhw);
1594 data.br_stack = &cpuhw->bhrb_stack;
1595 }
1596
1436 if (perf_event_overflow(event, &data, regs)) 1597 if (perf_event_overflow(event, &data, regs))
1437 power_pmu_stop(event, 0); 1598 power_pmu_stop(event, 0);
1438 } 1599 }