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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1825720/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:17:21  来源:igfitidea点击:

C++ high precision time measurement in Windows

c++cwindows

提问by Kelly Elton

I'm interested in measuring a specific point in time down to the nanosecond using C++ in Windows. Is this possible? If it isn't, is it possible to get the specific time in microseconds at least?. Any library should do, unless I suppose it's possible with managed code. thanks

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

回答by Andreas Brinck

If you have a threaded application running on a multicore computer QueryPerformanceCountercan (and will) return different values depending on which core the code is executing on. See thisMSDN article. (rdtschas the same problem)

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

This is not just a theoretical problem; we ran into it with our application and had to conclude that the only reliable time source is timeGetTimewhich only has ms precision (which fortunately was sufficient in our case). We also tried fixating the thread affinity for our threads to guarantee that each thread always got a consistent value from QueryPerformanceCounter, this worked but it absolutely killed the performance in the application.

这不仅仅是一个理论问题;我们在我们的应用程序中遇到了它,并且不得不得出结论,唯一可靠的时间源是timeGetTime只有 ms 精度(幸运的是,这在我们的情况下就足够了)。我们还尝试为我们的线程固定线程关联,以确保每个线程始终从 获得一致的值QueryPerformanceCounter,这有效,但它绝对会降低应用程序的性能。

To sum things up there isn't a reliabletimer on windows that can be used to time thing with micro second precision (at least not when running on a multicore computer).

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

回答by Konrad Rudolph

Windows has a high-performance counter API.

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

You need to get the ticks form QueryPerformanceCounterand divide by the frequency of the processor, provided by QueryPerformanceFrequency.

您需要获取刻度形式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;

This intervalshould be in seconds.

interval应该在几秒钟内。

回答by Frank LaPiana

For future reference, with Windows Vista, 2008 and higher, Windows requires the hardware support "HPET". This operates independently of the CPU and its clock and frequency. It is possible to obtain times with accuracies to the sub-microsecond.

为了将来参考,对于 Windows Vista、2008 和更高版本,Windows 需要硬件支持“HPET”。这独立于 CPU 及其时钟和频率运行。可以获得精确到亚微秒的时间。

In order to implement this, you DO need to use QPC/QPF. The problem is that QPF (frequency) is a NOMINAL value, so using the raw calls will cause time drifts that can exceed minutes per day. In order to accound for this, you have to measure the actual frequency and check for its drift over time as heat and other physical operating conditions will affect it.

为了实现这一点,您确实需要使用 QPC/QPF。问题在于 QPF(频率)是一个 NOMINAL 值,因此使用原始调用会导致时间漂移,每天可能会超过几分钟。为了解决这个问题,您必须测量实际频率并检查其随时间的漂移,因为热量和其他物理操作条件会对其产生影响。

An article that describes this can be found on MSDN (circa 2004!) at this link. http://msdn.microsoft.com/en-us/magazine/cc163996.aspx

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

I did implement something similar to this myself (and just found the above link today!) but prefer not to use "microsecond time" because the QPC call itself is rather lengthy compared to other Windows calls such as GetSystemTimeAsFileTime, and synchronization adds more overhead. So I prefer to use millisecond timestamps (approx 70% less call time than using QPC) especially when I'm trying to get the time hundreds of thousands of times per second.

我自己确实实现了类似的东西(今天刚刚找到了上面的链接!)但不喜欢使用“微秒时间”,因为与其他 Windows 调用(如 GetSystemTimeAsFileTime)相比,QPC 调用本身相当冗长,并且同步增加了更多的开销。所以我更喜欢使用毫秒时间戳(比使用 QPC 减少大约 70% 的调用时间),尤其是当我试图获得每秒数十万次的时间时。

回答by Arno

The best choice are the functions QueryPerformanceCounterand QueryPerformanceFrequency.

最好的选择是功能QueryPerformanceCounterQueryPerformanceFrequency

Microsoft has just recently (2014) released more detailed information about QueryPerformanceCounter:

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

See Acquiring high-resolution time stamps(MSDN 2014) for the details.

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

This is a comprehensive article with lots of examples and detailed description. A must read for users of QPC.

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

回答by Robinson

I think microseconds is a bit unreasonable (without hardware assistance). Milliseconds is doable, but even then not that accurate due to various nefarious counter resolution issues. Regardless, I include my own timer class (based on std::chrono) for your consideration:

我认为微秒有点不合理(没有硬件帮助)。毫秒是可行的,但由于各种邪恶的计数器解析问题,即使如此也不是那么准确。无论如何,我包括我自己的计时器类(基于 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;
};

Note that under the hood on Windows std::chrono::high_resolution_clock is using QueryPerformanceCounter, so it's just the same but portable.

请注意,Windows std::chrono::high_resolution_clock 的幕后使用的是 QueryPerformanceCounter,因此它是相同但可移植的。

回答by SChepurin

MSDNclaims that -

MSDN声称-

A Scenario object is a highly-accurate timer that logs ETW events (Event Tracing for Windows) when you start and stop it. It's designed to be used for performance instrumentation and benchmarking, and comes in both C# and C++ versions. ... As a rule of thumb on modern hardware, a call to Begin() or End() takes on the order of a microsecond, and the resulting timestamps are accurate to 100ns (i.e. 0.1 microseconds). ... Versions are available for both .NET 3.5 (written in C#), and native C++, and run on both x86 and x64 platforms. The Scenario class was originally developed using Visual Studio 2008, but is now targeted at developers using Visual Studio 2010.]

Scenario 对象是一个高度准确的计时器,它会在您启动和停止它时记录 ETW 事件(Windows 事件跟踪)。它旨在用于性能检测和基准测试,并提供 C# 和 C++ 版本。... 作为现代硬件的经验法则,对 Begin() 或 End() 的调用需要一微秒的数量级,并且由此产生的时间戳精确到 100ns(即 0.1 微秒)。... .NET 3.5(用 C# 编写)和本机 C++ 都有可用的版本,并且可以在 x86 和 x64 平台上运行。Scenario 类最初是使用 Visual Studio 2008 开发的,但现在面向使用 Visual Studio 2010 的开发人员。]

From Scenario Home Page. As far as i know, it was provided by the same people as PPL.

场景主页。据我所知,它是由与 PPL 相同的人提供的。

Addionaly you can read this High Resolution Clocks and Timers for Performance Measurement in Windows.

此外,您可以阅读此高分辨率时钟和计时器以在 Windows 中进行性能测量

回答by Craig Ringer

In newer Windows versions you probably want GetSystemTimePreciseAsFileTime. See Acquiring high resolution timestamps.

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

Lots of this varies a rather unfortunate amount based on hardware and OS version.

根据硬件和操作系统版本,其中很多变化相当不幸。

回答by SpamBot

If you can use the Visual Studio compiler 2012 or higher, you can well use the std::chronostandard library.

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

#include <chrono>

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

Note that the MSVC 2012 version may be only 1ms accurate. Newer versions should be accurate up to a microsecond.

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

回答by xtofl

You canuse the Performance Counter API as Konrad Rudolf proposed, but should be warned that it is based on the CPU frequency. This frequency is not stable when e.g. a power save mode is enabled. If you want to use this API, make sure the CPU is at a constant frequency.

可以使用 Konrad Rudolf 建议的 Performance Counter API,但应注意它基于 CPU 频率。当例如启用省电模式时,该频率不稳定。如果要使用此 API,请确保 CPU 处于恒定频率。

Otherwise, you can create some kind of 'statistical' system, correlating the CPU ticks to the PC BIOS clock. The latter is way less precise, but constant.

否则,您可以创建某种“统计”系统,将 CPU 滴答与 PC BIOS 时钟相关联。后者不太精确,但始终如一。

回答by Clifford

With respect to Konrad Rudolph's answer, note that in my experience the frequency of the performance counter is around 3.7MHz, so sub-microsecond, but certainly not nanosecond precision. The actual frequency is hardware (and power-save mode) dependent. Nanosecond precision is somewhat unreasonable in any case since interrupt latencies and process/thread context switching times are far longer than that, and that is also the order of magnitude of individual machine instructions.

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