English 中文(简体)
C++ 窗口时间
原标题:C++ windows time
  • 时间:2009-09-30 12:03:57
  •  标签:

I have a problem in using time. I want to use and get microseconds on windows using C++.

我无法找到办法。

问题回答

The “canonical” questionnaire was given by unwind/strong>:

一种受欢迎的方式是使用QueryPerformanceCounter()电话。

然而,这种方法存在的问题很少:

  1. it s intended for measurement of time intervals, not time. This means you have to write code to establish "epoch time" from which you will measure precise intervals. This is called calibration.
  2. As you calibrate your clock, you also need to periodically adjust it so it s never too much out of sync (this is called drift) with your system clock.
  3. QueryPerformanceCounter is not implemented in user space; this means context switch is needed to call kernel side of implementation, and that is relatively expensive (around 0.7 microsecond). This seems to be required to support legacy hardware.

但并非全部损失。 第1点和第2点是你可以做的编码范围,3点可以直接打电话给RDTSC(可通过<代码>__rdtsc(<> 固有”),只要你知道CPU24的准确频率的话。 虽然在旧的CPU上,这种呼吁可能会受到内部锁定速度的改变,但在所有新的英特尔公司和AMD CPU中,这种呼吁得到保证,能够取得相当准确的结果,并受到CPU锁(例如电力储蓄特征)的改变的影响。

让我们从1开始。 这里的数据结构是掌握校准数据:

struct init
{
  long long stamp; // last adjustment time
  long long epoch; // last sync time as FILETIME
  long long start; // counter ticks to match epoch
  long long freq;  // counter frequency (ticks per 10ms)

  void sync(int sleep);
};

init                  data_[2] = {};
const init* volatile  init_ = &data_[0];

这里是初步校准守则;必须给它时间(流利器)以等待24小时搬迁;我发现,500毫秒(时间越短,精确的校准)。 为了便于使用,我们将使用<代码>。 证书/编码等。 仅需要将其称作<条码>数据_[0],因为<条码>数据_[...]/条码>将通过定期24小时调整加以更新(见下文)。

void init::sync(int sleep)
{
  LARGE_INTEGER t1, t2, p1, p2, r1, r2, f;
  int cpu[4] = {};

  // prepare for rdtsc calibration - affinity and priority
  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
  SetThreadAffinityMask(GetCurrentThread(), 2);
  Sleep(10);

  // frequency for time measurement during calibration
  QueryPerformanceFrequency(&f);

  // for explanation why RDTSC is safe on modern CPUs, look for "Constant TSC" and "Invariant TSC" in
  // Intel(R) 64 and IA-32 Architectures Software Developer’s Manual (document 253668.pdf)

  __cpuid(cpu, 0); // flush CPU pipeline
  r1.QuadPart = __rdtsc();
  __cpuid(cpu, 0);
  QueryPerformanceCounter(&p1);

  // sleep some time, doesn t matter it s not accurate.
  Sleep(sleep);

  // wait for the system clock to move, so we have exact epoch
  GetSystemTimeAsFileTime((FILETIME*) (&t1.u));
  do
  {
    Sleep(0);
    GetSystemTimeAsFileTime((FILETIME*) (&t2.u));
    __cpuid(cpu, 0); // flush CPU pipeline
    r2.QuadPart = __rdtsc();
  } while(t2.QuadPart == t1.QuadPart);

  // measure how much time has passed exactly, using more expensive QPC
  __cpuid(cpu, 0);
  QueryPerformanceCounter(&p2);

  stamp = t2.QuadPart;
  epoch = t2.QuadPart;
  start = r2.QuadPart;

  // calculate counter ticks per 10ms
  freq = f.QuadPart * (r2.QuadPart-r1.QuadPart) / 100 / (p2.QuadPart-p1.QuadPart);

  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  SetThreadAffinityMask(GetCurrentThread(), 0xFF);
}

有了良好的校准数据,你可以计算低廉的低温和反应能力的确切时间(我对电传和计算进行了测量,在我的机器上为大约25纳米秒)。 值得注意的是:

  1. 返回类型是符合国际自由职业和专业技能评估体系结构的双轨,与<代码”不同,准确到100人。 GetSystemtimeAsFiletime(在1030天或10 000天以上或1毫秒之间加薪)。

  2. 为了避免将昂贵的重新分类为两倍于累犯,整个计算是在64个轨道分类账中进行的。 尽管这些数字可能很多,但确实存在着造成分类过度流动的风险,因此,必须定期提交<条码>><>启动/代码>,以避免出现这种情况。 这样做是为了进行24小时调整。

  3. 我们正在提供校准数据的副本,因为在我们的呼吁中,可以通过在另一条路面进行锁定调整来加以更新。

在这里,该守则将非常精确地阅读目前的时间。 回归价值是与国际自由职业观察所兼容的双倍,即自1 1601年1月以来100-nanosecond的间隔。

long long now()
{
  // must make a copy
  const init* it = init_;
  // __cpuid(cpu, 0) - no need to flush CPU pipeline here
  const long long p = __rdtsc();
  // time passed from epoch in counter ticks
  long long d = (p - it->start);
  if (d > 0x80000000000ll)
  {
    // closing to integer overflow, must adjust now
    adjust();
  }
  // convert 10ms to 100ns periods
  d *= 100000ll;
  d /= it->freq;
  // and add to epoch, so we have proper FILETIME
  d += it->epoch;
  return d;
}

为了进行24小时调整,我们需要抓住确切的时间(按系统锁定)并将时间与我们24小时进行比较;这将给我们带来流动价值。 其次,我们采用简单的公式计算“调整后的”通用报告格式频率,以便在下一次调整时锁定我们的锁定会。 因此,必须定期进行调整;我发现,每次15分钟,调整工作都很好。 我使用<代码>Createtimer Queuetimer,在计划启动时,一度要求安排调整电话(此处没有说明)。

掌握准确的系统时间(用于计算漂流)的轻微问题是,我们需要等到这个系统24小时才能移动,这可能需要30毫米秒左右(long)。 如不进行调整,则有可能在职能<代码>now(<>>>/代码>内进行批发,更不用提从系统锁上未经校正的流出。 在<代码>now()中,防止超支,但我们确实不想在错误时刻用“now(<<><><>>>>/code”号”的透镜中 trigger。

这里是定期24小时调整的代码,24小时流放载于r->epoch - r->stamp:

void adjust()
{
  // must make a copy
  const init* it = init_;
  init* r = (init_ == &data_[0] ? &data_[1] : &data_[0]);
  LARGE_INTEGER t1, t2;

  // wait for the system clock to move, so we have exact time to compare against
  GetSystemTimeAsFileTime((FILETIME*) (&t1.u));
  long long p = 0;
  int cpu[4] = {};
  do
  {
    Sleep(0);
    GetSystemTimeAsFileTime((FILETIME*) (&t2.u));
    __cpuid(cpu, 0); // flush CPU pipeline
    p = __rdtsc();
  } while (t2.QuadPart == t1.QuadPart);

  long long d = (p - it->start);
  // convert 10ms to 100ns periods
  d *= 100000ll;
  d /= it->freq;

  r->start = p;
  r->epoch = d + it->epoch;
  r->stamp = t2.QuadPart;

  const long long dt1 = t2.QuadPart - it->epoch;
  const long long dt2 = t2.QuadPart - it->stamp;
  const double s1 = (double) d / dt1;
  const double s2 = (double) d / dt2;

  r->freq = (long long) (it->freq * (s1 + s2 - 1) + 0.5);

  InterlockedExchangePointer((volatile PVOID*) &init_, r);

  // if you have log output, here is good point to log calibration results
}

最后,两个公用事业职能。 一种做法是将国际电算和测算系统(包括从<代码>now(<>>>>>>>/代码>)转换成SYSTEMT,同时将微型秒转换成单独的<代码>int。 另一些则将返回频率,因此贵方案可直接使用<代码>_rdtsc(>,以便准确测量时间间隔(精确度为纳米秒)。

void convert(SYSTEMTIME& s, int &us, long long f)
{
  LARGE_INTEGER i;
  i.QuadPart = f;
  FileTimeToSystemTime((FILETIME*) (&i.u), &s);
  s.wMilliseconds = 0;
  LARGE_INTEGER t;
  SystemTimeToFileTime(&s, (FILETIME*) (&t.u));
  us = (int) (i.QuadPart - t.QuadPart)/10;
}

long long frequency()
{
  // must make a copy
  const init* it = init_;
  return it->freq * 100;
}

当然,上述内容中没有一个比你的系统锁更准确,这不可能比几百毫秒。 上文实施的precise clock(而不是accurate)的目的是提供可用于的单一措施:

  1. cheap and very accurate measurement of time intervals (not wall time),
  2. much less accurate, but monotonous and consistent with the above, measure of wall time

我认为,它做得很好。 例使用是标志,其中人们不仅可以使用时间序列来确定事件的时间,而且还可以说明内部方案的时间、相对性(微观轨道)等原因。

我将管道(用于初步校准、时间安排调整)作为硬体读物者的一种做法。

你们可以使用提高日期的图书馆。

You can use boost::posix_time::hours, boost::posix_time::minutes, boost::posix_time::seconds, boost::posix_time::millisec, boost::posix_time::nanosec

一种受欢迎的方式是使用<代码>。 QueryPerformanceCounter(> calls。 如果你需要高精度的时间,例如只按摩擦顺序衡量期限,那是有用的。 我认为,通过<条码>RDTSC的机器指示实施。

可能会出现一些问题,例如,相对频率与节能不同,以及多个核心之间的同步。 关于这些问题的详情,见上文Wikipedia链接。

可帮助:

NTSTATUS WINAPI NtQuerySystemTime(__out  PLARGE_INTEGER SystemTime);

系统时间——接收系统时间的LARGE-INTEERT结构的协调人。 这是自1月1日1 1601(UTC)以来100-nanosecond的64倍值。





相关问题