Portar clock_gettime a windows

Tengo el siguiente código ejecutándose en 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; } 

Ahora quiero exportar el código por encima de Windows. ¿alguien puede proporcionar código de muestra?

¡Gracias!

Puede implementar un reemplazo clock_gettime () para Windows de la siguiente manera:

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

Evitar el desorden de PerformanceCounter, código simple:

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

… es solución de portabilidad rápida, confiable y correcta con una impresionante precisión de 100ns (1ms / 10000).

Y la solución basada en QPC cuya precisión será posiblemente (en algunos hw) aún mejor es:

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

Mi versión mejorada de clock_gettime() usando 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; } 

Creo que mi versión es una mejora sobre la respuesta actualmente aceptada utilizando QueryPerformanceCounter() , porque –

  1. Más robusto: comprueba los valores devueltos de las funciones, también el valor devuelto en la variable de paso por referencia.
  2. Más robusto: verifica la validez del parámetro de entrada.
  3. Más simplificado: utiliza el número de variables necesario (3 frente a 7).
  4. Más optimizado: evita la ruta de código que involucra GetSystemTimeAsFileTime() ya que QueryPerformanceFrequency () y QueryPerformanceCounter () tienen la garantía de funcionar en sistemas que ejecutan Windows XP o posterior .

Puede usar timespec_get para implementar simple clock_gettime.
(la función timespec_get está disponible desde C11)

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

… pero el timespec del resultado tiene una resolución de aproximadamente 10 milisegundos en mi máquina Windows7 de 64 bits. 🙁

Aquí está mi versión de 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; } 

Necesitaba monotónico y en tiempo real.

Para monotónico, simplemente tomo el contador de perf del dispositivo porque la línea de base del reloj de pared no tiene sentido.

 #define MS_PER_SEC 1000ULL // MS = milliseconds #define US_PER_MS 1000ULL // US = microseconds #define HNS_PER_US 10ULL // HNS = hundred-nanoseconds (eg, 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; } 

y reloj de pared, basado en GMT a diferencia de la tentadora y similar función _time ().

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

Y luego la función compatible con POSIX … ver el encabezado POSIX para typedef y macros.

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