【问题标题】:Linux alternative to Windows high-resolution performance counter APILinux 替代 Windows 高分辨率性能计数器 API
【发布时间】:2011-12-15 15:05:48
【问题描述】:

我正在寻找 Windows 高分辨率性能计数器 API 的 Linux 替代方案,尤其是以下 API 函数:

谢谢。

【问题讨论】:

    标签: linux performancecounter


    【解决方案1】:

    查看带有CLOCK_MONOTONIC_RAW 标志的clock_gettime()clock_getres()

    这里也是一个如何使用它的例子:

    【讨论】:

    • 我还是想不通:当我尝试使用clock_gettime(clock_id, &tp); tp 仅以微秒和秒为单位返回经过的时间,我需要的是周期数(=tickes)。
    • @user1087995:CPU 周期?什么CPU呢?除非您明确设置 CPU 亲和性,否则您的程序可以安排在不同的 CPU 上。这种衡量性能的方法几乎已经过时了。但如果你仍然想走那条路,看看 RDTSC - en.wikipedia.org/wiki/Time_Stamp_Counter
    • 但是为了获得精度,您必须知道 CPU 频率才能将周期数转换为时间。但是,CPU 频率可能不是恒定的,即英特尔有 Turbo Boost 技术来节能等。这样说吧 - Windows 是有缺陷的。
    • @ScrollerBlaster:感谢您的提示。我提供了一个新链接。虽然现在它有点 C 并且也移植到了 OS X。
    • 如果你想用 C99 支持编译 stopwatch,你必须使用 gcc 标志 -std=gnu99 而不是 -std=c99 才能工作。只是添加,因为我为此工作了一个小时:)
    【解决方案2】:

    perf 工具已经随内核一起提供了一段时间,现在可能会满足您的需求。它有很多选项,所以请仔细研究;)

    编辑:算了,我以为你在谈论 CPU 性能计数器。

    【讨论】:

    • 感谢您的快速回复。我需要在 cpp 程序中使用这些功能。我该怎么做?
    • @user1087995: perf 是一个分析工具,可以为您提供许多指标,但它甚至与QueryPerformanceCounter 在 Windows 上所做的相比还差得远。所以perf 不是答案。 clock_gettime () 是为您提供高精度(硬件)贴墙时间的原因。使用它。
    • 嗯,好吧,当我看到“性能计数器”时,我真的以为 CPU 性能计数器是指的,但这里似乎不是这种情况。
    【解决方案3】:

    Linux perf_event_open 系统调用

    此系统调用以与架构无关的方式公开多个性能计数器。

    man perf_event_open 记录了可用的计数器,其中包括您所期望的所有最基本的东西:

    • 循环计数 (config = PERF_COUNT_HW_CPU_CYCLES)
    • 缓存命中和未命中 (type = PERF_TYPE_HW_CACHE)
    • 分支未命中 (config = PERF_COUNT_HW_BRANCH_MISSES)
    • 内核软件可见事件,例如页面错误 (PERF_COUNT_SW_PAGE_FAULTS) 和上下文切换 (PERF_COUNT_SW_CONTEXT_SWITCHES)

    我在How to get the CPU cycle count in x86_64 from C++? 处给出了循环计数

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-14
      • 2010-12-06
      相关资源
      最近更新 更多