PM_RUN_INST_CMPL, instructions completed with the run latch set, is the architected PowerISA v3.1 event defined with PMC4SEL = 0xFA.
Implement it by checking for the CTRL RUN bit before incrementing the counter. To make this work properly we also need to force a new translation block each time SPR_CTRL is written. A small tweak in pmu_events_increment_insns() is then needed to only increment this event if the thread has the run latch. Signed-off-by: Daniel Henrique Barboza <danielhb...@gmail.com> --- target/ppc/cpu.h | 4 ++++ target/ppc/cpu_init.c | 2 +- target/ppc/power8-pmu.c | 23 ++++++++++++++++++++--- target/ppc/spr_tcg.h | 1 + target/ppc/translate.c | 12 ++++++++++++ 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 185a6166aa..6f9a48a5a1 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -302,6 +302,7 @@ typedef enum { PMU_EVENT_INVALID = 0, PMU_EVENT_CYCLES, PMU_EVENT_INSTRUCTIONS, + PMU_EVENT_INSN_RUN_LATCH, } PMUEventType; typedef struct PMUEvent { @@ -398,6 +399,9 @@ typedef struct PMUEvent { #define MMCR1_PMC4SEL_START 56 #define MMCR1_PMC4EVT_EXTR (64 - MMCR1_PMC4SEL_START - MMCR1_EVT_SIZE) +/* PMU uses CTRL_RUN to sample PM_RUN_INST_CMPL */ +#define CTRL_RUN PPC_BIT(63) + /* LPCR bits */ #define LPCR_VPM0 PPC_BIT(0) #define LPCR_VPM1 PPC_BIT(1) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index ffcd08a947..eb1a0320b9 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -6748,7 +6748,7 @@ static void register_book3s_ctrl_sprs(CPUPPCState *env) { spr_register(env, SPR_CTRL, "SPR_CTRL", SPR_NOACCESS, SPR_NOACCESS, - SPR_NOACCESS, &spr_write_generic, + SPR_NOACCESS, &spr_write_CTRL, 0x00000000); spr_register(env, SPR_UCTRL, "SPR_UCTRL", &spr_read_ureg, SPR_NOACCESS, diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c index e9c6b9dfec..3946314e9c 100644 --- a/target/ppc/power8-pmu.c +++ b/target/ppc/power8-pmu.c @@ -62,6 +62,15 @@ static void define_enabled_events(CPUPPCState *env) event->type = PMU_EVENT_CYCLES; } break; + case 0xFA: + /* + * PMC4SEL = 0xFA is the "instructions completed + * with run latch set" event. + */ + if (event->sprn == SPR_POWER_PMC4) { + event->type = PMU_EVENT_INSN_RUN_LATCH; + } + break; case 0xFE: /* * PMC1SEL = 0xFE is the architected PowerISA v3.1 @@ -110,13 +119,21 @@ static bool pmu_events_increment_insns(CPUPPCState *env, uint32_t num_insns) /* PMC6 never counts instructions. */ for (i = 0; i < PMU_EVENTS_NUM - 1; i++) { PMUEvent *event = &env->pmu_events[i]; + bool insn_event = event->type == PMU_EVENT_INSTRUCTIONS || + event->type == PMU_EVENT_INSN_RUN_LATCH; - if (!pmu_event_is_active(env, event) || - event->type != PMU_EVENT_INSTRUCTIONS) { + if (!pmu_event_is_active(env, event) || !insn_event) { continue; } - env->spr[event->sprn] += num_insns; + if (event->type == PMU_EVENT_INSTRUCTIONS) { + env->spr[event->sprn] += num_insns; + } + + if (event->type == PMU_EVENT_INSN_RUN_LATCH && + env->spr[SPR_CTRL] & CTRL_RUN) { + env->spr[event->sprn] += num_insns; + } if (env->spr[event->sprn] >= COUNTER_NEGATIVE_VAL && pmu_event_has_overflow_enabled(env, event)) { diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h index 82f9dc16a4..28126da6e2 100644 --- a/target/ppc/spr_tcg.h +++ b/target/ppc/spr_tcg.h @@ -27,6 +27,7 @@ void spr_read_generic(DisasContext *ctx, int gprn, int sprn); void spr_write_generic(DisasContext *ctx, int sprn, int gprn); void spr_write_MMCR0(DisasContext *ctx, int sprn, int gprn); void spr_write_MMCR1(DisasContext *ctx, int sprn, int gprn); +void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn); void spr_read_xer(DisasContext *ctx, int gprn, int sprn); void spr_write_xer(DisasContext *ctx, int sprn, int gprn); void spr_read_lr(DisasContext *ctx, int gprn, int sprn); diff --git a/target/ppc/translate.c b/target/ppc/translate.c index acc0e50194..e2839883be 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -404,6 +404,18 @@ void spr_write_generic(DisasContext *ctx, int sprn, int gprn) spr_store_dump_spr(sprn); } +void spr_write_CTRL(DisasContext *ctx, int sprn, int gprn) +{ + spr_write_generic(ctx, sprn, gprn); + + /* + * SPR_CTRL writes must force a new translation block, + * allowing the PMU to calculate the run latch events with + * more accuracy. + */ + ctx->base.is_jmp = DISAS_EXIT_UPDATE; +} + #if !defined(CONFIG_USER_ONLY) void spr_write_generic32(DisasContext *ctx, int sprn, int gprn) { -- 2.31.1