C++ 中的 clock() 是否与重 CPU 负载一致

Is clock() in c++ consistent with heavy CPU loads

现在我基本上有一个程序,它使用时钟来测试我的程序执行某些操作所花费的时间,通常它精确到几毫秒。我的问题是:如果 CPU 负载很重,我还会得到相同的结果吗?

时钟是否仅在 CPU 在我的进程上工作时计算?

让我们假设:多核 CPU 但进程不利用多线程

CPU 中有共享组件,例如末级缓存、执行单元(在一个内核中的硬件线程之间),因此在重负载下您会出现抖动,因为即使您的应用程序执行的数量完全相同的指令,每条指令可能需要更多的周期(等待内存,因为数据被从缓存中逐出,可用的执行单元),更多的周期意味着更多的执行时间(假设 Turbo Boost 不会补偿)。

如果您追求精密仪器,请查看hardware counters

考虑物理 CPU 上可用内核数量、超线程和其他 BIOS 设置(如 Intel CPU 上的 Turbo Boost)以及使用的线程技术等因素也很重要在查看 CPU 密集型任务的时间指标时进行编码。

OpenMP 这样的并行化工具提供了内置函数来计算计算和像 omp_get_wtime( ); 这样的挂钟时间,在使用这种类型的程序中,它们通常比 clock() 更准确并行化。

除了同意指示时间取决于许多因素的响应之外,我想提请您注意自 C++11 以来可用的 std::chrono 库:

#include <chrono>
#include <iostream>

int main() {
      auto beg = std::chrono::high_resolution_clock::now();
      std::cout << "*** Displaying Some Stuff ***" << std::endl;
      auto end = std::chrono::high_resolution_clock::now();
      auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end - beg);
      std::cout << "Elapsed: " << dur.count() << " microseconds" << std::endl;
    }

根据标准,此程序将使用您的系统提供的最高精度时钟,并将以微秒分辨率滴答(还有其他分辨率可用;see the docs)。

样本运行:

$ g++ example.cpp -std=c++14 -Wall -Wextra -O3
$ ./a.out
*** Displaying Some Stuff ***
Elapsed: 29 microseconds

虽然它比依赖 C 风格 std::clock() 冗长得多,但我觉得它给了你更多的表现力,你可以隐藏一个漂亮的界面背后的冗长(例如, 在这里我使用 std::chrono 来构建一个函数定时器)。

clock的功能依赖于OS。在 windows 中,从一个遥远的决定中,clock 给出了经过的时间,在大多数其他 OS 中(当然 Linux,MacOS 和其他 Unix -相关OS)。

根据您实际想要实现的目标,经过的时间或 CPU 时间可能是您想要衡量的。

在有其他进程 运行ning 的系统中,运行时间和 CPU 使用率之间的差异可能很大(当然,如果您的 CPU 不忙运行正在启动您的应用程序,例如等待网络数据包通过线路传输或从硬盘传输文件数据),然后其他应用程序的运行时间为 "avialable"。

当同一系统中有其他进程 运行ning 时,也存在大量错误 factors/interference 因素:

  • 如果我们假设您的 OS 支持 clock 作为 CPU 时间的度量,这里的精度并不总是那么好 - 例如,它很可能是根据 CPU-timer ticks 来计算的,例如,如果它正在做 I/O,那么你的进程可能不会 运行 对于 "full tick"。

  • 其他进程可能使用"your"cpu进行部分中断处理,在OS切换到"account for this as interrupt time"之前,处理时网络或硬盘上的数据包 i/o 占一定百分比的时间 [通常不是很大,但在非常繁忙的系统中,它可能占总时间的百分之几],如果其他进程 运行 在 "your" cpu 上,在 "your time" 上计算另一个进程加载其数据后使用 "your" 进程数据重新加载缓存的时间。这种 "interference" 很可能会影响您的测量 - 多少取决于系统中正在发生的 "what else"。

  • 如果您的进程 [通过共享内存] 与另一个进程共享数据,那么也会(同样,通常是一分钟的量,但在极端情况下,它可能很重要)一些时间花在当您的进程无法执行时,处理您的进程和其他进程之间的 "cache-snoop requests" 。

  • 如果OS是切换任务,"half"切换to/from任务的时间会占到你的进程,其他进程占一半正在切换 in/out。同样,这通常是很小的数量,但如果您的系统非常繁忙且有很多进程切换,它可能会加起来。

  • 一些处理器类型,例如英特尔的超线程还与您的实际核心共享资源,因此该核心上只有部分时间花在您的进程中,并且您进程的缓存内容现在与其他一些进程的数据和指令共享 - 这意味着您的进程可能会得到"evicted" 来自同一 CPU 核心上的另一个线程 运行 的缓存。

  • 同样,多核 CPU 通常有一个共享的 L3 缓存 在 CPU.

  • 的其他核心上受到其他进程 运行ning 的影响
  • 文件缓存和其他 "system caches" 也会受到其他进程的影响 - 所以如果您的进程正在读取某些文件,而其他进程也访问文件,缓存内容将 "less yours" 比系统不那么忙时的内容。

为了准确测量您的进程使用了​​多少系统资源,您需要处理器性能计数器(和可重现的测试用例,因为您可能需要多次 运行 相同的设置以确保你得到 "right" 性能计数器组合)。当然,这些计数器中的大多数也是系统范围的,并且中断和其他随机干扰中的某些处理会影响测量,因此如果您没有许多其他(繁忙的)进程,则最准确的结果将是运行宁在系统中。

当然,在许多情况下,仅测量应用程序的总时间就足够了。同样,只要您有一个可重现的测试用例,它在特定场景中每次 运行 时都给出相同(或至少相似)的时间。

每个应用不同,每个系统不同。绩效衡量是一个庞大的主题,很难面面俱到 - 当然,我们不会在这里回答有关 "how do I get my PI-with-a-million-decimals to run faster when there are other processes running in the same system" 或其他任何问题的极其具体的问题。