Windows中的C ++高精度时间测量

我感兴趣的是使用Windows中的C ++测量特定的时间点到纳秒。 这可能吗? 如果不是,至less可以在几微秒内得到具体的时间吗? 任何图书馆都应该这样做,除非我认为托pipe代码是可能的。 谢谢

如果在多核计算机上运行线程应用程序,则QueryPerformanceCounter可以(并将)根据执行代码的内核返回不同的值。 看到这个 MSDN文章。 rdtsc有同样的问题)

这不仅仅是一个理论问题, 我们用我们的应用程序碰到了这个问题,不得不得出结论,唯一可靠的时间源是timeGetTime ,它只有ms精度(在我们的例子中幸运的是足够了)。 我们也试着修复线程的亲和力,以保证每个线程总是从QueryPerformanceCounter得到一个一致的值,这个工作,但它绝对杀死了应用程序的性能。

总结一下,Windows上没有可靠的定时器,可以用微秒的精度来处理事情(至少不是在多核计算机上运行时)。

Windows有一个高性能计数器API 。

您需要获取QueryPerformanceCounter的刻度,然后除以QueryPerformanceFrequency提供的处理器的频率。

 LARGE_INTEGER frequency; if (::QueryPerformanceFrequency(&frequency) == FALSE) throw "foo"; LARGE_INTEGER start; if (::QueryPerformanceCounter(&start) == FALSE) throw "foo"; // Calculation. LARGE_INTEGER end; if (::QueryPerformanceCounter(&end) == FALSE) throw "foo"; double interval = static_cast<double>(end.QuadPart - start.QuadPart) / frequency.QuadPart; 

这个interval应该在几秒钟内。

为了将来的参考,在Windows Vista,2008及更高版本中,Windows需要硬件支持“HPET”。 这个操作独立于CPU及其时钟和频率。 精度可以达到亚微秒。

为了实现这一点,你需要使用QPC / QPF。 问题是QPF(频率)是一个NOMINAL值,所以使用原始呼叫会造成时间漂移,每天可能会超过几分钟。 为了解决这个问题,你必须测量实际的频率,并检查其随着时间的推移,因为热量和其他物理操作条件会影响它。

描述这个的文章可以在MSDN上找到(大约在2004年!)在这个链接。 http://msdn.microsoft.com/en-us/magazine/cc163996.aspx

我自己也自己实现了类似的东西(现在刚刚发现了上面的链接!),但是宁愿不要使用“微秒时间”,因为与其他Windows调用(如GetSystemTimeAsFileTime)相比,QPC调用本身相当长,同步会增加更多开销。 所以我更喜欢使用毫秒时间戳(比使用QPC少了大约70%的通话时间),特别是当我试图让时间每秒钟数十万次时。

QueryPerformanceCounterQueryPerformanceFrequency是最好的选择。

微软最近刚刚(2014年)发布了更多有关QueryPerformanceCounter的详细信息:

有关详细信息,请参阅获取高分辨率时间戳 (MSDN 2014)。

这是一个综合性的文章,有很多的例子和详细的描述。 A必须阅读QPC的用户。

MSDN声称 –

场景对象是一个高度准确的计时器,当您启动和停止ETW事件时(Windows的事件跟踪)。 它被设计用于性能测试和基准测试,并且包含C#和C ++版本。 …根据现代硬件的经验,对Begin()或者End()的调用需要微秒的数量级,并且得到的时间戳精确到100ns(即0.1微秒)。 … .NET 3.5(用C#编写)和本地C ++都可以使用,并且可以在x86和x64平台上运行。 Scenario类最初是使用Visual Studio 2008开发的,但现在针对使用Visual Studio 2010的开发人员。]

从方案主页 。 据我所知,它是由PPL提供的。

Addionaly你可以阅读这个高分辨率时钟和定时器在Windows中的性能测量 。

可以使用Konrad Rudolf提出的性能计数器API,但应该警告它是基于CPU频率的。 当例如省电模式被启用时,该频率不稳定。 如果你想使用这个API,确保CPU是在一个恒定的频率。

否则,您可以创建某种“统计”系统,将CPU刻度与PC BIOS时钟相关联。 后者是不太精确,但不变。

我认为微秒有点不合理(没有硬件帮助)。 毫秒是可行的,但即使那样不准确,由于各种邪恶的反分辨率问题。 无论如何,我还包括我自己的定时器类(基于std :: chrono)供您考虑:

 #include <type_traits> #include <chrono> class Stopwatch final { public: using elapsed_resolution = std::chrono::milliseconds; Stopwatch() { Reset(); } void Reset() { reset_time = clock.now(); } elapsed_resolution Elapsed() { return std::chrono::duration_cast<elapsed_resolution>(clock.now() - reset_time); } private: std::chrono::high_resolution_clock clock; std::chrono::high_resolution_clock::time_point reset_time; }; 

请注意,在Windows下的std :: chrono :: high_resolution_clock正在使用QueryPerformanceCounter,所以它只是相同的,但可移植。

在较新的Windows版本中, 您可能需要GetSystemTimePreciseAsFileTime 请参阅获取高分辨率时间戳 。

大量的这些变化是一个相当不幸的金额和硬件和操作系统版本的基础上。

如果您可以使用Visual Studio编译器2012或更高版本,则可以使用std :: chrono标准库。

 #include <chrono> ::std::chrono::steady_clock::time_point time = std::chrono::steady_clock::now(); 

请注意, MSVC 2012版本可能只有1ms准确 。 新版本应该精确到微秒。

使用QueryPerformanceCounter (用于Windows)

关于康拉德·鲁道夫的回答,请注意,根据我的经验,性能计数器的频率在3.7MHz左右,所以亚微秒级,但肯定不是纳秒级的精度。 实际的频率是硬件(和省电模式)的依赖。 毫微秒精度在任何情况下都是不合理的,因为中断延迟和进程/线程上下文切换时间远远超过这个时间,这也是个别机器指令的数量级。

rdtsc指令是最准确的。

这是一个Timer类,可以同时适用于Windows和Linux:

 #ifndef INCLUDE_CTIMER_HPP_ #define INCLUDE_CTIMER_HPP_ #if defined(_MSC_VER) # define NOMINMAX // workaround a bug in windows.h # include <windows.h> #else # include <sys/time.h> #endif namespace Utils { class CTimer { private: # if defined(_MSC_VER) LARGE_INTEGER m_depart; # else timeval m_depart; # endif public: inline void start() { # if defined(_MSC_VER) QueryPerformanceCounter(&m_depart); # else gettimeofday(&m_depart, 0); # endif }; inline float GetSecondes() const { # if defined(_MSC_VER) LARGE_INTEGER now; LARGE_INTEGER freq; QueryPerformanceCounter(&now); QueryPerformanceFrequency(&freq); return (now.QuadPart - m_depart.QuadPart) / static_cast<float>(freq.QuadPart); # else timeval now; gettimeofday(&now, 0); return now.tv_sec - m_depart.tv_sec + (now.tv_usec - m_depart.tv_usec) / 1000000.0f; # endif }; }; } #endif // INCLUDE_CTIMER_HPP_ 

感谢您的输入…虽然我无法获得纳米,或微妙的分辨率本来不错,但是我能够拿出这个…也许别人会发现它有用。

  class N_Script_Timer { public: N_Script_Timer() { running = false; milliseconds = 0; seconds = 0; start_t = 0; end_t = 0; } void Start() { if(running)return; running = true; start_t = timeGetTime(); } void End() { if(!running)return; running = false; end_t = timeGetTime(); milliseconds = end_t - start_t; seconds = milliseconds / (float)1000; } float milliseconds; float seconds; private: unsigned long start_t; unsigned long end_t; bool running; };