这是c++和Python之间CPU时间比较的有效方法吗?

Is this a valid method for CPU time comparison between C++ and Python?

本文关键字:有效 方法 比较 时间 c++ Python 之间 CPU 这是      更新时间:2023-10-16

我感兴趣的是比较CPU时间一些代码部分编写的c++和Python(运行在Linux上)。下面的方法会在两者之间产生一个"公平"的比较吗?

Python

使用资源模块:
import resource
def cpu_time():
    return resource.getrusage(resource.RUSAGE_SELF)[0]+ # time in user mode
        resource.getrusage(resource.RUSAGE_SELF)[1] # time in system mode

允许这样计时:

def timefunc( func ):
    start=cpu_time()
    func()
    return (cpu_time()-start)

然后测试如下:

def f():
    for i in range(int(1e6)):
        pass
avg = 0
for k in range(10):
    avg += timefunc( f ) / 10.0
print avg
=> 0.002199700000000071
<标题> c++ h1> 用ctime lib:
#include <ctime>
#include <iostream>
int main() {
    double avg = 0.0;
    int N = (int) 1e6;
    for (int k=0; k<10; k++) {
        clock_t start;
        start = clock();
        for (int i=0; i<N; i++) continue;
        avg += (double)(clock()-start) / 10.0 / CLOCKS_PER_SEC;
    }
    std::cout << avg << 'n';
    return 0;
}

生成0.002

问题:

  1. 我读过c++ clock()测量CPU时间,这是我所追求的,但我似乎找不到它是否包括用户和系统时间。
  2. c++的
  3. 结果不太精确。为什么呢?
  4. 如上所述的总体比较公平性。
<标题> 更新

按照David在注释中的建议更新了c++代码:

#include <sys/resource.h>
#include <iostream>
int main() {
    double avg = 0.0;
    int N = (int) 1e6;
    int tally = 0;
    struct rusage usage;
    struct timeval ustart, ustop, sstart, sstop;
    getrusage(RUSAGE_SELF, &usage);
    ustart = usage.ru_utime;
    sstart = usage.ru_stime;
    for (int k=0; k<10; k++) {
        ustart = usage.ru_utime;
        sstart = usage.ru_stime;
        for (int i=0; i<N; i++) continue;
        getrusage(RUSAGE_SELF, &usage);
        ustop = usage.ru_utime;
        sstop = usage.ru_stime;
        avg += (
            (ustop.tv_sec+ustop.tv_usec/1e6+
            sstop.tv_sec+sstop.tv_usec/1e6)
            -
            (ustart.tv_sec+ustart.tv_usec/1e6+
            sstart.tv_sec+sstart.tv_usec/1e6)
        ) / 10.0; 
    }
    std::cout << avg << 'n';
    return 0;
}
运行:

g++ -O0 cpptimes.cpp ; ./a.out
=> 0.0020996
g++ -O1 cpptimes.cpp ; ./a.out
=> 0

所以我想getrusage给我一点更好的分辨率,但我不确定我应该读多少。

文档说:

"返回进程从与程序执行相关的实现定义时代开始以来所使用的近似处理器时间。"

将结果值转换为秒。

这很模糊。CLOCK_PER_SEC设置为10^6,近似表示低分辨率,并不是说当前时钟超过1000快,结果是四舍五入的。这可能不是一个非常专业的术语,但它是合适的。我测试的所有地方的实际分辨率都是100Hz = 0.01 s。这种情况已经持续好多年了。在这里注明日期http://www.guyrutenberg.com/2007/09/10/resolution-problems-in-clock/。

然后文档后面跟着:"在posix兼容系统上,时钟id为CLOCK_PROCESS_CPUTIME_ID的clock_gettime提供更好的分辨率。"

:

  1. 这只是CPU时间。但是2个线程= 2*CPU时间。

  2. 如前所述,它根本不适合细粒度测量。

  3. 在我看来,测量挂钟是唯一明智的事情,但这是一个相当个人的观点。特别是对于多线程应用程序和一般的多处理。否则system + user的结果应该相似。

编辑:3。这当然适用于计算任务。如果您的进程使用sleep或放弃执行返回给系统,那么测量CPU时间可能更可行。另外,关于clock分辨率是呃…坏的。确实如此,但公平地说,有人可能会认为不应该度量如此短的计算。在我看来,这太糟糕了,但如果你在几秒钟内测量时间,我想这很好。我个人会使用其他可用的工具。

设置优化标志当然会有很大的不同。

c++是一种需要编译优化的语言,特别是当所讨论的代码使用c++标准库中的容器和迭代器时。

一个简单的++iterator在未优化编译时从一个相当大的函数调用链缩小到一个或两个程序集语句。

也就是说,我知道编译器会对测试代码做什么。任何合适的优化编译器都会使for (int i=0; i<N; i++) continue;循环消失。这是工作中的as-if规则。该循环不做任何事情,因此编译器可以自由地将其视为根本不存在。

当我观察一个可疑的CPU占用者的CPU行为时,我编写了一个简单的驱动程序(在一个单独的文件中),该驱动程序多次调用可疑的函数,有时调用的次数非常多。我在启用优化的情况下编译要测试的功能,但在禁用优化的情况下编译驱动程序。我不希望一个过于聪明的优化编译器看到这100,000个对function_to_be_tested()的调用可以被拉出循环,然后进一步优化循环。

在单个调用开始计时器和停止计时器之间多次调用test函数有许多可靠的理由。这就是为什么python有timeit模块。