2

我熟悉两种方法,但它们都有其局限性。

第一个是使用指令RDTSC。但是,问题在于它没有单独计算我的程序的周期数,因此对并发进程引起的噪声很敏感。

第二种选择是使用clock库函数。我认为这种方法是可靠的,因为我希望它只计算我的程序的周期数(我打算实现的目标)。但是,事实证明,在我的情况下,它测量经过的时间,然后将其乘以 CLOCKS_PER_SEC. 这不仅不可靠,而且是错误的,因为 CLOCKS_PER_SEC设置为1,000,000与我的处理器的实际频率不对应。

鉴于所提出方法的局限性,是否有更好、更可靠的替代方案来产生一致的结果?

4

3 回答 3

4

这里很大程度上取决于您尝试测量的时间量。

如果正确使用,RDTSC 可以(几乎)100% 可靠。然而,它主要用于测量真正微观的代码片段。如果你想测量两个序列,比如说,几十个左右的指令,可能没有其他东西可以做同样的工作。

不过,正确使用它有点挑战性。一般来说,要获得良好的测量结果,您至少需要执行以下操作:

  1. 将代码设置为仅在一个特定内核上运行。
  2. 将代码设置为以最高优先级执行,这样就没有任何东西可以抢占它。
  3. 大量使用 CPUID 以确保在需要时进行序列化。

另一方面,如果您试图测量需要花费 100 毫秒以上的任何时间的东西,那RDTSC是没有意义的。这就像试图用千分尺测量城市之间的距离。为此,通常最好确保有问题的代码需要(至少)一秒钟左右的大部分时间。clock不是特别精确,但是在这个一般顺序的一段时间内,它可能只精确到 10 毫秒左右这一事实或多或少无关紧要。

于 2016-03-11T00:27:52.437 回答
2

Linuxperf_event_open系统调用与config = PERF_COUNT_HW_CPU_CYCLES

此系统调用对以下内容具有显式控制:

  • 过程PID选择
  • 是否考虑内核/管理程序指令

因此,即使多个进程同时运行,它也会正确计算周期。

有关更多详细信息,请参阅此答案:如何从 C++ 获取 x86_64 中的 CPU 周期计数?

perf_event_open.c

#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <inttypes.h>

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                int cpu, int group_fd, unsigned long flags)
{
    int ret;

    ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
                    group_fd, flags);
    return ret;
}

int
main(int argc, char **argv)
{
    struct perf_event_attr pe;
    long long count;
    int fd;

    uint64_t n;
    if (argc > 1) {
        n = strtoll(argv[1], NULL, 0);
    } else {
        n = 10000;
    }

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HARDWARE;
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_CPU_CYCLES;
    pe.disabled = 1;
    pe.exclude_kernel = 1;
    // Don't count hypervisor events.
    pe.exclude_hv = 1;

    fd = perf_event_open(&pe, 0, -1, -1, 0);
    if (fd == -1) {
        fprintf(stderr, "Error opening leader %llx\n", pe.config);
        exit(EXIT_FAILURE);
    }

    ioctl(fd, PERF_EVENT_IOC_RESET, 0);
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

    /* Loop n times, should be good enough for -O0. */
    __asm__ (
        "1:;\n"
        "sub $1, %[n];\n"
        "jne 1b;\n"
        : [n] "+r" (n)
        :
        :
    );

    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
    read(fd, &count, sizeof(long long));

    printf("%lld\n", count);

    close(fd);
}
于 2020-11-18T17:29:06.037 回答
0

RDTSC 是计算程序执行周期的最准确方法。如果您希望在线程被抢占的情况下随时间尺度测量执行性能,那么使用分析器(例如 VTune)可能会更好。

与几乎没有开销的 RDTSC 相比,CLOCKS_PER_SECOND/clock() 是一种非常糟糕(低性能)的获取时间的方法。

如果您对 RDTSC 有特定问题,我可以提供帮助。


回复:评论

Intel Performance Counter Monitor:这主要用于测量处理器之外的指标,例如内存带宽、电源使用情况、PCIe 使用情况。它也确实会测量 CPU 频率,但它通常对处理器受限的应用程序性能没有用处。

RDTSC可移植性:RDTSC 是所有现代 Intel CPU 都支持的 Intel CPU 指令。在现代 CPU 上,它基于您的 CPU 的非核心频率,并且在 CPU 核心之间有些相似,尽管如果您的应用程序经常被不同的核心(尤其是不同的插槽)抢占,这是不合适的。如果是这种情况,您真的想查看分析器。

乱序执行:是的,事情是乱序执行的,所以这可能会稍微影响性能,但执行指令仍然需要时间,RDTSC 是衡量该时间的最佳方法。它在在同一个内核上执行非 IO 绑定指令的正常用例中表现出色,这就是它的真正用途。如果您有一个更复杂的用例,您确实应该使用不同的工具,但这并不能否定 rdtsc() 在分析程序执行时非常有用。

于 2016-03-10T18:14:55.257 回答