最快的定时分辨率系统

Pon*_*oni 9 c c++ windows time

C/C++程序员可以使用的最快的计时系统是什么?

例如:
time()将给出自1970年1月1日00:00以来的秒数.
Windows上的GetTickCount()将给出自系统启动时间以来的时间(以毫秒为单位),但限制为49.7天(此后它将简单地回零).

我想获得当前时间,或者从系统/应用程序启动时间开始计时,以毫秒为单位.

最大的问题是方法的开销 - 我需要最轻的一个,因为我每秒钟要打多次.

我的情况是我有一个工作线程,对于那个工作线程我发布了待处理的工作.每个工作都有一个"执行时间".因此,我不关心时间是当前的"实际"时间还是系统正常运行时间以来的时间 - 它必须是线性的和轻的.

编辑:

unsigned __int64 GetTickCountEx()
{
    static DWORD dwWraps = 0;
    static DWORD dwLast = 0;

    DWORD dwCurrent = 0;

    timeMutex.lock();

    dwCurrent = GetTickCount();
    if(dwLast > dwCurrent)
        dwWraps++;

    dwLast = dwCurrent;

    unsigned __int64 timeResult = ((unsigned __int64)0xFFFFFFFF * dwWraps) + dwCurrent;

    timeMutex.unlock();

    return timeResult;
}
Run Code Online (Sandbox Code Playgroud)

por*_*ges 15

对于计时,目前的Microsoft建议是使用QueryPerformanceCounter&QueryPerformanceFrequency.

这将为您提供优于毫秒的时序.如果系统不支持高分辨率计时器,则默认为毫秒(与之相同GetTickCount).

这是一篇简短的微软文章,里面有你应该使用它的例子 :)


res*_*eso 5

我最近有这个问题并做了一些研究.好消息是所有三个主要操作系统都提供某种高分辨率计时器.坏消息是它是每个系统上不同的API调用.对于POSIX操作系统,您希望使用clock_gettime().但是,如果您使用的是Mac OS X,则不支持此操作,您必须使用mach_get_time().对于Windows,请使用QueryPerformanceCounter.或者,对于支持OpenMP的编译器,您可以使用omp_get_wtime(),但它可能无法提供您正在寻找的分辨率.

我还发现fftw.org(www.fftw.org/cycle.h)中的cycle.h非常有用.

下面是一些使用一些丑陋的#ifdef语句在每个操作系统上调用计时器的代码.用法很简单:定时器t; t.tic(); SomeOperation(); t.toc( "消息"); 它将以秒为单位打印出已用时间.

#ifndef TIMER_H
#define TIMER_H

#include <iostream>
#include <string>
#include <vector>

# if  (defined(__MACH__) && defined(__APPLE__))
#   define _MAC
# elif (defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(_WIN64))
#   define _WINDOWS
#   ifndef WIN32_LEAN_AND_MEAN
#     define WIN32_LEAN_AND_MEAN
#   endif
#endif

# if defined(_MAC)
#    include <mach/mach_time.h>
# elif defined(_WINDOWS)
#    include <windows.h>
# else
#    include <time.h>
# endif


#if defined(_MAC)
  typedef uint64_t timer_t;
  typedef double   timer_c;

#elif defined(_WINDOWS)
  typedef LONGLONG      timer_t;
  typedef LARGE_INTEGER timer_c;

#else
  typedef double   timer_t;
  typedef timespec timer_c;
#endif

  //==============================================================================
  // Timer
  // A quick class to do benchmarking.
  // Example: Timer t;  t.tic();  SomeSlowOp(); t.toc("Some Message");

  class Timer {
  public:
    Timer();

    inline void tic();
    inline void toc();
    inline void toc(const std::string &msg);

    void print(const std::string &msg);
    void print();
    void reset();
    double getTime();

  private:
    timer_t start;
    double duration;
    timer_c ts;
    double conv_factor;
    double elapsed_time;
  };



  Timer::Timer() {

#if defined(_MAC)
    mach_timebase_info_data_t info;
    mach_timebase_info(&info);

    conv_factor = (static_cast<double>(info.numer))/
                  (static_cast<double>(info.denom));
    conv_factor = conv_factor*1.0e-9;

#elif defined(_WINDOWS)
    timer_c freq;
    QueryPerformanceFrequency(&freq);
    conv_factor = 1.0/(static_cast<double>freq.QuadPart);

#else
    conv_factor = 1.0;
#endif

    reset();
  }

  inline void Timer::tic() {

#if defined(_MAC)
    start = mach_absolute_time();

#elif defined(_WINDOWS)
    QueryPerformanceCounter(&ts);
    start = ts.QuadPart;

#else
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
    start = static_cast<double>(ts.tv_sec) + 1.0e-9 *
            static_cast<double>(ts.tv_nsec);

#endif
  }

  inline void Timer::toc() {
#if defined(_MAC)
    duration =  static_cast<double>(mach_absolute_time() - start);

#elif defined(_WINDOWS)
    QueryPerformanceCounter(&qpc_t);
    duration = static_cast<double>(qpc_t.QuadPart - start);

#else
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
    duration = (static_cast<double>(ts.tv_sec) + 1.0e-9 *
                static_cast<double>(ts.tv_nsec)) - start;

#endif

    elapsed_time = duration*conv_factor;
  }

  inline void Timer::toc(const std::string &msg) { toc(); print(msg); };

  void Timer::print(const std::string &msg) {
    std::cout << msg << " "; print();
  }

  void Timer::print() {
    if(elapsed_time) {
      std::cout << "elapsed time: " << elapsed_time << " seconds\n";
    }
  }

  void Timer::reset() { start = 0; duration = 0; elapsed_time = 0; }
  double Timer::getTime() { return elapsed_time; }


#if defined(_WINDOWS)
# undef WIN32_LEAN_AND_MEAN
#endif

#endif // TIMER_H
Run Code Online (Sandbox Code Playgroud)


Arn*_*rno 5

GetSystemTimeAsFileTime是最快的资源。其粒度可以通过调用填充lpTimeIncrement的GetSystemTimeAdjustment来获得。作为文件时间的系统时间以 100ns 为单位,并按TimeIncrement递增。 TimeIncrement可能会有所不同,并且取决于多媒体计时器接口的设置。

对timeGetDevCaps 的调用将公开时间服务的功能。它返回一个值wPeriodMin,表示支持的最小中断周期。以wPeriodMin作为参数调用timeBeginPeriod会将系统设置为以尽可能高的中断频率(通常约为 1ms)运行。这也会迫使返回的系统文件时间的时间增量变小。其粒度将在 1ms(10000 100ns 单位)范围内。GetSystemTimeAsFileTime

出于您的目的,我建议采用这种方法。

QueryPerformanceCounter 的选择是有问题的,因为它的频率通过两种方式并不准确:首先,它与QueryPerformanceFrequency给出的值存在硬件特定偏移量的偏差。该偏移很容易达到几百 ppm,这意味着转换成时间将包含每秒几百微秒的误差。其次它有热漂移。此类设备的漂移很容易达到几个 ppm。这样就添加了另一个 - 热依赖 - 几个 us/s 的误差。

因此,只要 ~1ms 的分辨率就足够了,并且主要问题是开销, GetSystemTimeAsFileTime这就是迄今为止最好的解决方案。

当微秒很重要时,您就必须走得更远,才能看到更多细节。Windows 时间戳项目描述了亚毫秒时间服务