2

我正在尝试使用 pmu 在 linux 内核中测量我的代码的性能。首先,我想测试 pmu,因此在内核中创建了简单的耦合操作循环。我将它置于禁用中断的自旋锁下,因此我的测试代码不能被抢占。然后我打印了循环计数器来检查这个循环需要多少 CPU 周期。但我在每次打印时看到的值非常不同:100、500、1000、200,......我的问题是:为什么我每次看到的值都如此不同?PS:与循环计数器相反,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);

和真实设备上的输出是(皮质 A-57):

...
ticks 31 are: 2287
ticks 32 are: 2287
ticks 33 are: 2287
ticks 34 are: 1984
ticks 35 are: 457
ticks 36 are: 1604
ticks 37 are: 2287
...

4

1 回答 1

3

为了在 Arm 上使用计时器和 PMU 等功能,您应该isb在读取 PMU 寄存器之前插入一条指令。架构允许处理器推测性地提前或延迟读取寄存器,因为它不依赖于nops.

所以试试这个:

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

将在让指令继续isb之前刷新管道。mrsCPU 也可能在热节流,但这不应该影响您使用周期计数器的测量,但如果您正在读取通用计时器来测量时间,它会影响。

于 2019-10-28T14:27:27.470 回答