2011-03-23 131 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