C ARM PMU循环计数器的值不一致

C ARM PMU循环计数器的值不一致,c,linux-kernel,arm,arm64,intel-pmu,C,Linux Kernel,Arm,Arm64,Intel Pmu,我试图用pmu来衡量linux内核中代码的性能。 首先,我想测试pmu,因此在内核中创建了简单的耦合循环操作。我把它放在禁用中断的自旋锁下,这样我的测试代码就不能被抢占。然后我打印周期计数器来检查这个循环需要多少CPU周期。但我在每一张打印上看到了非常不同的值:1005001000200。。。 我的问题是:为什么我每次都看到如此不同的价值观? PS:在countrary to cycle counter中,pmu的指令计数器是稳定的,我每次都看到相同的值。 我还尝试使用arm定时器,但它也显示了

我试图用pmu来衡量linux内核中代码的性能。 首先,我想测试pmu,因此在内核中创建了简单的耦合循环操作。我把它放在禁用中断的自旋锁下,这样我的测试代码就不能被抢占。然后我打印周期计数器来检查这个循环需要多少CPU周期。但我在每一张打印上看到了非常不同的值:1005001000200。。。 我的问题是:为什么我每次都看到如此不同的价值观? PS:在countrary to cycle counter中,pmu的指令计数器是稳定的,我每次都看到相同的值。 我还尝试使用arm定时器,但它也显示了不同的值,类似于pmu的循环计数器。 以下是我如何使用ARM定时器来测量性能:

unsigned long long ticks_start, ticks_end;
int i = 0, j;
unsigned long flags;

spin_lock_irqsave(&lock, flags);
while (i++ < 100) {
   j = 0;
   asm volatile("mrs %0, CNTPCT_EL0" : "=r" (ticks_start)); 
   while (j++ < 10000) {
      asm volatile ("nop");
   }
   asm volatile("mrs %0, CNTPCT_EL0" : "=r" (ticks_end));
   printk("ticks %d are: %llu\n", i, ticks_end - ticks_start);
}
spin_unlock_irqrestore(&lock, flags);


对于在Arm上使用计时器和PMU之类的东西,应该在读取PMU寄存器之前插入
isb
指令。体系结构允许处理器推测性地提前或延迟读取寄存器,因为它不依赖于
nops
的内部循环

所以试试这个:

asm volatile("isb; mrs %0, CNTPCT_EL0" : "=r" (ticks_end));

isb
将在执行
mrs
指令之前刷新管道。CPU也可能是热节流的,但这不应影响使用循环计数器的测量,但是,如果你正在阅读通用计时器来测量时间,你会这样做。

请提供准确的代码,你是如何测量时间的,以及测量什么的?为什么你希望每次都是一样的?@Alex Hoppus我提供了ARM计时器代码片段。@old_timer,但我不明白为什么会有如此巨大的差异,例如100和500。。。这是什么原因?它在同一个CPU内核上的原子上下文中执行,但我每次都看到不同的值time@scopichmu您应该提供程序集
asm volatile("isb; mrs %0, CNTPCT_EL0" : "=r" (ticks_end));