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]; };
}
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]; };
}