ARM Cortex-A7 中的事件计数器

Event counters in ARM Cortex-A7

ARM Cortex-A7 支持多少个事件计数器,我如何 select/read/write 这些计数器?

例如如果运行:

./perf stat -e L1-dcache-loads,branch-loads sleep 1

它在哪里存储事件计数?

Here可以看到,{c9,c13,0}代表循环计数寄存器,{c9,c13,2}代表事件计数寄存器,所以执行perf命令后哪个寄存器值会改变c9或者c13?

如果您看到以下代码:

static inline int armv7_pmnc_select_counter(int idx)
{
        u32 counter = ARMV7_IDX_TO_COUNTER(idx);
        asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));
        return idx;
}

static inline void armv7pmu_write_counter(struct perf_event *event, u32 value)
{
        struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
        if (!armv7_pmnc_counter_valid(cpu_pmu, idx))
                pr_err("CPU%u writing wrong counter %d\n",smp_processor_id(), idx);
        else if (idx == ARMV7_IDX_CYCLE_COUNTER)
                asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
        else if (armv7_pmnc_select_counter(idx) == idx)
                asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));
}

对于每个事件计数器,armv7pmu_write_counter 函数使用 armv7_pmnc_select_counter 设置不同的 idx 值,但要更新 value,它调用相同的 mcr 指令,如何?

因为第二个是数据寄存器,它提供读写a计数器值的权限,而第一个是变址寄存器,它选择那个数据寄存器的实际计数器正在运行。

采用这种设置的典型原因是,不同的实现可以提供不同数量的寄存器,而无需更改整个寄存器映射。在 ARMv7 PMU 的情况下,相对有限的系统寄存器编码 space 有 32 个计数寄存器和 32 个事件类型寄存器并不是一个很好的用途,其中大部分将未实现,你当然不会希望寄存器根据这个特定 CPU 实现的计数器数量来回移动。

如果有帮助,想象这样的事情:

class PMU {
private:
    int sel;
    int counter[NUMBER];

public:
    int  num_counters(void)    { return NUMBER; };

    void select_counter(int i) { sel = i % NUMBER; };

    void write_counter(int d)  { counter[sel] = d; };
    int  read_counter(void)    { return counter[sel]; };
}