struct cpu_hw_events { int n_events; int disabled;
u8 pmcs_enabled; struct perf_event *event[MAX_HWEVENTS];
}; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
staticstruct fsl_emb_pmu *ppmu;
/* Number of perf_events counting hardware events */ static atomic_t num_events; /* Used to avoid races in calling reserve/release_pmc_hardware */ static DEFINE_MUTEX(pmc_reserve_mutex);
staticint collect_events(struct perf_event *group, int max_count, struct perf_event *ctrs[])
{ int n = 0; struct perf_event *event;
if (!is_software_event(group)) { if (n >= max_count) return -1;
ctrs[n] = group;
n++;
}
for_each_sibling_event(event, group) { if (!is_software_event(event) &&
event->state != PERF_EVENT_STATE_OFF) { if (n >= max_count) return -1;
ctrs[n] = event;
n++;
}
} return n;
}
/* context locked on entry */ staticint fsl_emb_pmu_add(struct perf_event *event, int flags)
{ struct cpu_hw_events *cpuhw; int ret = -EAGAIN; int num_counters = ppmu->n_counter;
u64 val; int i;
if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
num_counters = ppmu->n_restricted;
/* *Allocatecountersfromtop-down,sothatrestricted-capable *countersarekeptfreeaslongaspossible.
*/ for (i = num_counters - 1; i >= 0; i--) { if (cpuhw->event[i]) continue;
val = 0; if (event->hw.sample_period) {
s64 left = local64_read(&event->hw.period_left); if (left < 0x80000000L)
val = 0x80000000L - left;
}
local64_set(&event->hw.prev_count, val);
event->hw.state = 0;
left = local64_read(&event->hw.period_left);
val = 0; if (left < 0x80000000L)
val = 0x80000000L - left;
write_pmc(event->hw.idx, val);
/* unpack config */
type = config & 0xff;
op = (config >> 8) & 0xff;
result = (config >> 16) & 0xff;
if (type >= PERF_COUNT_HW_CACHE_MAX ||
op >= PERF_COUNT_HW_CACHE_OP_MAX ||
result >= PERF_COUNT_HW_CACHE_RESULT_MAX) return -EINVAL;
ev = (*ppmu->cache_events)[type][op][result]; if (ev == 0) return -EOPNOTSUPP; if (ev == -1) return -EINVAL;
*eventp = ev; return0;
}
staticint fsl_emb_pmu_event_init(struct perf_event *event)
{
u64 ev; struct perf_event *events[MAX_HWEVENTS]; int n; int err; int num_restricted; int i;
if (ppmu->n_counter > MAX_HWEVENTS) {
WARN(1, "No. of perf counters (%d) is higher than max array size(%d)\n",
ppmu->n_counter, MAX_HWEVENTS);
ppmu->n_counter = MAX_HWEVENTS;
}
switch (event->attr.type) { case PERF_TYPE_HARDWARE:
ev = event->attr.config; if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0) return -EOPNOTSUPP;
ev = ppmu->generic_events[ev]; break;
case PERF_TYPE_HW_CACHE:
err = hw_perf_cache_event(event->attr.config, &ev); if (err) return err; break;
case PERF_TYPE_RAW:
ev = event->attr.config; break;
default: return -ENOENT;
}
event->hw.config = ppmu->xlate_event(ev); if (!(event->hw.config & FSL_EMB_EVENT_VALID)) return -EINVAL;
/* *Ifthisisinagroup,checkifitcangoonwithallthe *otherhardwareeventsinthegroup.Weassumetheevent *hasn'tbeenlinkedintoitsleader'ssiblinglistatthispoint.
*/
n = 0; if (event->group_leader != event) {
n = collect_events(event->group_leader,
ppmu->n_counter - 1, events); if (n < 0) return -EINVAL;
}
if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
num_restricted = 0; for (i = 0; i < n; i++) { if (events[i]->hw.config & FSL_EMB_EVENT_RESTRICTED)
num_restricted++;
}
if (num_restricted >= ppmu->n_restricted) return -EINVAL;
}
if (event->attr.exclude_user)
event->hw.config_base |= PMLCA_FCU; if (event->attr.exclude_kernel)
event->hw.config_base |= PMLCA_FCS; if (event->attr.exclude_idle) return -ENOTSUPP;
if (event->hw.state & PERF_HES_STOPPED) {
write_pmc(event->hw.idx, 0); return;
}
/* we don't have to worry about interrupts here */
prev = local64_read(&event->hw.prev_count);
delta = (val - prev) & 0xfffffffful;
local64_add(delta, &event->count);
/* *Seeifthetotalperiodforthiseventhasexpired, *andupdateforthenextperiod.
*/
val = 0;
left = local64_read(&event->hw.period_left) - delta; if (period) { if (left <= 0) {
left += period; if (left <= 0)
left = period;
record = 1;
event->hw.last_period = event->hw.sample_period;
} if (left < 0x80000000LL)
val = 0x80000000LL - left;
}
for (i = 0; i < ppmu->n_counter; ++i) {
event = cpuhw->event[i];
val = read_pmc(i); if ((int)val < 0) { if (event) { /* event has overflowed */
record_and_restart(event, val, regs);
} else { /* *Disabledcounterisnegative, *resetitjustincase.
*/
write_pmc(i, 0);
}
}
}
/* PMM will keep counters frozen until we return from the interrupt. */
mtmsr(mfmsr() | MSR_PMM);
mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
isync();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.