这里有几个问题。第一个问题是,当传递给
diffclock()
函数时,你显然交换了开始和停止时间。第二个问题是优化。启用优化的任何合理智能编译器都会将整个循环丢弃,因为它没有任何副作用。但即使你解决了以上问题,该程序最可能仍将打印 0。如果你想象每秒进行数十亿次操作,使用先进的乱序执行、预测和现代 CPU 使用的大量其他技术,甚至 CPU 也可以优化掉你的循环。但即使它没有,你需要远远超过 10K 次迭代才能让程序运行更长时间。你可能需要让程序运行一两秒钟才能使
clock()
反映出任何东西。
但最重要的问题是
clock()
本身。该函数不适用于任何性能测量时间。它所做的是给出程序使用的处理器时间的
近似值。除了可能由任何给定实现使用的近似方法的模糊性质(因为标准不要求任何特定的东西),POSIX标准还要求
CLOCKS_PER_SEC
等于
1000000
,独立于实际分辨率。换句话说——时钟的精度如何并不重要,您的CPU运行频率也不重要。简而言之——这是一个完全无用的数字,因此是一个完全无用的函数。它仍然存在的唯一原因可能是出于历史原因。因此,请不要使用它。
为了实现您要寻找的内容,人们已经开始使用
CPU时间戳,也被称为“RDTSC”,以相应CPU指令的名称来读取它。然而,这些天这也大多是无用的,因为:
以下是翻译的结果,按照要求仅返回翻译后的内容:
- 现代操作系统可以轻松地将程序从一个CPU迁移到另一个CPU。您可以想象,在另一个CPU上运行一秒钟后读取时间戳并没有多少意义。只有在最新的Intel CPU中,计数器跨CPU核心进行同步。总的来说,这仍然是可能的,但必须采取很多额外的注意(例如,可以为进程设置关联等等)。
- 测量程序的CPU指令通常不能准确反映它实际使用的时间。这是因为在真实的程序中,可能存在一些系统调用,其中工作由操作系统内核代表进程执行。在这种情况下,该时间不包括在内。
- 还可能发生操作系统暂停进程执行的情况。即使只执行了几条指令,对用户来说也像是一秒钟。因此,这种性能测量可能是无用的。
那么应该怎么做呢?
当涉及到性能分析时,必须使用像
perf
这样的工具。它可以跟踪许多CPU时钟、缓存未命中、已经执行的分支数量、未执行的分支数量、进程从一个CPU移动到另一个CPU的次数等等。它可以作为一个工具使用,也可以嵌入到你的应用程序中(类似于
PAPI)。
如果问题是关于实际花费的时间,人们会使用挂钟。最好是高精度的,也不受NTP调整的影响(单调)。它准确地显示了经过的时间,无论发生了什么。为此,可以使用
clock_gettime()
。它是SUSv2、POSIX.1-2001标准的一部分。鉴于您使用了
getch()
来保持终端打开状态,我假设您正在使用Windows。在那里,不幸的是,您没有
clock_gettime()
,最接近的东西将是性能计数器API:
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
对于一个便携式的解决方案,最好的选择是std::chrono::high_resolution_clock()
。它在C++11中被引入,但大多数工业级编译器(GCC、Clang、MSVC)都支持它。
下面是一个如何使用它的例子。请注意,由于我知道我的CPU会比一毫秒快地执行10000次整数递增,所以我已经将其更改为微秒。我还声明了计数器为volatile
,希望编译器不会将其优化掉。
#include <ctime>
#include <chrono>
#include <iostream>
int main()
{
volatile int i = 0;
auto start = std::chrono::steady_clock::now();
while (i < 10000) {
++i;
}
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "It took me " << elapsed.count() << " microseconds." << std::endl;
}
当我编译并运行它时,它会打印出:
$ g++ -std=c++11 -Wall -o test ./test.cpp && ./test
It took me 23 microseconds.
希望能帮到你。祝好运!
start
和end
之间执行所需的时间为 0。 - Drew DormannCLOCKS_PER_SEC
的值可能会导致整数除法问题 - 将double diffms=(diffticks)/(CLOCKS_PER_SEC/1000)
更改为double diffms=diffticks/(CLOCKS_PER_SEC/1000.0)
。 - Paul R