prog_util: use QueryPerformanceCounter() on Windows

QueryPerformanceCounter() is much more accurate than
GetSystemTimeAsFileTime().

Also avoid converting into a specific time unit until the results need
to be displayed.  This is more efficient and avoids losing precision.
This commit is contained in:
Eric Biggers 2016-10-16 14:15:59 -07:00
parent 7662390f55
commit e20e275081
4 changed files with 55 additions and 20 deletions

View File

@ -352,26 +352,26 @@ do_benchmark(struct file_stream *in, void *original_buf, void *compressed_buf,
total_uncompressed_size += original_size; total_uncompressed_size += original_size;
/* Compress the chunk of data. */ /* Compress the chunk of data. */
start_time = current_time(); start_time = timer_ticks();
compressed_size = do_compress(compressor, compressed_size = do_compress(compressor,
original_buf, original_buf,
original_size, original_size,
compressed_buf, compressed_buf,
original_size - 1); original_size - 1);
total_compress_time += current_time() - start_time; total_compress_time += timer_ticks() - start_time;
if (compressed_size) { if (compressed_size) {
/* Successfully compressed the chunk of data. */ /* Successfully compressed the chunk of data. */
/* Decompress the data we just compressed and compare /* Decompress the data we just compressed and compare
* the result with the original. */ * the result with the original. */
start_time = current_time(); start_time = timer_ticks();
result = do_decompress(decompressor, result = do_decompress(decompressor,
compressed_buf, compressed_buf,
compressed_size, compressed_size,
decompressed_buf, decompressed_buf,
original_size); original_size);
total_decompress_time += current_time() - start_time; total_decompress_time += timer_ticks() - start_time;
if (!result) { if (!result) {
msg("%"TS": failed to decompress data", msg("%"TS": failed to decompress data",
@ -414,11 +414,11 @@ do_benchmark(struct file_stream *in, void *original_buf, void *compressed_buf,
(unsigned int)(total_compressed_size * 100000 / (unsigned int)(total_compressed_size * 100000 /
total_uncompressed_size % 1000)); total_uncompressed_size % 1000));
printf("\tCompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n", printf("\tCompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n",
total_compress_time / 1000000, timer_ticks_to_ms(total_compress_time),
1000 * total_uncompressed_size / total_compress_time); timer_MB_per_s(total_uncompressed_size, total_compress_time));
printf("\tDecompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n", printf("\tDecompression time: %"PRIu64" ms (%"PRIu64" MB/s)\n",
total_decompress_time / 1000000, timer_ticks_to_ms(total_decompress_time),
1000 * total_uncompressed_size / total_decompress_time); timer_MB_per_s(total_uncompressed_size, total_decompress_time));
return 0; return 0;
} }

View File

@ -79,9 +79,9 @@ checksum_stream(struct file_stream *in, cksum_fn_t cksum, u32 *sum,
break; break;
size += ret; size += ret;
start_time = current_time(); start_time = timer_ticks();
*sum = cksum(*sum, buf, ret); *sum = cksum(*sum, buf, ret);
elapsed += current_time() - start_time; elapsed += timer_ticks() - start_time;
} }
if (elapsed == 0) if (elapsed == 0)
@ -178,8 +178,8 @@ tmain(int argc, tchar *argv[])
if (do_timing) { if (do_timing) {
printf("%08"PRIx32"\t%"TS"\t" printf("%08"PRIx32"\t%"TS"\t"
"%"PRIu64" ms\t%"PRIu64" MB/s\n", "%"PRIu64" ms\t%"PRIu64" MB/s\n",
sum, in.name, elapsed / 1000000, sum, in.name, timer_ticks_to_ms(elapsed),
1000 * size / elapsed); timer_MB_per_s(size, elapsed));
} else { } else {
printf("%08"PRIx32"\t%"TS"\t\n", sum, in.name); printf("%08"PRIx32"\t%"TS"\t\n", sum, in.name);
} }

View File

@ -102,16 +102,16 @@ xmalloc(size_t size)
} }
/* /*
* Retrieve the current time in nanoseconds since a start time which is fixed * Return the number of timer ticks that have elapsed since some unspecified
* for the duration of program execution but is otherwise unspecified * point fixed at the start of program execution
*/ */
u64 u64
current_time(void) timer_ticks(void)
{ {
#ifdef _WIN32 #ifdef _WIN32
FILETIME ft; LARGE_INTEGER count;
GetSystemTimeAsFileTime(&ft); QueryPerformanceCounter(&count);
return 100 * (((u64)ft.dwHighDateTime << 32) | ft.dwLowDateTime); return count.QuadPart;
#elif defined(HAVE_CLOCK_GETTIME) #elif defined(HAVE_CLOCK_GETTIME)
struct timespec ts; struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts); clock_gettime(CLOCK_MONOTONIC, &ts);
@ -119,10 +119,43 @@ current_time(void)
#else #else
struct timeval tv; struct timeval tv;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
return (1000000000 * (u64)tv.tv_sec) + (1000 * (u64)tv.tv_usec); return (1000000 * (u64)tv.tv_sec) + tv.tv_usec;
#endif #endif
} }
/*
* Return the number of timer ticks per second
*/
static u64
timer_frequency(void)
{
#ifdef _WIN32
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return freq.QuadPart;
#elif defined(HAVE_CLOCK_GETTIME)
return 1000000000;
#else
return 1000000;
#endif
}
/*
* Convert a number of elapsed timer ticks to milliseconds
*/
u64 timer_ticks_to_ms(u64 ticks)
{
return ticks * 1000 / timer_frequency();
}
/*
* Convert a byte count and a number of elapsed timer ticks to MB/s
*/
u64 timer_MB_per_s(u64 bytes, u64 ticks)
{
return bytes * timer_frequency() / ticks / 1000000;
}
/* /*
* Retrieve a pointer to the filename component of the specified path. * Retrieve a pointer to the filename component of the specified path.
* *

View File

@ -120,7 +120,9 @@ extern void _printf(1, 2) msg_errno(const char *fmt, ...);
extern void *xmalloc(size_t size); extern void *xmalloc(size_t size);
extern u64 current_time(void); extern u64 timer_ticks(void);
extern u64 timer_ticks_to_ms(u64 ticks);
extern u64 timer_MB_per_s(u64 bytes, u64 ticks);
extern const tchar *get_filename(const tchar *path); extern const tchar *get_filename(const tchar *path);