当我输出gettimeofday()
的微秒字段时,我注意到微秒字段大于1,000,000。有人知道这是为什么吗?这是否意味着我对gettimeofday()
的解释是错误的?
为了记录在案,我的假设是根据gettimeofday()
的当前时间(以微秒为单位)如下:
struct timeval ts;
gettimeofday(&ts, NULL);
printf("%zu", ts.tv_sec * 1000000 + ts.tv_usec);
编辑:下面是导致问题的代码。在下面的注解之后,printf()可能出错了。
struct timeval curr_time;
gettimeofday(&curr_time, NULL);
printf("Done-arino! Onto the matrix multiplication (at %zu s, %03zu ms)\n", curr_time.tv_sec, curr_time.tv_usec);
// Matrix Multiplication
struct timeval start_tv, end_tv, elapsed_tv;
gettimeofday(&start_tv, NULL);
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
for (k = 0; k < N; k++)
C[i][j] += A[i][k] * B[k][j];
gettimeofday(&end_tv, NULL);
timersub(&end_tv, &start_tv, &elapsed_tv);
// Print results
printf("Elapsed time: %zu s, %03zu ms\n", elapsed_tv.tv_sec, elapsed_tv.tv_usec / 1000);
3条答案
按热度按时间8fq7wneg1#
成功到
gettimeofday
后,是的,tv_usec
保证严格小于1000000。如果你(认为你)看到了一个1000000或更大的值,那么是的,很可能你做错了什么。
一个常见的错误是天真地加减两个
struct timeval
值,而没有在tv_sec
和tv_usec
字段之间实现正确的进位或借位,这很容易导致tv_usec
中的(错误)值大于1000000。(在你编辑过的帖子中,你提到了减去时间规格,但是你使用的是系统提供的timersub
函数,它应该得到正确的借用。)如果你用
struct timespec
而不是struct timeval
,* 如果 * 一个闰秒正在进行,* 如果 * 你(奇迹般地)使用一个实现了MarkusKuhn在https://www.cl.cam.ac.uk/~mgk25/posix-clocks.html中提出的CLOCK_UTC
时钟类型的OS内核,您会看到tv_nsec
值大于100000000,但这需要很多“如果“(据我所知,没有一个广泛使用的内核实现过CLOCK_UTC
)。yyyllmsg2#
您需要展示一些更有说服力的代码,并确定遇到问题的平台。
例如:
非常繁忙的循环有点烦人;也许您应该使用
nanosleep()
在每次迭代中休眠一到两微秒:或者,包括进度表以演示代码正在运行:
一米一分一秒
在Ubuntu 16.04 LTS VM上,我可以找到包含宏的文件
/usr/include/x86_64-linux-gnu/sys/time.h
:我能看到的所有迹象都表明
tv_usec
是一个无符号量__u32
,如果是这样,那么< 0
条件永远不会为真,有时你可能会看到非常大的正值,当然是YMMV。进一步的检查表明,虽然有些头文件似乎将
__u32
用于tv_usec
,但它们不是主要的系统头文件。看到任何代码对具有该名称的成员使用无符号类型是令人担忧的,但这并不意味着使用
struct timeval
和timersub()
的代码也会发生这种情况。此代码:
编译为64位(因此
long
足够大,可以容纳tv_usec
可以定义为的任何内容)打印0 -1
。可以将tv_usec
成员初始化为0
,递减它,并验证它是否为负,以及进行各种其他相关测试。因此,问题并不像"
timersub()
是错误的"那么简单--这是一个巨大的解脱。thtygnil3#
您的
printf
可疑,可能导致此问题。%zu
用于打印size_t
值。但是tv_sec
和tv_usec
都没有size_t
类型。在现代系统中,
size_t
可能是64位,但如果tv_sec
或tv_usec
不是,printf
最终将错误地打印这些值。我把你的
printf
改成了以及
不过,这些不一定适合您--这取决于您的系统对
tv_sec
和tv_usec
的特定选择。像这样打印实现定义类型的值的通用和可移植方法是将其显式转换为最大类型,然后使用与转换到的类型对应的
printf
。例如:强制类型转换可能是也可能不是no-op,但关键是,无论原始类型是什么,最终得到的结果都符合您告诉
printf
的预期。