mirror of
https://gitlab.com/80486DX2-66/gists
synced 2025-01-10 17:32:05 +05:30
134 lines
3.0 KiB
C
134 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
|