ARM中有与rdtsc等效的指令吗?

问题描述 投票:0回答:3

对于我的项目我必须使用内联汇编指令例如rdtsc来计算一些C/C++指令的执行时间。

以下代码似乎适用于 Intel,但不适用于 ARM 处理器:

{unsigned a, d;asm volatile("rdtsc" : "=a" (a), "=d" (d)); t0 = ((unsigned long)a) | (((unsigned long)d) << 32);}
//The C++ statement to measure its execution time
{unsigned a, d;asm volatile("rdtsc" : "=a" (a), "=d" (d)); t1 = ((unsigned long)a) | (((unsigned long)d) << 32);}
time = t1-t0;

我的问题是:

如何编写类似于上面的内联汇编代码(计算指令的执行时间)以在ARM处理器上工作?

c++ c assembly arm inline-assembly
3个回答
21
投票

您应该读取协处理器

PMCCNTR
(不是实际的协处理器,只是CPU函数的入口点)的
p15
寄存器来获取周期计数。请注意,只有在以下情况下,它才可用于非特权应用程序:

  1. 允许非特权

    PMCCNTR
    读取:

    PMUSERENR
    寄存器的位0必须设置为1(官方文档

  2. PMCCNTR
    实际上是在计算周期:

    PMCNTENSET
    寄存器的位31必须设置为1(官方文档

这是一个真实世界的示例,说明它是如何完成的。


12
投票

对于 Arm64,系统寄存器

CNTVCT_EL0
可用于检索计数器 用户空间。

// SPDX-License-Identifier: GPL-2.0
u64 rdtsc(void)
{
    u64 val;

    /*
     * According to ARM DDI 0487F.c, from Armv8.0 to Armv8.5 inclusive, the
     * system counter is at least 56 bits wide; from Armv8.6, the counter
     * must be 64 bits wide.  So the system counter could be less than 64
     * bits wide and it is attributed with the flag 'cap_user_time_short'
     * is true.
     */
    asm volatile("mrs %0, cntvct_el0" : "=r" (val));

    return val;
}

请参阅此补丁https://lore.kernel.org/patchwork/patch/1305380/了解更多详细信息。


0
投票

我在这里找到了一个非 GPL,但关于读取 ARM64 上系统实时计数器的 BSD 源代码:https://github.com/cloudius-systems/osv/blob/master/arch/aarch64/arm-clock.cc

更好的是,那里的代码不仅像

rdtsc()
在 Intel/AMD 上那样提供某种滴答声,它甚至还报告这些滴答声的频率。是的,它在多核上的所有核心上都是同步的。因此它对很多事情都很有用,包括基准测试或跟踪线程池中的线程等。当然,它不会具有系统时钟的长期稳定性,系统时钟通过
 同步到外部时间源ntp

引用的代码中定义的

class arm_clock
对于许多目的来说可能有点过分了。例如,它还展示了如何设置硬件计时器,这是普通用户模式进程可能没有权限执行的操作。以下是读取 TSC 和频率的最重要部分的摘录。它可以在 Intel、AMD 和 ARM 上与最新的 GCC 良好地编译。当然,频率读数仅在 ARM 上提供:

#ifdef __ARM_ARCH_ISA_A64
// Adapted from: https://github.com/cloudius-systems/osv/blob/master/arch/aarch64/arm-clock.cc
uint64_t rdtsc() {
    //Please note we read CNTVCT cpu system register which provides
    //the accross-system consistent value of the virtual system counter.
    uint64_t cntvct;
    asm volatile ("mrs %0, cntvct_el0; " : "=r"(cntvct) :: "memory");
    return cntvct;
}

uint64_t rdtsc_barrier() {
    uint64_t cntvct;
    asm volatile ("isb; mrs %0, cntvct_el0; isb; " : "=r"(cntvct) :: "memory");
    return cntvct;
}

uint32_t rdtsc_freq() {
    uint32_t freq_hz;
    asm volatile ("mrs %0, cntfrq_el0; isb; " : "=r"(freq_hz) :: "memory");
    return freq_hz;
}
#else
#include <x86intrin.h>
uint64_t rdtsc(){ return __rdtsc(); }
#endif

我测试的执行时间在

rdtsc()
为7 ns,
rdtsc_barrier()
为30 ns,与Intel和AMD非常相似。

© www.soinside.com 2019 - 2024. All rights reserved.