C语言中clock()函数的准确性

10

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

#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);
}

我的机器上运行这段代码的输出结果是:
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 强制转换为浮点值才能正常工作。 - Some programmer dude
1
此外还有一个小细节需要指出,以 _t 后缀结尾的符号通常用于类型别名(通过 typedef 创建)。例如 size_ttime_t 甚至是 clock_t - Some programmer dude
2
CLOCKS_PER_SEC 在不同平台上不同的原因是因为“滴答声”是平台相关的。它不仅取决于硬件,还取决于操作系统。分辨率和精度是您必须在操作系统文档中找到的内容。可靠且可移植获取秒数的唯一方法是将(浮点)差异除以 CLOCKS_PER_SEC。否则这些数字本身就没有太多意义。 - Some programmer dude
@JoachimPileborg非常有用。 有没有办法将分辨率提高到10微秒的级别?也许使用一组精度更高的替代函数? - user2808264
1
你实际上不能改变 clock 函数或其内部工作方式。但是,根据操作系统,可能会有更高分辨率的计时器可用。如果你在一个只有最小操作系统的嵌入式系统上,则硬件可能有可替代使用的计时器。 - Some programmer dude
显示剩余3条评论
1个回答

9
<转译> < p > 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)可以提供更好的精度。它的精度为纳秒级别。

请注意精确度和准确度之间的区别:精确度是指报告值的单位。准确度是指报告值与真实值的接近程度。除非您正在处理实时系统,否则没有硬性保证代码执行需要多长时间,包括测量函数本身的调用。

一些处理器具有计算处理器周期而不是挂钟时间的循环时钟,但这会非常依赖于系统。

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


@Giles 这正是我所需要的。与时钟函数的100毫秒分辨率相比,它具有高达1微秒的分辨率。但是你知道这段代码是否可移植吗?我需要在ARM M0系统上运行它。有没有办法使这段代码可移植? - user2808264
如果你需要超出 clock 的功能,那么它就不太具有可移植性,你将会在操作系统或 CPU 上创建依赖。检查一下你的操作系统提供了什么。如果你正在运行裸机程序,如果你想要接近 1 微秒的精度,那么你将需要一个周期精确计数器,检查一下你的 CPU 上是否存在调试功能(我认为这是一个可选功能)。如果你不需要那么高的精度,那么你可以使用 systick 计时器,它是可选的但广泛使用的。 - Gilles 'SO- stop being evil'

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