Commit b2e23725 authored by Aaron Lindsay's avatar Aaron Lindsay Committed by Peter Maydell
Browse files

target/arm: PMU: Add instruction and cycle events



The instruction event is only enabled when icount is used, cycles are
always supported. Always defining get_cycle_count (but altering its
behavior depending on CONFIG_USER_ONLY) allows us to remove some
CONFIG_USER_ONLY #defines throughout the rest of the code.

Signed-off-by: default avatarAaron Lindsay <alindsay@codeaurora.org>
Signed-off-by: default avatarAaron Lindsay <aaron@os.amperecomputing.com>
Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Message-id: 20181211151945.29137-12-aaron@os.amperecomputing.com
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 5ecdd3e4
Loading
Loading
Loading
Loading
+44 −46
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "arm_ldst.h"
#include <zlib.h> /* For crc32 */
#include "exec/semihost.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "fpu/softfloat.h"
#include "qemu/range.h"
@@ -1021,7 +1022,48 @@ typedef struct pm_event {
    uint64_t (*get_count)(CPUARMState *);
} pm_event;

static bool event_always_supported(CPUARMState *env)
{
    return true;
}

/*
 * Return the underlying cycle count for the PMU cycle counters. If we're in
 * usermode, simply return 0.
 */
static uint64_t cycles_get_count(CPUARMState *env)
{
#ifndef CONFIG_USER_ONLY
    return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
                   ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
#else
    return cpu_get_host_ticks();
#endif
}

#ifndef CONFIG_USER_ONLY
static bool instructions_supported(CPUARMState *env)
{
    return use_icount == 1 /* Precise instruction counting */;
}

static uint64_t instructions_get_count(CPUARMState *env)
{
    return (uint64_t)cpu_get_icount_raw();
}
#endif

static const pm_event pm_events[] = {
#ifndef CONFIG_USER_ONLY
    { .number = 0x008, /* INST_RETIRED, Instruction architecturally executed */
      .supported = instructions_supported,
      .get_count = instructions_get_count,
    },
    { .number = 0x011, /* CPU_CYCLES, Cycle */
      .supported = event_always_supported,
      .get_count = cycles_get_count,
    }
#endif
};

/*
@@ -1030,7 +1072,7 @@ static const pm_event pm_events[] = {
 * should first be updated to something sparse instead of the current
 * supported_event_map[] array.
 */
#define MAX_EVENT_ID 0x0
#define MAX_EVENT_ID 0x11
#define UNSUPPORTED_EVENT UINT16_MAX
static uint16_t supported_event_map[MAX_EVENT_ID + 1];

@@ -1131,8 +1173,6 @@ static CPAccessResult pmreg_access_swinc(CPUARMState *env,
    return pmreg_access(env, ri, isread);
}

#ifndef CONFIG_USER_ONLY

static CPAccessResult pmreg_access_selr(CPUARMState *env,
                                        const ARMCPRegInfo *ri,
                                        bool isread)
@@ -1243,9 +1283,7 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter)
 */
void pmccntr_op_start(CPUARMState *env)
{
    uint64_t cycles = 0;
    cycles = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
                          ARM_CPU_FREQ, NANOSECONDS_PER_SECOND);
    uint64_t cycles = cycles_get_count(env);

    if (pmu_counter_enabled(env, 31)) {
        uint64_t eff_cycles = cycles;
@@ -1391,42 +1429,6 @@ static void pmccntr_write32(CPUARMState *env, const ARMCPRegInfo *ri,
    pmccntr_write(env, ri, deposit64(cur_val, 0, 32, value));
}

#else /* CONFIG_USER_ONLY */

void pmccntr_op_start(CPUARMState *env)
{
}

void pmccntr_op_finish(CPUARMState *env)
{
}

void pmevcntr_op_start(CPUARMState *env, uint8_t i)
{
}

void pmevcntr_op_finish(CPUARMState *env, uint8_t i)
{
}

void pmu_op_start(CPUARMState *env)
{
}

void pmu_op_finish(CPUARMState *env)
{
}

void pmu_pre_el_change(ARMCPU *cpu, void *ignored)
{
}

void pmu_post_el_change(ARMCPU *cpu, void *ignored)
{
}

#endif

static void pmccfiltr_write(CPUARMState *env, const ARMCPRegInfo *ri,
                            uint64_t value)
{
@@ -1823,7 +1825,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
    /* Unimplemented so WI. */
    { .name = "PMSWINC", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 4,
      .access = PL0_W, .accessfn = pmreg_access_swinc, .type = ARM_CP_NOP },
#ifndef CONFIG_USER_ONLY
    { .name = "PMSELR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 5,
      .access = PL0_RW, .type = ARM_CP_ALIAS,
      .fieldoffset = offsetoflow32(CPUARMState, cp15.c9_pmselr),
@@ -1845,7 +1846,6 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
      .fieldoffset = offsetof(CPUARMState, cp15.c15_ccnt),
      .readfn = pmccntr_read, .writefn = pmccntr_write,
      .raw_readfn = raw_read, .raw_writefn = raw_write, },
#endif
    { .name = "PMCCFILTR", .cp = 15, .opc1 = 0, .crn = 14, .crm = 15, .opc2 = 7,
      .writefn = pmccfiltr_write_a32, .readfn = pmccfiltr_read_a32,
      .access = PL0_RW, .accessfn = pmreg_access,
@@ -5675,7 +5675,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         * count register.
         */
        unsigned int i, pmcrn = 0;
#ifndef CONFIG_USER_ONLY
        ARMCPRegInfo pmcr = {
            .name = "PMCR", .cp = 15, .crn = 9, .crm = 12, .opc1 = 0, .opc2 = 0,
            .access = PL0_RW,
@@ -5732,7 +5731,6 @@ void register_cp_regs_for_features(ARMCPU *cpu)
            g_free(pmevtyper_name);
            g_free(pmevtyper_el0_name);
        }
#endif
        ARMCPRegInfo clidr = {
            .name = "CLIDR", .state = ARM_CP_STATE_BOTH,
            .opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,