将clock_gettime移植到窗口

ven*_*rty 19 c c++ windows

我在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;
}
Run Code Online (Sandbox Code Playgroud)

现在我想将代码移植到Windows上.任何人都可以提供示例代码.

谢谢!

小智 36

您可以为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);
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的代码片段.当我尝试使用`mingw`交叉编译你的代码时,我得到一个错误`'无法将'timespec*'转换为'timeval*'以获取参数'2'到'int clock_gettime(int,timeval*)`..我在这里缺少什么? (2认同)
  • 此代码显示相对于程序启动的时间,而不是实际时钟时间。它显示了重要的功能,但不能代替clock_gettime! (2认同)
  • X 的值是多少? (2认同)

Asa*_*vic 11

避免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;
}
Run Code Online (Sandbox Code Playgroud)

...是快速,可靠和正确的移植解决方案,具有令人印象深刻的100ns精度(1ms/10000).

而基于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;
}
Run Code Online (Sandbox Code Playgroud)

  • FILETIME结构的文档[这里](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx)说"不要将指向FILETIME结构的指针强制转换为ULARGE_INTEGER*或者__int64*值,因为它可能导致64位Windows上的对齐错误." (4认同)
  • @Spencer 它是 &amp;__int64 转换为 FILETIME*,而不是相反的方向,所以它不是总是与 8 字节对齐。 (2认同)

jws*_*jws 7

我需要单调和实时。

对于单调性,我只采用性能计数器,因为挂钟基线毫无意义。

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

    if (!ticksPerSec.QuadPart) {
        QueryPerformanceFrequency(&ticksPerSec);
        if (!ticksPerSec.QuadPart) {
            errno = ENOTSUP;
            return -1;
        }
    }

    QueryPerformanceCounter(&ticks);

    tv->tv_sec = (long)(ticks.QuadPart / ticksPerSec.QuadPart);
    tv->tv_nsec = (long)(((ticks.QuadPart % ticksPerSec.QuadPart) * NS_PER_SEC) / ticksPerSec.QuadPart);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

和挂钟,基于 GMT,与诱人且类似的 _ftime() 函数不同。

int clock_gettime_realtime(struct timespec *tv)
{
    FILETIME ft;
    ULARGE_INTEGER hnsTime;

    GetSystemTimePreciseAsFileTime(&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;
}
Run Code Online (Sandbox Code Playgroud)

然后是 POSIX 兼容函数...有关 typedef 和宏,请参阅 POSIX 标头。

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;
}
Run Code Online (Sandbox Code Playgroud)


Cla*_*son 5

mingw-w64 中的全功能且经过全面测试的实现clock_gettime()已经存在很多年了。您必须使用带有 mingw64/msys2 的工具链才能使用它,并带有标头#include <time.h>(在 Windows 上)。<time.h>如果您正在编写可在 linux 和 windows 之间移植的代码库,并且在linux 版本3中找不到clock_gettime() ,我建议您尝试使用#include <pthread_time.h>进行编译-pthread或使用 进行链接-lrt

另请参阅有关 Windows 版本的问题60020968 ;以及33846055538609用于您的 Linux 版本。