【问题标题】:Accuracy of clock() function in CC中clock()函数的准确性
【发布时间】:2017-02-17 13:11:30
【问题描述】:

我有一些代码试图确定代码块的执行时间。

#include <time.h>
#include <stdio.h>

int main()
{
   clock_t start_t, end_t, total_t;
   int i;

   start_t = clock(); //clock start
   printf("Starting of the program, start_t = %ld\n", start_t);

   printf("Going to scan a big loop, start_t = %ld\n", start_t);
   for(i=0; i< 10000000; i++)  //trying to determine execution time of this block
   {
   }
   end_t = clock(); //clock stopped
   printf("End of the big loop, end_t = %ld\n", end_t);

   total_t = (long int)(end_t - start_t);
   printf("Total time taken by CPU: %lu\n", total_t  );

   return(0);
}

代码sn-p在我机器上的输出是

Starting of the program, start_t = 8965
Going to scan a big loop, start_t = 8965
End of the big loop, end_t = 27259
Total time taken by CPU: 18294

因此,如果我的 CPU 以 21 MHz 运行并假设这是唯一要执行的事情,则每个机器周期大约等于 47 纳秒,因此 (18294 * 47) = 859818 纳秒。

这是我代码中 for 循环的执行时间吗?我在这里做了一些不正确的假设吗?

【问题讨论】:

  • 要获得以秒为单位的时间,您应该除以数字,例如total_t 在你的情况下,CLOCKS_PER_SEC。请注意,您需要将 total_t 转换为浮点值才能使其工作。
  • 对您的命名方案也有一点吹毛求疵:以后缀 _t 结尾的符号通常用于类型别名(使用 typdef 创建)。例如size_ttime_t 甚至clock_t
  • @JoachimPileborg 我查看了 clock() 函数的文档,CLOCK_PER_SEC 将返回精确到 1/100 秒的时间,我正在寻找高达 10 微秒的分辨率,因此我使用了上述方法。另外我希望它可以在不同的平台和架构上工作,所以我认为只计算差异然后将其与时钟速度相乘会是一个更好的选择,因为 CLOCKS_PER_SEC 会随架构而变化。
  • CLOCKS_PER_SEC 在不同平台上不同的原因是因为“ticks”是平台相关的。它不仅取决于硬件,还取决于操作系统。您必须在操作系统文档中找到分辨率和精度。可靠且可移植获得秒数的唯一方法是将(浮点)差除以CLOCKS_PER_SEC。否则,这些数字本身毫无意义。
  • 您无法真正更改clock 函数或其内部工作方式。但根据操作系统的不同,可能会有更高分辨率的计时器可用。如果你在一个只有最小操作系统的嵌入式系统上,那么硬件可能有你可以使用的计时器。

标签: c time clock system-clock


【解决方案1】:

clock 函数使用的时间单位是任意的。在大多数平台上,它与处理器速度无关。它通常与外部定时器中断的频率有关——它可以在软件中配置——或者与经过多年处理器发展而保持的兼容性的历史值有关。您需要使用宏CLOCKS_PER_SEC 转换为实时。

printf("Total time taken by CPU: %fs\n", (double)total_t / CLOCKS_PER_SEC);

C 标准库被设计为可在各种硬件上实现,包括没有内部计时器并依靠外部外围设备来显示时间的处理器。许多平台有比time 更精确的挂钟时间测量方法和比clock 更精确的CPU 消耗测量方法。例如,在 POSIX 系统(例如 Linux 和其他类 Unix 系统)上,您可以使用 getrusage,它具有微秒精度。

struct timeval start, end;
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
start = usage.ru_utime;
…
getrusage(RUSAGE_SELF, &usage);
end = usage.ru_utime;
printf("Total time taken by CPU: %fs\n", (double)(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec) / 1e-6);

如果可用,clock_gettime(CLOCK_THREAD_CPUTIME_ID)clock_gettime(CLOCK_PROCESS_CPUTIME_ID) 可能会提供更好的精度。它具有纳秒级精度。

请注意精度和准确度之间的区别:精度是报告值的单位。准确度是报告值与实际值的接近程度。除非您正在处理 real-time system,否则无法保证一段代码需要多长时间,包括调用测量函数本身。

一些处理器有 cycle 时钟来计算处理器周期而不是挂钟时间,但这变得非常特定于系统。

在进行基准测试时,请注意,您要测量的是在这些特定情况下此特定 CPU 上此特定可执行文件的执行情况,并且结果可能会或可能不会推广到其他情况。例如,除非您关闭优化,否则大多数编译器都会优化您问题中的空循环。测量未优化代码的速度通常是没有意义的。即使您在循环中添加实际工作,也要小心玩具基准:它们通常不具有与实际代码相同的性能特征。在 PC 和智能手机等现代高端 CPU 上,CPU 密集型代码的基准测试通常对缓存效果非常敏感,其结果可能取决于系统上运行的其他内容、确切的 CPU 型号(由于不同的缓存大小和布局)、代码恰好加载的地址等。

【讨论】:

  • @Giles 这正是我所需要的。与分辨率为 100 ms 的时钟功能相比,它的分辨率高达 1 us。但是您知道此代码是否可移植。我需要它在 ARM M0 系统上运行。有没有办法让这段代码可移植?
  • @user2808264 如果您需要clock 以外的东西,那么它就不会那么便携,您将创建对操作系统或CPU 或两者的依赖关系。检查您的操作系统提供了什么。如果您在裸机上运行,​​如果您想要接近 1µs 的精度,那么您将需要一个周期精确的计数器,检查您的 CPU 上存在哪些调试功能(我认为这是一个可选功能)。如果您不需要那么高的准确性,那么您可以使用systick timer,它是可选的,但很普遍。
猜你喜欢
  • 2021-04-15
  • 2019-10-17
  • 2013-03-27
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2023-01-13
  • 2011-06-25
  • 2021-04-03
相关资源
最近更新 更多