【问题标题】:Event counters in ARM Cortex-A7ARM Cortex-A7 中的事件计数器
【发布时间】:2026-01-27 19:00:01
【问题描述】:

ARM Cortex-A7 支持多少个事件计数器,如何选择/读取/写入这些计数器?

例如如果运行:

./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 函数设置不同的idx 值与armv7_pmnc_select_counter 但要更新value,它调用相同的mcr 指令,如何?

【问题讨论】:

标签: arm armv7 perf


【解决方案1】:

因为第二个是数据寄存器,它允许读取和写入 a 计数器值,而第一个是索引寄存器,它选择数据寄存器正在操作的实际计数器。

进行这种设置的典型原因是,不同的实现可以提供不同数量的寄存器,而无需更改整体寄存器映射。在 ARMv7 PMU 的情况下,拥有 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]; };
}

【讨论】:

  • 感谢您的回答!现在,我明白了:-)
  • @enfinet 您可以接受答案,方法是单击答案左侧的“投票”计数。这向人们表明您(提问者)认为答案是正确的。此外,它还为您提供了一些关于堆栈溢出的更多信息。
  • 是的,我已经投票了,但它没有公开显示,因为我的声望不超过 15。它会在 score(>=15) 之后更新 :) .