/* * clock_hr_microsec.c * * A small library to measure execution time of code as precisely as possible. * * TODO: Use fixed point arithmetics * * Author: Intel A80486DX2-66 * License: Unlicense */ #include "clock_hr_microsec.h" // macros #if defined(SYS_NT) static LONGLONG QPF_frequency; # define WinAPI_perror_COMMON_MACRO \ fprintf(stderr, "%s: %lu, %s", s, errorCode, errorString) # define CLOCK_HR_DIFFTIME_MS(t2, t1) \ (((clock_hr_microsec_t) ((t2) - (t1))) / \ ((clock_hr_microsec_t) QPF_frequency)) #elif defined(SYS_UNIX) # define CLOCK_HR_DIFFTIME_MS(t2, t1) \ ((t2) - (t1)) #else # define CLOCK_HR_DIFFTIME_MS(t2, t1) \ ((clock_hr_microsec_t) ((t2) - (t1)) * 1000000.L) / \ ((clock_hr_microsec_t) CLOCKS_PER_SEC) #endif // function implementations void clock_hr_microsec_init(void) { # ifdef SYS_NT // set console output code page to the native one SetConsoleOutputCP(GetACP()); // get CPU frequency LARGE_INTEGER freq; if (!QueryPerformanceFrequency(&freq)) { WinAPI_perror("QueryPerformanceFrequency"); exit(EXIT_FAILURE); } QPF_frequency = freq.QuadPart; # endif } long double clock_hr_microsec(void) { # if defined(SYS_NT) // FIXME: less accurate than Unix LARGE_INTEGER counter; if (!QueryPerformanceCounter(&counter)) { WinAPI_perror("QueryPerformanceCounter"); exit(EXIT_FAILURE); } return (long double) (counter.QuadPart * 1000000ULL); # elif defined(SYS_UNIX) struct timespec ts; clock_gettime(CLOCK_MONOTONIC_RAW, &ts); return ((long double) (ts.tv_sec * 1000000000ULL + ts.tv_nsec)) / 1000.l; # else return (long double) (clock() * 1000000ULL); # endif } clock_hr_microsec_t clock_hr_microsec_diff(clock_hr_microsec_t a, clock_hr_microsec_t b) { return CLOCK_HR_DIFFTIME_MS(a, b); } # ifdef SYS_NT void WinAPI_perror(const char* s) { DWORD errorCode = GetLastError(); LPSTR errorString = NULL; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&errorString, 0, NULL ); if (errorString == NULL) { errorString = "???\n"; WinAPI_perror_COMMON_MACRO; } else { WinAPI_perror_COMMON_MACRO; LocalFree(errorString); } } # endif #ifdef TEST # include int main(void) { clock_hr_microsec_init(); clock_hr_microsec_t t1 = 0, t2 = 0; t1 = clock_hr_microsec(); int counter = 0; printf("["); for (int i = 1; i <= 240; i += 3, counter++) { if (i >= 8 && (counter & 7) == 0) { printf("\n "); } printf("0x%02X", i); if (i <= 237) { printf(", "); } } puts("]\n"); t2 = clock_hr_microsec(); printf("Counter = %d\n" "Time: %" CLOCK_HR_MICROSEC_PRI " microsec\n", counter, clock_hr_microsec_diff(t2, t1)); } #endif