我想问问你们中的任何人是否熟悉这个功能,如下所示。我想将其移植到Windows平台,但一直失败。我只能通过使用时间而不是时间规范来获得微秒精度。最后,会出现错误:除以零和访问违规异常
unsigned long get_usecs(struct timeval *myts)
{
if (clock_gettime(myts))
terminal_error("clock_gettime");
return (myts->tv_sec * 1000000 + myts->tv_usec);
}
void burn_loops(unsigned long loops)
{
unsigned long i;
/*
* We need some magic here to prevent the compiler from optimising
* this loop away. Otherwise trying to emulate a fixed cpu load
* with this loop will not work.
*/
for (i = 0; i < loops; i++)
_ReadWriteBarrier();
}
void calibrate_loop()
{
unsigned long long start_time, loops_per_msec, run_time = 0;
unsigned long loops;
struct timeval myts;
loops_per_msec = 100000;
redo:
/* Calibrate to within 1% accuracy */
while (run_time > 1010000 || run_time < 990000) {
loops = loops_per_msec;
start_time = get_usecs(&myts);
burn_loops(loops);
run_time = get_usecs(&myts) - start_time;
loops_per_msec = (1000000 * loops_per_msec / run_time ? run_time : loops_per_msec );
}
/* Rechecking after a pause increases reproducibility */
Sleep(1 * 1000);
loops = loops_per_msec;
start_time = get_usecs(&myts);
burn_loops(loops);
run_time = get_usecs(&myts) - start_time;
/* Tolerate 5% difference on checking */
if (run_time > 1050000 || run_time < 950000)
goto redo;
loops_per_ms = loops_per_msec;
}
我知道的唯一clock_gettime()
函数是 POSIX 指定的函数,该函数的签名与您正在使用的函数不同。 它确实提供纳秒分辨率(尽管它不太可能提供单纳秒精度)。 但是,据我所知,它在Windows上不可用。 Microsoft获取纳秒级时差的答案是使用其专有的"查询性能计数器"(QPC) API。 但是,请暂时将其放在一边,因为我怀疑时钟分辨率不是您的真正问题。
假设您的 get_usecs()
函数成功检索具有微秒分辨率和至少(大约)毫秒精度的时钟时间,这似乎是预期的,您的代码看起来有点奇特。 特别是这个任务...
loops_per_msec = (1000000 * loops_per_msec / run_time
? run_time
: loops_per_msec );
。看起来很不对劲,当格式强调运算符优先级时会更明显,如上所述(*
和/
的优先级高于?:
)。 如果您没有得到可测量的正运行时间,它会给你除以零,否则它总是会给你相同的loops_per_msec
值,或者run_time
,后者甚至没有正确的单位。
我怀疑意图更像这样......
loops_per_msec = ((1000000 * loops_per_msec)
/ (run_time ? run_time : loops_per_msec));
...,但这仍然有一个问题:如果 1000000 个循环不足以消耗至少一微秒(如测量值),那么你将陷入无限循环,loops_per_msec
反复设置为 1000000。
这将不太容易受到该特定问题的影响......
loops_per_msec = ((1000000 * loops_per_msec) / (run_time ? run_time : 1));
。这对我来说也更有意义,因为如果测量的运行时间为 0 微秒,那么 1 微秒是比任何其他可能值更好的非零近似值。 请注意,当测量的运行时间为零微秒时,这将非常迅速地扩展您的loops_per_msec
(一百万倍)。 你不能在不溢出的情况下做很多次,即使unsigned long long
结果是 128 位,如果你得到溢出,那么你将进入无限循环。 另一方面,如果发生溢出,则它表示您尝试估计的loops_per_msec
的正确值大得离谱。
这让我得出了我的结论:我怀疑你真正的问题是你的时序计算是错误的或无效的,要么是因为get_usecs()
工作不正常,要么是因为burn_loops()
的主体被优化了(尽管你努力避免这种情况)。 您的时间测量不需要亚微秒精度。 事实上,你甚至不需要比毫秒更好的精度,只要你的burn_loop()
确实与其参数的值成正比。