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

时间:2009-12-01 11:58:05

标签: c++ c windows

我有兴趣在Windows中使用C ++测量一个特定的时间点到纳秒。这可能吗?如果不是,是否有可能至少以微秒为单位获得特定时间?任何库都应该这样做,除非我认为托管代码是可能的。 感谢

14 个答案:

答案 0 :(得分:34)

如果您在多核计算机上运行了线程应用程序QueryPerformanceCounter可以(并且将)返回不同的值,具体取决于代码执行的核心。请参阅this MSDN文章。 (rdtsc有同样的问题)

这不仅仅是一个理论问题;我们用我们的应用程序遇到它并且必须得出结论,唯一可靠的时间源是timeGetTime,它只有ms精度(幸运的是在我们的情况下已经足够了)。我们还尝试修复线程的线程亲和性,以保证每个线程始终从QueryPerformanceCounter获得一致的值,这有效,但它绝对杀死了应用程序中的性能。

总而言之,Windows上没有可靠的计时器,可用于以微秒精度计时(至少在多核计算机上运行时不行)。

答案 1 :(得分:14)

Windows有一个high-performance counter 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应该在几秒钟内完成。

答案 2 :(得分:6)

为了将来参考,对于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%的通话时间),特别是当我试图每秒钟数十万次时。

答案 3 :(得分:5)

最佳选择是函数QueryPerformanceCounterQueryPerformanceFrequency

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

有关详细信息,请参阅Acquiring high-resolution time stamps(MSDN 2014)。

这是一篇包含大量示例和详细说明的综合性文章。必须为QPC用户阅读。

答案 4 :(得分:3)

MSDN声称 -

  

Scenario对象是一个高度准确的计时器,用于记录ETW事件   (启动和停止事件跟踪)。它的设计   用于性能仪表和基准测试,并且来了   在C#和C ++版本中。 ......作为现代的经验法则   硬件,对Begin()或End()的调用采用a的顺序   微秒,结果时间戳精确到100ns(即   0.1微秒)。 ...版本可用于.NET 3.5(用C#编写)和本机C ++,并且可以在x86和x64上运行   平台。 Scenario类最初是使用Visual开发的   Studio 2008,但现在针对使用Visual Studio的开发人员   2010。]

来自Scenario Home Page。据我所知,它是由与PPL相同的人提供的。

Addionaly你可以阅读High Resolution Clocks and Timers for Performance Measurement in Windows

答案 5 :(得分:3)

我认为微秒有点不合理(没有硬件辅助)。毫秒是可行的,但即使这样,由于各种邪恶的反分辨率问题也不那么准确。无论如何,我包括我自己的计时器类(基于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,所以它只是相同但可移植。

答案 6 :(得分:2)

在较新的Windows版本you probably want GetSystemTimePreciseAsFileTime中。请参阅Acquiring high resolution timestamps

根据硬件和操作系统版本的不同,很多都会变得非常不幸。

答案 7 :(得分:1)

可以使用性能计数器API,就像Konrad Rudolf提出的那样,但是应该警告它是基于CPU频率的。例如,当频率不稳定时启用省电模式。如果要使用此API,请确保CPU处于恒定频率。

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

答案 8 :(得分:1)

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

#include <chrono>

::std::chrono::steady_clock::time_point time = std::chrono::steady_clock::now();

请注意MSVC 2012 version may be only 1ms accurate。较新的版本应该精确到一微秒。

答案 9 :(得分:0)

使用QueryPerformanceCounter(对于Windows)

答案 10 :(得分:0)

关于Konrad Rudolph的回答,请注意,根据我的经验,性能计数器的频率约为3.7MHz,因此亚微秒,但肯定不是纳秒精度。实际频率取决于硬件(和省电模式)。在任何情况下,纳秒精度都是不合理的,因为中断延迟和进程/线程上下文切换时间远远长于此,并且这也是单个机器指令的数量级。

答案 11 :(得分:0)

rdtsc instruction是最准确的。

答案 12 :(得分:0)

这是一个适用于Windows和Linux的Timer类:

#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_

答案 13 :(得分:0)

感谢您的输入......虽然我无法获得nano或微秒分辨率本来不错,但我能够想出这个...也许别人会发现它很有用。

    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;
};