C++ 将 clock_gettime 移植到 Windows
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5404277/
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
Porting clock_gettime to windows
提问by venkysmarty
I have the following code running on qnx momemntics.
我在 qnx momemntics 上运行了以下代码。
#define BILLION 1000000000L;
struct timespec start_time;
struct timespec stop_time;
void start MyTestFunc() {
//Initialize the Test Start time
clock_gettime(CLOCK_REALTIME,&start_time)
// ... additonal code.
cout << "The exectuion time of func "<< calculateExecutionTime();
}
double calculateExecutionTime ()
{
clock_gettime(CLOCK_REALTIME,&stop_time);
double dSeconds = (stop_time.tv_sec - start_time.tv_sec);
double dNanoSeconds = (double)( stop_time.tv_nsec - start_time.tv_nsec ) / BILLION;
return dSeconds + dNanoSeconds;
}
Now i want to port above code to windows. can any one provide sample code.
现在我想将上面的代码移植到 Windows。任何人都可以提供示例代码。
Thanks!
谢谢!
回答by Carl Staelin
You can implement a clock_gettime() replacement for windows as follows:
您可以为 Windows 实现 clock_gettime() 替换,如下所示:
LARGE_INTEGER
getFILETIMEoffset()
{
SYSTEMTIME s;
FILETIME f;
LARGE_INTEGER t;
s.wYear = 1970;
s.wMonth = 1;
s.wDay = 1;
s.wHour = 0;
s.wMinute = 0;
s.wSecond = 0;
s.wMilliseconds = 0;
SystemTimeToFileTime(&s, &f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
return (t);
}
int
clock_gettime(int X, struct timeval *tv)
{
LARGE_INTEGER t;
FILETIME f;
double microseconds;
static LARGE_INTEGER offset;
static double frequencyToMicroseconds;
static int initialized = 0;
static BOOL usePerformanceCounter = 0;
if (!initialized) {
LARGE_INTEGER performanceFrequency;
initialized = 1;
usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
if (usePerformanceCounter) {
QueryPerformanceCounter(&offset);
frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
} else {
offset = getFILETIMEoffset();
frequencyToMicroseconds = 10.;
}
}
if (usePerformanceCounter) QueryPerformanceCounter(&t);
else {
GetSystemTimeAsFileTime(&f);
t.QuadPart = f.dwHighDateTime;
t.QuadPart <<= 32;
t.QuadPart |= f.dwLowDateTime;
}
t.QuadPart -= offset.QuadPart;
microseconds = (double)t.QuadPart / frequencyToMicroseconds;
t.QuadPart = microseconds;
tv->tv_sec = t.QuadPart / 1000000;
tv->tv_usec = t.QuadPart % 1000000;
return (0);
}
回答by Asain Kujovic
Avoiding PerformanceCounter mess, simple code:
避免 PerformanceCounter 一团糟,简单的代码:
struct timespec { long tv_sec; long tv_nsec; }; //header part
int clock_gettime(int, struct timespec *spec) //C-file part
{ __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
wintime -=116444736000000000i64; //1jan1601 to 1jan1970
spec->tv_sec =wintime / 10000000i64; //seconds
spec->tv_nsec =wintime % 10000000i64 *100; //nano-seconds
return 0;
}
...is fast, reliable and correct porting solution with impressive 100ns precision (1ms/10000).
...是快速、可靠和正确的移植解决方案,具有令人印象深刻的 100ns 精度 (1ms/10000)。
And QPC-based solution which precision will be possibly (on some hw) even better is:
而基于 QPC 的解决方案的精度可能(在某些硬件上)甚至更好:
struct timespec { long tv_sec; long tv_nsec; }; //header part
#define exp7 10000000i64 //1E+7 //C-file part
#define exp9 1000000000i64 //1E+9
#define w2ux 116444736000000000i64 //1.jan1601 to 1.jan1970
void unix_time(struct timespec *spec)
{ __int64 wintime; GetSystemTimeAsFileTime((FILETIME*)&wintime);
wintime -=w2ux; spec->tv_sec =wintime / exp7;
spec->tv_nsec =wintime % exp7 *100;
}
int clock_gettime(int, timespec *spec)
{ static struct timespec startspec; static double ticks2nano;
static __int64 startticks, tps =0; __int64 tmp, curticks;
QueryPerformanceFrequency((LARGE_INTEGER*)&tmp); //some strange system can
if (tps !=tmp) { tps =tmp; //init ~~ONCE //possibly change freq ?
QueryPerformanceCounter((LARGE_INTEGER*)&startticks);
unix_time(&startspec); ticks2nano =(double)exp9 / tps; }
QueryPerformanceCounter((LARGE_INTEGER*)&curticks); curticks -=startticks;
spec->tv_sec =startspec.tv_sec + (curticks / tps);
spec->tv_nsec =startspec.tv_nsec + (double)(curticks % tps) * ticks2nano;
if (!(spec->tv_nsec < exp9)) { spec->tv_sec++; spec->tv_nsec -=exp9; }
return 0;
}
回答by work.bin
My improvedversion of clock_gettime()
using QueryPerformanceCounter()
.
我改进版的clock_gettime()
使用QueryPerformanceCounter()
。
#define BILLION (1E9)
static BOOL g_first_time = 1;
static LARGE_INTEGER g_counts_per_sec;
int clock_gettime(int dummy, struct timespec *ct)
{
LARGE_INTEGER count;
if (g_first_time)
{
g_first_time = 0;
if (0 == QueryPerformanceFrequency(&g_counts_per_sec))
{
g_counts_per_sec.QuadPart = 0;
}
}
if ((NULL == ct) || (g_counts_per_sec.QuadPart <= 0) ||
(0 == QueryPerformanceCounter(&count)))
{
return -1;
}
ct->tv_sec = count.QuadPart / g_counts_per_sec.QuadPart;
ct->tv_nsec = ((count.QuadPart % g_counts_per_sec.QuadPart) * BILLION) / g_counts_per_sec.QuadPart;
return 0;
}
I think my version is an improvement over the currently accepted answer using QueryPerformanceCounter()
, because -
我认为我的版本是对当前接受的答案的改进QueryPerformanceCounter()
,因为 -
- More robust - checks return values of functions, also value returned in pass-by-reference variable.
- More robust - checks validity of input parameter.
- More streamlined - Uses as few as necessary number of variables (3 vs 7).
- More streamlined - Avoids the code-path involving
GetSystemTimeAsFileTime()
since QueryPerformanceFrequency()and QueryPerformanceCounter()are guaranteed to work on systems that run Windows XP or later.
- 更健壮 - 检查函数的返回值,以及传递引用变量中返回的值。
- 更健壮 - 检查输入参数的有效性。
- 更精简 - 使用尽可能少的变量(3 对 7)。
- 更精简 - 避免了代码路径,
GetSystemTimeAsFileTime()
因为QueryPerformanceFrequency()和QueryPerformanceCounter()保证在运行 Windows XP 或更高版本的系统上工作。
回答by Clark Thomborson
A full-featured and fully-tested implementation of clock_gettime()
has been in mingw-w64 for many years now. You'll have to use a toolchain with mingw64/msys2 to use this conveniently with #include <pthread_time.h>
.
clock_gettime()
mingw-w64 中一个功能齐全且经过全面测试的实现已经存在多年了。您必须使用带有 mingw64/msys2 的工具链才能方便地将其与#include <pthread_time.h>
.
回答by jws
I needed monotonic and realtime.
我需要单调和实时。
For monotonic, I just take the perf counter since a wall clock baseline is meaningless.
对于单调,我只使用性能计数器,因为挂钟基线是没有意义的。
#define MS_PER_SEC 1000ULL // MS = milliseconds
#define US_PER_MS 1000ULL // US = microseconds
#define HNS_PER_US 10ULL // HNS = hundred-nanoseconds (e.g., 1 hns = 100 ns)
#define NS_PER_US 1000ULL
#define HNS_PER_SEC (MS_PER_SEC * US_PER_MS * HNS_PER_US)
#define NS_PER_HNS (100ULL) // NS = nanoseconds
#define NS_PER_SEC (MS_PER_SEC * US_PER_MS * NS_PER_US)
int clock_gettime_monotonic(struct timespec *tv)
{
static LARGE_INTEGER ticksPerSec;
LARGE_INTEGER ticks;
double seconds;
if (!ticksPerSec.QuadPart) {
QueryPerformanceFrequency(&ticksPerSec);
if (!ticksPerSec.QuadPart) {
errno = ENOTSUP;
return -1;
}
}
QueryPerformanceCounter(&ticks);
seconds = (double) ticks.QuadPart / (double) ticksPerSec.QuadPart;
tv->tv_sec = (time_t)seconds;
tv->tv_nsec = (long)((ULONGLONG)(seconds * NS_PER_SEC) % NS_PER_SEC);
return 0;
}
and wall clock, based on GMT unlike the tempting and similar _ftime() function.
和挂钟,基于 GMT,与诱人且类似的 _ftime() 函数不同。
int clock_gettime_realtime(struct timespec *tv)
{
FILETIME ft;
ULARGE_INTEGER hnsTime;
GetSystemTimeAsFileTime(&ft);
hnsTime.LowPart = ft.dwLowDateTime;
hnsTime.HighPart = ft.dwHighDateTime;
// To get POSIX Epoch as baseline, subtract the number of hns intervals from Jan 1, 1601 to Jan 1, 1970.
hnsTime.QuadPart -= (11644473600ULL * HNS_PER_SEC);
// modulus by hns intervals per second first, then convert to ns, as not to lose resolution
tv->tv_nsec = (long) ((hnsTime.QuadPart % HNS_PER_SEC) * NS_PER_HNS);
tv->tv_sec = (long) (hnsTime.QuadPart / HNS_PER_SEC);
return 0;
}
And then the POSIX compatible function... see POSIX header for typedef and macros.
然后是 POSIX 兼容函数...请参阅 POSIX 标头以了解 typedef 和宏。
int clock_gettime(clockid_t type, struct timespec *tp)
{
if (type == CLOCK_MONOTONIC)
{
return clock_gettime_monotonic(tp);
}
else if (type == CLOCK_REALTIME)
{
return clock_gettime_realtime(tp);
}
errno = ENOTSUP;
return -1;
}
回答by Woosung
You can use timespec_getto implement simple clock_gettime.
(timespec_getfunction is available since C11)
您可以使用timespec_get来实现简单的 clock_gettime。
(timespec_get函数自 C11 起可用)
int clock_gettime(int, struct timespec *tv)
{
return timespec_get(tv, TIME_UTC);
}
... but result timespec has about 10 milisec resolution on my windows7 64bit machine. :(
...但结果 timespec 在我的 windows7 64 位机器上有大约 10 毫秒的分辨率。:(
Here is my version of clock_gettime.
这是我的clock_gettime 版本。
int clock_gettime(int, struct timespec *tv)
{
static int initialized = 0;
static LARGE_INTEGER freq, startCount;
static struct timespec tv_start;
LARGE_INTEGER curCount;
time_t sec_part;
long nsec_part;
if (!initialized) {
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&startCount);
timespec_get(&tv_start, TIME_UTC);
initialized = 1;
}
QueryPerformanceCounter(&curCount);
curCount.QuadPart -= startCount.QuadPart;
sec_part = curCount.QuadPart / freq.QuadPart;
nsec_part = (long)((curCount.QuadPart - (sec_part * freq.QuadPart))
* 1000000000UL / freq.QuadPart);
tv->tv_sec = tv_start.tv_sec + sec_part;
tv->tv_nsec = tv_start.tv_nsec + nsec_part;
if(tv->tv_nsec >= 1000000000UL) {
tv->tv_sec += 1;
tv->tv_nsec -= 1000000000UL;
}
return 0;
}