我有兴趣在Windows中使用C ++测量一个特定的时间点到纳秒。这可能吗?如果不是,是否有可能至少以微秒为单位获得特定时间?任何库都应该这样做,除非我认为托管代码是可能的。 感谢
答案 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)
最佳选择是函数QueryPerformanceCounter
和QueryPerformanceFrequency
。
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;
};