/* * Scan the alternatives table for a match and return the * index into the alternatives table if found, else -1.
*/ staticint find_alternative(unsignedint event)
{ int i, j;
for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) { if (event < event_alternatives[i][0]) break; for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j) if (event == event_alternatives[i][j]) return i;
} return -1;
}
/* * Some direct events for decodes of event bus byte 3 have alternative * PMCSEL values on other counters. This returns the alternative * event code for those that do, or -1 otherwise. This also handles * alternative PCMSEL values for add events.
*/ static s64 find_alternative_bdecode(u64 event)
{ int pmc, altpmc, pp, j;
staticint power5p_get_alternatives(u64 event, unsignedint flags, u64 alt[])
{ int i, j, nalt = 1; int nlim;
s64 ae;
alt[0] = event;
nalt = 1;
nlim = power5p_limited_pmc_event(event);
i = find_alternative(event); if (i >= 0) { for (j = 0; j < MAX_ALT; ++j) {
ae = event_alternatives[i][j]; if (ae && ae != event)
alt[nalt++] = ae;
nlim += power5p_limited_pmc_event(ae);
}
} else {
ae = find_alternative_bdecode(event); if (ae > 0)
alt[nalt++] = ae;
}
if (flags & PPMU_ONLY_COUNT_RUN) { /* * We're only counting in RUN state, * so PM_CYC is equivalent to PM_RUN_CYC * and PM_INST_CMPL === PM_RUN_INST_CMPL. * This doesn't include alternatives that don't provide * any extra flexibility in assigning PMCs (e.g. * 0x100005 for PM_RUN_CYC vs. 0xf for PM_CYC). * Note that even with these additional alternatives * we never end up with more than 3 alternatives for any event.
*/
j = nalt; for (i = 0; i < nalt; ++i) { switch (alt[i]) { case 0xf: /* PM_CYC */
alt[j++] = 0x600005; /* PM_RUN_CYC */
++nlim; break; case 0x600005: /* PM_RUN_CYC */
alt[j++] = 0xf; break; case 0x100009: /* PM_INST_CMPL */
alt[j++] = 0x500009; /* PM_RUN_INST_CMPL */
++nlim; break; case 0x500009: /* PM_RUN_INST_CMPL */
alt[j++] = 0x100009; /* PM_INST_CMPL */
alt[j++] = 0x200009; break;
}
}
nalt = j;
}
if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) { /* remove the limited PMC events */
j = 0; for (i = 0; i < nalt; ++i) { if (!power5p_limited_pmc_event(alt[i])) {
alt[j] = alt[i];
++j;
}
}
nalt = j;
} elseif ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) { /* remove all but the limited PMC events */
j = 0; for (i = 0; i < nalt; ++i) { if (power5p_limited_pmc_event(alt[i])) {
alt[j] = alt[i];
++j;
}
}
nalt = j;
}
return nalt;
}
/* * Map of which direct events on which PMCs are marked instruction events. * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event. * Bit 0 is set if it is marked for all PMCs. * The 0x80 bit indicates a byte decode PMCSEL value.
*/ staticunsignedchar direct_event_is_marked[0x28] = {
0, /* 00 */
0x1f, /* 01 PM_IOPS_CMPL */
0x2, /* 02 PM_MRK_GRP_DISP */
0xe, /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
0, /* 04 */
0x1c, /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
0x80, /* 06 */
0x80, /* 07 */
0, 0, 0,/* 08 - 0a */
0x18, /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
0, /* 0c */
0x80, /* 0d */
0x80, /* 0e */
0, /* 0f */
0, /* 10 */
0x14, /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
0, /* 12 */
0x10, /* 13 PM_MRK_GRP_CMPL */
0x1f, /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
0x2, /* 15 PM_MRK_GRP_ISSUED */
0x80, /* 16 */
0x80, /* 17 */
0, 0, 0, 0, 0,
0x80, /* 1d */
0x80, /* 1e */
0, /* 1f */
0x80, /* 20 */
0x80, /* 21 */
0x80, /* 22 */
0x80, /* 23 */
0x80, /* 24 */
0x80, /* 25 */
0x80, /* 26 */
0x80, /* 27 */
};
/* * Returns 1 if event counts things relating to marked instructions * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
*/ staticint power5p_marked_instr_event(u64 event)
{ int pmc, psel; int bit, byte, unit;
u32 mask;
staticint power5p_compute_mmcr(u64 event[], int n_ev, unsignedint hwc[], struct mmcr_regs *mmcr, struct perf_event *pevents[],
u32 flags __maybe_unused)
{ unsignedlong mmcr1 = 0; unsignedlong mmcra = 0; unsignedint pmc, unit, byte, psel; unsignedint ttm; int i, isbus, bit, grsel; unsignedint pmc_inuse = 0; unsignedchar busbyte[4]; unsignedchar unituse[16]; int ttmuse;
if (n_ev > 6) return -1;
/* First pass to count resource use */
memset(busbyte, 0, sizeof(busbyte));
memset(unituse, 0, sizeof(unituse)); for (i = 0; i < n_ev; ++i) {
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK; if (pmc) { if (pmc > 6) return -1; if (pmc_inuse & (1 << (pmc - 1))) return -1;
pmc_inuse |= 1 << (pmc - 1);
} if (event[i] & PM_BUSEVENT_MSK) {
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK; if (unit > PM_LASTUNIT) return -1; if (unit == PM_ISU0_ALT)
unit = PM_ISU0; if (byte >= 4) { if (unit != PM_LSU1) return -1;
++unit;
byte &= 3;
} if (busbyte[byte] && busbyte[byte] != unit) return -1;
busbyte[byte] = unit;
unituse[unit] = 1;
}
}
/* * Assign resources and set multiplexer selects. * * PM_ISU0 can go either on TTM0 or TTM1, but that's the only * choice we have to deal with.
*/ if (unituse[PM_ISU0] &
(unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
unituse[PM_ISU0_ALT] = 1; /* move ISU to TTM1 */
unituse[PM_ISU0] = 0;
} /* Set TTM[01]SEL fields. */
ttmuse = 0; for (i = PM_FPU; i <= PM_ISU1; ++i) { if (!unituse[i]) continue; if (ttmuse++) return -1;
mmcr1 |= (unsignedlong)i << MMCR1_TTM0SEL_SH;
}
ttmuse = 0; for (; i <= PM_GRS; ++i) { if (!unituse[i]) continue; if (ttmuse++) return -1;
mmcr1 |= (unsignedlong)(i & 3) << MMCR1_TTM1SEL_SH;
} if (ttmuse > 1) return -1;
/* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */ for (byte = 0; byte < 4; ++byte) {
unit = busbyte[byte]; if (!unit) continue; if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) { /* get ISU0 through TTM1 rather than TTM0 */
unit = PM_ISU0_ALT;
} elseif (unit == PM_LSU1 + 1) { /* select lower word of LSU1 for this byte */
mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
}
ttm = unit >> 2;
mmcr1 |= (unsignedlong)ttm
<< (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
}
/* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */ for (i = 0; i < n_ev; ++i) {
pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
psel = event[i] & PM_PMCSEL_MSK;
isbus = event[i] & PM_BUSEVENT_MSK; if (!pmc) { /* Bus event or any-PMC direct event */ for (pmc = 0; pmc < 4; ++pmc) { if (!(pmc_inuse & (1 << pmc))) break;
} if (pmc >= 4) return -1;
pmc_inuse |= 1 << pmc;
} elseif (pmc <= 4) { /* Direct event */
--pmc; if (isbus && (byte & 2) &&
(psel == 8 || psel == 0x10 || psel == 0x28)) /* add events on higher-numbered bus */
mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
} else { /* Instructions or run cycles on PMC5/6 */
--pmc;
} if (isbus && unit == PM_GRS) {
bit = psel & 7;
grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
mmcr1 |= (unsignedlong)grsel << grsel_shift[bit];
} if (power5p_marked_instr_event(event[i]))
mmcra |= MMCRA_SAMPLE_ENABLE; if ((psel & 0x58) == 0x40 && (byte & 1) != ((pmc >> 1) & 1)) /* select alternate byte lane */
psel |= 0x10; if (pmc <= 3)
mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
hwc[i] = pmc;
}
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.