Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 370823
b: refs/heads/master
c: 3925f46
h: refs/heads/master
i:
  370821: 6f40bd4
  370819: f439c6e
  370815: c15b099
v: v3
  • Loading branch information
Anshuman Khandual authored and Benjamin Herrenschmidt committed Apr 26, 2013
1 parent 8802dfd commit f4de17b
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b1113557fb5f4d47d888572a7ffeac91fc692743
refs/heads/master: 3925f46bb5902ba9f227591584e27acb6a32c9b0
1 change: 1 addition & 0 deletions trunk/arch/powerpc/include/asm/perf_event_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ extern int register_power_pmu(struct power_pmu *);
struct pt_regs;
extern unsigned long perf_misc_flags(struct pt_regs *regs);
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long int read_bhrb(int n);

/*
* Only override the default definitions in include/linux/perf_event.h
Expand Down
167 changes: 164 additions & 3 deletions trunk/arch/powerpc/perf/core-book3s.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include <asm/firmware.h>
#include <asm/ptrace.h>

#define BHRB_MAX_ENTRIES 32
#define BHRB_TARGET 0x0000000000000002
#define BHRB_PREDICTION 0x0000000000000001
#define BHRB_EA 0xFFFFFFFFFFFFFFFC

struct cpu_hw_events {
int n_events;
int n_percpu;
Expand All @@ -38,7 +43,15 @@ struct cpu_hw_events {

unsigned int group_flag;
int n_txn_start;

/* BHRB bits */
u64 bhrb_filter; /* BHRB HW branch filter */
int bhrb_users;
void *bhrb_context;
struct perf_branch_stack bhrb_stack;
struct perf_branch_entry bhrb_entries[BHRB_MAX_ENTRIES];
};

DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);

struct power_pmu *ppmu;
Expand Down Expand Up @@ -858,6 +871,9 @@ static void power_pmu_enable(struct pmu *pmu)
}

out:
if (cpuhw->bhrb_users)
ppmu->config_bhrb(cpuhw->bhrb_filter);

local_irq_restore(flags);
}

Expand Down Expand Up @@ -888,6 +904,47 @@ static int collect_events(struct perf_event *group, int max_count,
return n;
}

/* Reset all possible BHRB entries */
static void power_pmu_bhrb_reset(void)
{
asm volatile(PPC_CLRBHRB);
}

void power_pmu_bhrb_enable(struct perf_event *event)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);

if (!ppmu->bhrb_nr)
return;

/* Clear BHRB if we changed task context to avoid data leaks */
if (event->ctx->task && cpuhw->bhrb_context != event->ctx) {
power_pmu_bhrb_reset();
cpuhw->bhrb_context = event->ctx;
}
cpuhw->bhrb_users++;
}

void power_pmu_bhrb_disable(struct perf_event *event)
{
struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);

if (!ppmu->bhrb_nr)
return;

cpuhw->bhrb_users--;
WARN_ON_ONCE(cpuhw->bhrb_users < 0);

if (!cpuhw->disabled && !cpuhw->bhrb_users) {
/* BHRB cannot be turned off when other
* events are active on the PMU.
*/

/* avoid stale pointer */
cpuhw->bhrb_context = NULL;
}
}

/*
* Add a event to the PMU.
* If all events are not already frozen, then we disable and
Expand Down Expand Up @@ -947,6 +1004,9 @@ static int power_pmu_add(struct perf_event *event, int ef_flags)

ret = 0;
out:
if (has_branch_stack(event))
power_pmu_bhrb_enable(event);

perf_pmu_enable(event->pmu);
local_irq_restore(flags);
return ret;
Expand Down Expand Up @@ -999,6 +1059,9 @@ static void power_pmu_del(struct perf_event *event, int ef_flags)
cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
}

if (has_branch_stack(event))
power_pmu_bhrb_disable(event);

perf_pmu_enable(event->pmu);
local_irq_restore(flags);
}
Expand Down Expand Up @@ -1117,6 +1180,15 @@ int power_pmu_commit_txn(struct pmu *pmu)
return 0;
}

/* Called from ctxsw to prevent one process's branch entries to
* mingle with the other process's entries during context switch.
*/
void power_pmu_flush_branch_stack(void)
{
if (ppmu->bhrb_nr)
power_pmu_bhrb_reset();
}

/*
* Return 1 if we might be able to put event on a limited PMC,
* or 0 if not.
Expand Down Expand Up @@ -1231,9 +1303,11 @@ static int power_pmu_event_init(struct perf_event *event)
if (!ppmu)
return -ENOENT;

/* does not support taken branch sampling */
if (has_branch_stack(event))
return -EOPNOTSUPP;
if (has_branch_stack(event)) {
/* PMU has BHRB enabled */
if (!(ppmu->flags & PPMU_BHRB))
return -EOPNOTSUPP;
}

switch (event->attr.type) {
case PERF_TYPE_HARDWARE:
Expand Down Expand Up @@ -1314,6 +1388,15 @@ static int power_pmu_event_init(struct perf_event *event)

cpuhw = &get_cpu_var(cpu_hw_events);
err = power_check_constraints(cpuhw, events, cflags, n + 1);

if (has_branch_stack(event)) {
cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
event->attr.branch_sample_type);

if(cpuhw->bhrb_filter == -1)
return -EOPNOTSUPP;
}

put_cpu_var(cpu_hw_events);
if (err)
return -EINVAL;
Expand Down Expand Up @@ -1372,8 +1455,79 @@ struct pmu power_pmu = {
.cancel_txn = power_pmu_cancel_txn,
.commit_txn = power_pmu_commit_txn,
.event_idx = power_pmu_event_idx,
.flush_branch_stack = power_pmu_flush_branch_stack,
};

/* Processing BHRB entries */
void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
{
u64 val;
u64 addr;
int r_index, u_index, target, pred;

r_index = 0;
u_index = 0;
while (r_index < ppmu->bhrb_nr) {
/* Assembly read function */
val = read_bhrb(r_index);

/* Terminal marker: End of valid BHRB entries */
if (val == 0) {
break;
} else {
/* BHRB field break up */
addr = val & BHRB_EA;
pred = val & BHRB_PREDICTION;
target = val & BHRB_TARGET;

/* Probable Missed entry: Not applicable for POWER8 */
if ((addr == 0) && (target == 0) && (pred == 1)) {
r_index++;
continue;
}

/* Real Missed entry: Power8 based missed entry */
if ((addr == 0) && (target == 1) && (pred == 1)) {
r_index++;
continue;
}

/* Reserved condition: Not a valid entry */
if ((addr == 0) && (target == 1) && (pred == 0)) {
r_index++;
continue;
}

/* Is a target address */
if (val & BHRB_TARGET) {
/* First address cannot be a target address */
if (r_index == 0) {
r_index++;
continue;
}

/* Update target address for the previous entry */
cpuhw->bhrb_entries[u_index - 1].to = addr;
cpuhw->bhrb_entries[u_index - 1].mispred = pred;
cpuhw->bhrb_entries[u_index - 1].predicted = ~pred;

/* Dont increment u_index */
r_index++;
} else {
/* Update address, flags for current entry */
cpuhw->bhrb_entries[u_index].from = addr;
cpuhw->bhrb_entries[u_index].mispred = pred;
cpuhw->bhrb_entries[u_index].predicted = ~pred;

/* Successfully popullated one entry */
u_index++;
r_index++;
}
}
}
cpuhw->bhrb_stack.nr = u_index;
return;
}

/*
* A counter has overflowed; update its count and record
Expand Down Expand Up @@ -1433,6 +1587,13 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
if (event->attr.sample_type & PERF_SAMPLE_ADDR)
perf_get_data_addr(regs, &data.addr);

if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) {
struct cpu_hw_events *cpuhw;
cpuhw = &__get_cpu_var(cpu_hw_events);
power_pmu_bhrb_read(cpuhw);
data.br_stack = &cpuhw->bhrb_stack;
}

if (perf_event_overflow(event, &data, regs))
power_pmu_stop(event, 0);
}
Expand Down

0 comments on commit f4de17b

Please sign in to comment.