如何在Linux/Windows上测量CPU时间和墙钟时间?

55

我的意思是:如何测量CPU在执行函数上花费的时间和运行函数所需的挂钟时间?(我对Linux / Windows以及x86和x86_64都很感兴趣)。看看我想做什么(这里我使用C ++,但我更喜欢C语言解决方案):

int startcputime, endcputime, wcts, wcte;

startcputime = cputime();
function(args);
endcputime = cputime();

std::cout << "it took " << endcputime - startcputime << " s of CPU to execute this\n";

wcts = wallclocktime();
function(args);
wcte = wallclocktime();

std::cout << "it took " << wcte - wcts << " s of real time to execute this\n";

另一个重要问题是:这种时间测量体系结构是否独立于架构?


我知道你想在代码中以编程方式实现这个,但还是让我来回答一下:http://superuser.com/questions/228056/windows-equivalent-to-unix-time-command - Son-Huy Pham
@Huytard:谢谢 :) 我知道在Linux中有time,但正如你所写的,我需要直接在C代码中实现。 - yak
在Windows上,clock()提供墙钟时间,而GetProcessTimes提供CPU时间。在Linux上,gettimeofday()提供墙钟时间,而clock()提供CPU时间。 - Mysticial
2
如果你会使用C++,那么boost::auto_cpu_timer(http://boost.org/libs/timer)就是你需要的。你只需这样编写代码:`boost::auto_cpu_timer t; function(args);`(是的,没有cout,什么都没有,就这样,你就可以得到墙上时间和CPU时间——我喜欢这个功能)。 - lip
曾经我遇到过一个问题,就是clock()函数很容易溢出。clock_t是一个4字节的有符号整数,其最大值为2^31=2.147e9。在Windows中,CLOCKS_PER_SEC为1000,在Linux中为1000000。因此,在Windows中,最大时间为24.8天,在Linux中为35.8分钟。 - Sergey
显示剩余3条评论
4个回答

71

这里有一个复制粘贴的解决方案,适用于Windows和Linux以及C和C++。

如评论中所述,有一种名为boost的库可以实现此功能。但如果不能使用boost,这个解决方案应该能够解决问题:

//  Windows
#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <time.h>
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .000001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

有许多方法来实现这些时钟。但是以下的代码片段使用了以下方式:

对于Windows系统:

对于Linux系统:


这里有一个小演示:

#include <math.h>
#include <iostream>
using namespace std;

int main(){

    //  Start Timers
    double wall0 = get_wall_time();
    double cpu0  = get_cpu_time();

    //  Perform some computation.
    double sum = 0;
#pragma omp parallel for reduction(+ : sum)
    for (long long i = 1; i < 10000000000; i++){
        sum += log((double)i);
    }

    //  Stop timers
    double wall1 = get_wall_time();
    double cpu1  = get_cpu_time();

    cout << "Wall Time = " << wall1 - wall0 << endl;
    cout << "CPU Time  = " << cpu1  - cpu0  << endl;

    //  Prevent Code Elimination
    cout << endl;
    cout << "Sum = " << sum << endl;

}

输出(12个线程):

Wall Time = 15.7586
CPU Time  = 178.719

Sum = 2.20259e+011

1
@yak 不应该是这样的。它们是特定于操作系统的。而且Windows可能使用 rdtsc() 来实现性能计数器。但如果在不同的架构上,实现这些功能就是操作系统的工作。至于在内联汇编中执行这些操作,这很棘手。请注意,仅凭 rdtsc() 是无法获得墙时的,因为您仍然需要某些信息来告诉你一秒钟有多少个时钟周期。我不知道除了操作系统以外还有什么可以给你CPU时间。 - Mysticial
经过的时间(wall1 - wall0)是以秒为单位吗? - dynamic
1
@llnk 是的,它们都是以秒为单位。 - Mysticial
1
clock() 在 Linux 上运行良好,但不包括在子进程中花费的时间(例如由 system() 调用启动的进程)。如果您需要测量子进程中花费的时间,请查看 times(),它为当前进程和子进程提供 CPU 时间和系统时间。请注意,这里的每秒钟时钟数不是 CLOCKS_PER_SEC,而是 sysconf(_SC_CLK_TCK) - farindk
使用QueryPerformanceCounter时要小心,因为它可能会突然向前跳几秒钟,所以您必须不断将其与GetTickCount进行比较:Microsoft KB274323 - Tyler Streeter
显示剩余4条评论

37

C++11更易于编写!

使用std::chrono::system_clock获取墙上时钟和std::clock获取CPU时钟http://en.cppreference.com/w/cpp/chrono/system_clock

#include <cstdio>
#include <ctime>
#include <chrono>

.... 

std::clock_t startcputime = std::clock();
do_some_fancy_stuff();
double cpu_duration = (std::clock() - startcputime) / (double)CLOCKS_PER_SEC;
std::cout << "Finished in " << cpu_duration << " seconds [CPU Clock] " << std::endl;


auto wcts = std::chrono::system_clock::now();
do_some_fancy_stuff();
std::chrono::duration<double> wctduration = (std::chrono::system_clock::now() - wcts);
std::cout << "Finished in " << wctduration.count() << " seconds [Wall Clock]" << std::endl;

Et voilà,易于使用和携带!无需 #ifdef _WIN32 或 LINUX!

如果需要更高的精度,甚至可以使用 chrono::high_resolution_clock http://en.cppreference.com/w/cpp/chrono/high_resolution_clock


1
为什么在wcts上使用auto,然后在wctduration上使用std::chrono::duration<double> - puk
3
很遗憾,std::clock在Windows上的工作方式不太标准,因此“可移植”有点过于乐观。 - n. m.
@n.'pronouns'm. std::clock在Windows上以非标准的方式工作,具体是什么问题?您能详细解释一下吗? - user561749
@user561749 它测量的是挂钟时间,而不是标准所要求的 CPU 时间。这在其他评论中已经讨论过了,请阅读它们。 - n. m.
从您的链接中可以看到,system_clock()函数“可能不是单调的:在大多数系统上,系统时间可以在任何时刻进行调整。”例如,闰秒、NTP漂移等。如果您想获取代码的挂钟时间,应该使用steady_clock()函数。 - undefined

16

为了给@lip的建议提供一个具体的例子,如果可以的话,请使用boost::timer(在Boost 1.51中测试过):

#include <boost/timer/timer.hpp>

// this is wallclock AND cpu time
boost::timer::cpu_timer timer;

... run some computation ...

boost::timer::cpu_times elapsed = timer.elapsed();
std::cout << " CPU TIME: " << (elapsed.user + elapsed.system) / 1e9 << " seconds"
          << " WALLCLOCK TIME: " << elapsed.wall / 1e9 << " seconds"
          << std::endl;

哪一个是总时间? - Tomáš Zato
“total” 是指哪个方面?CPU 时间通常是在所有线程/核心上累加的(即每个 CPU 核心忙于执行代码的时间总和),墙钟时间是你需要等待代码完成的时间。对于在多个 CPU 核心上运行的代码,CPU 时间可能大于墙钟时间。 - Andre Holzner
1
不,你没有想明白,两者都是“总时间”,一个是墙上时钟时间,另一个是 CPU 时间。 - Neel Basu

0

使用 time.h 中的 clock 方法:

clock_t start = clock();
/* Do stuffs */
clock_t end = clock();
float seconds = (float)(end - start) / CLOCKS_PER_SEC;

不幸的是,这种方法在Linux上返回CPU时间,但在Windows上返回挂钟时间(感谢评论者提供此信息)。


它会给我哪个时间?墙上时钟时间还是CPU时间? - yak
它测量的是 CPU 时间,如果这正是你所寻找的。 - syb0rg
3
@syb0rg 实际上,clock() 在 Linux 上返回 CPU 时间,在 Windows 上返回墙钟时间。 - Mysticial
@yak 试一下吧。你会发现clock()会给出实时时间,不受线程活动的影响。 - Mysticial
3
@syb0rg:根据ISO标准,clock()应该返回CPU时间;然而微软的文档明确说明它在Windows中返回挂钟时间... - Christoph
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接