2011-03-23 187 views
15

我在qnx momemntics上运行以下代码。将clock_gettime移植到窗口

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

现在我想将上面的代码移植到windows。任何人都可以提供示例代码。

谢谢!

+1

检查一些选项在http://stackoverflow.com/questions/275004/c-timer-function-to-provide-time-in-nano-seconds – pmg 2011-03-23 11:20:26

回答

31

您可以实现一个用于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); 
} 
+0

whow ...你有这个代码准备好了,hadn你呢?我喜欢劫持'clock_gettime'函数的想法。 – xtofl 2011-03-23 12:27:54

+0

是的 - 这是我编写的代码作为lmbench到Windows的端口的一部分 – 2011-05-16 12:36:32

+2

感谢您的片段。当我尝试使用'mingw'交叉编译你的代码时,我得到一个'不能将参数'2'转换'timespec *'到'timeval *'的错误'int clock_gettime(int,timeval *)'..我在这里错过了什么? – a1337q 2013-01-11 10:44:59

8

避免的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; 
} 

...是快速,可靠和正确的移植解决方案时,高精度并不那么重要。

而且具有全精度基于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; 
} 
+4

FILETIME结构的文档[here](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx)说:“不要将指向FILETIME结构的指针转换为ULARGE_INTEGER *或__int64 *值,因为它可能导致64位Windows上的对齐错误。“ – Spencer 2015-09-03 17:04:35

+0

你是一个救世主。这是我的Windows机器和Linux针对的C99库之间唯一的东西:) – 2016-07-22 21:03:51

+1

@Spencer它是&__ int64转换为FILETIME *,而不是反方向,所以它不总是对齐到8个字节。 – 2016-07-27 14:50:19

-1

您可以使用timespec_get实现简单clock_gettime。
timespec_get功能可用,因为C11)

int clock_gettime(int, struct timespec *tv) 
{ 
    return timespec_get(tv, TIME_UTC); 
} 

...但结果的timespec有我的windows7 64位计算机上约10毫秒为单位的分辨率。 :(

这里是我的版本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; 
} 
+1

timespec_get()在VS 2013,Windows 8中不可用。 – 2016-07-05 19:42:32

2

使用QueryPerformanceCounter()提高版本的clock_gettime()

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

我觉得我的版本是采用了目前公认的答案的改进因为 -

  1. 更健壮 - 检查函数的返回值,也是通过引用传递变量返回的值。
  2. 更健壮 - 检查输入参数的有效性。
  3. 更简化 - 使用尽可能少的变量(3 vs 7)。
  4. 更简化 - 避免涉及GetSystemTimeAsFileTime()的代码路径,因为QueryPerformanceFrequency()QueryPerformanceCounter()保证在运行Windows XP或更高版本的系统上运行
+0

这不会使用MSVC2015的编译器进行编译。你忘了添加所有包含吗?如果可能,我想尝试一下。 – 2017-01-11 03:06:29

+1

我没有在片段中显示包含,但它确实需要这里提到的标头 - https://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx 。 – 2017-01-11 12:14:05

+0

太棒了! Ty更新,work.bin!我会检查出来^ _^ – 2017-01-11 18:51:47