1
0
mirror of https://gitlab.com/80486DX2-66/gists synced 2025-01-10 08:27:48 +05:30
gists/c-programming/benchmarking/clock_hr_microsec.c

131 lines
3.0 KiB
C

/*
* 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 <stdio.h>
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