我使用gettimeofday()连续打印微秒。如程序输出中所示,您可以看到时间不是更新的微秒间隔,而是某些样本的重复时间,然后增量不是以微秒为单位,而是以毫秒为单位。
while(1)
{
gettimeofday(&capture_time, NULL);
printf(".%ld\n", capture_time.tv_usec);
}
节目输出:
.414719
.414719
.414719
.414719
.430344
.430344
.430344
.430344
e.t.c
我希望输出顺序递增,如
.414719
.414720
.414721
.414722
.414723
或
.414723, .414723+x, .414723+2x, .414723 +3x + ...+ .414723+nx
当我从capture_time.tv_usec获取它时,似乎没有刷新微秒。
================================= //完整计划
#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
#endif
struct timezone
{
int tz_minuteswest; /* minutes W of Greenwich */
int tz_dsttime; /* type of dst correction */
};
timeval capture_time; // structure
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
unsigned __int64 tmpres = 0;
static int tzflag;
if (NULL != tv)
{
GetSystemTimeAsFileTime(&ft);
tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
/*converting file time to unix epoch*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
tmpres /= 10; /*convert into microseconds*/
tv->tv_sec = (long)(tmpres / 1000000UL);
tv->tv_usec = (long)(tmpres % 1000000UL);
}
if (NULL != tz)
{
if (!tzflag)
{
_tzset();
tzflag++;
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}
return 0;
}
int main()
{
while(1)
{
gettimeofday(&capture_time, NULL);
printf(".%ld\n", capture_time.tv_usec);// JUST PRINTING MICROSECONDS
}
}
答案 0 :(得分:7)
您观察到的时间变化为0.414719 s至0.430344 s。差异是15.615毫秒。数字表示为微秒的事实不意味着它增加1微秒。事实上,我预计会有15.625毫秒。这是标准硬件上的系统时间增量。我仔细研究了here和here。 这称为系统时间的粒度。
<强>窗:强>
但是,有一种方法可以改善这种情况,这是一种减少粒度的方法:Multimedia Timers。特别是Obtaining and Setting Timer Resolution将公开一种增加系统中断频率的方法。
代码:
#define TARGET_PERIOD 1 // 1-millisecond target interrupt period
TIMECAPS tc;
UINT wTimerRes;
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
// this call queries the systems timer hardware capabilities
// it returns the wPeriodMin and wPeriodMax with the TIMECAPS structure
{
// Error; application can't continue.
}
// finding the minimum possible interrupt period:
wTimerRes = min(max(tc.wPeriodMin, TARGET_PERIOD ), tc.wPeriodMax);
// and setting the minimum period:
timeBeginPeriod(wTimerRes);
这将强制系统以其最大中断频率运行。作为结果
系统时间的更新也会更频繁地发生,大多数系统的系统时间增量的粒度将为close to 1 milisecond
。
当您需要超出此范围的分辨率/粒度时,您必须查看QueryPerformanceCounter。但是在长时间使用时要小心使用。可以通过调用QueryPerformanceFrequency来获得此计数器的频率。操作系统将此频率视为常量,并始终给出相同的值。但是,某些硬件会产生此频率,而真实频率与给定值不同。它有一个偏移,它显示出热漂移。因此,误差应假定在几微秒至几微秒的范围内。有关这方面的更多详细信息,请参见上面的第二个“此处”链接。
<强> Linux的:强>
Linux的情况有所不同。请参阅this以了解相关信息。 Linux的 使用函数getnstimeofday使用函数timekeeping_get_ns(自纪元以来的秒数)和来自高频率计数器(微秒)的信息混合CMOS时钟的信息。这不是微不足道的,并且在准确性方面存在问题,因为两个源都有不同的硬件支持。这两个源不是锁相的,因此可以更多/更少,而不是每秒一百万微秒。
答案 1 :(得分:1)
Windows系统时钟每隔几毫秒才会打勾 - 在您的情况下每秒64次,所以当它打勾时,系统时间会增加15.625毫秒。
解决方案是使用更高分辨率的计时器,即系统时间(QueryPerformanceCounter
)。
你仍然不会看到.414723,.414723 + x,.414723 + 2x,.414723 + 3x + ... + .414723 + nx,因为你的代码每次{{1微秒。它会尽可能快地运行,但没有特别的理由应该始终是一个恒定的速度,或者如果它是一个整数微秒。
答案 2 :(得分:1)
我建议你查看C ++ 11 <chrono>
标题。
high_resolution_clock
(C ++ 11)具有最短滴答时间的时钟
此处提到的节拍周期是时钟更新的频率。如果我们查看more details:
template< class Rep, class Period = std::ratio<1> > class duration;
类模板
std::chrono::duration
表示时间间隔。它包含Rep类型的刻度计数和刻度周期,其中刻度周期是编译时有理常数,表示从一个刻度到下一个刻度的秒数。
以前,像gettimeofday
这样的函数会给你一个以微秒表示的时间,但是他们完全没有告诉你这个时间表达式被刷新的时间间隔。
在C ++ 11标准中,此信息现在已经明确,显而易见的是,表达时间的单位与刻度周期之间没有关系。因此,您肯定需要将两者都考虑在内。
当您想要测量接近它的持续时间时, tick 期间非常重要。如果你想测量的持续时间低于滴答期,那么你将像你观察到的那样“离散地”测量它:0,0,0,1,0,0,0,1,0,0,0,1, ......我建议在这一点上谨慎。
答案 3 :(得分:0)
这是因为运行代码的进程并不总是安排执行。
虽然它确实如此,它会快速绕过循环,每微秒打印多个值 - 这是现代CPU上相对较长的一段时间。
有些时间段没有安排系统执行,因此无法打印值。
如果您要执行的操作是每微秒执行一次,则可以使用在高性能硬件上运行的某些实时操作系统。