From b2108839b0d58281037133b896f0fac2ffe189d4 Mon Sep 17 00:00:00 2001 From: Norbert Federa Date: Thu, 27 Jun 2013 13:00:54 +0200 Subject: [PATCH] utils: fix broken stopwatch implementation Stopwatch (in the way it is used) must be able to measure the wall clock time with high resolution but used clock() which is not appropriate for this purpose: On POSIX systems clock() returns the processor time used by the program. On Windows clock() does measure the wall clock time but has only a resolution of 1ms (if at all). This also renders the freerdp profiler unusable. This commit changes stopwatch to use the performance counters on Windows and gettimeofday() for the rest. Also added a warning about invalid profiling results to the RemoteFX codec if rfxcontext->priv->UseThreads is enabled because stopwatch is currently not used in a thread safe way. Also see GitHub Issue #1325 --- include/freerdp/utils/stopwatch.h | 10 +++---- libfreerdp/codec/rfx.c | 1 + libfreerdp/utils/stopwatch.c | 44 ++++++++++++++++++++----------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/include/freerdp/utils/stopwatch.h b/include/freerdp/utils/stopwatch.h index 843d1bd12..af6aa1ee3 100644 --- a/include/freerdp/utils/stopwatch.h +++ b/include/freerdp/utils/stopwatch.h @@ -20,17 +20,15 @@ #ifndef FREERDP_UTILS_STOPWATCH_H #define FREERDP_UTILS_STOPWATCH_H -#include - #include #include struct _STOPWATCH { - clock_t start; - clock_t end; - double elapsed; - clock_t count; + UINT64 start; + UINT64 end; + UINT64 elapsed; + UINT32 count; }; typedef struct _STOPWATCH STOPWATCH; diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index a8fbea20c..f12547ce2 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -259,6 +259,7 @@ void rfx_context_free(RFX_CONTEXT* context) { CloseThreadpool(context->priv->ThreadPool); DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv); + IF_PROFILER (fprintf(stderr, "\nWARNING: Profiling results probably unusable with multithreaded RemoteFX codec!\n");) } BufferPool_Free(context->priv->BufferPool); diff --git a/libfreerdp/utils/stopwatch.c b/libfreerdp/utils/stopwatch.c index a9ffd6bb6..fb1c5c161 100644 --- a/libfreerdp/utils/stopwatch.c +++ b/libfreerdp/utils/stopwatch.c @@ -26,9 +26,33 @@ #include +#ifdef _WIN32 +LARGE_INTEGER stopwatch_freq = { 0, 0 }; +#else +#include +#endif + +void stopwatch_set_time(UINT64* usecs) +{ +#ifdef _WIN32 + LARGE_INTEGER perfcount; + QueryPerformanceCounter(&perfcount); + *usecs = (perfcount.QuadPart * 1000000) / stopwatch_freq.QuadPart; +#else + struct timeval tv; + gettimeofday(&tv, NULL); + *usecs = tv.tv_sec * 1000000 + tv.tv_usec; +#endif +} + STOPWATCH* stopwatch_create() { STOPWATCH* sw; +#ifdef _WIN32 + if (stopwatch_freq.QuadPart == 0) { + QueryPerformanceFrequency(&stopwatch_freq); + } +#endif sw = (STOPWATCH*) malloc(sizeof(STOPWATCH)); stopwatch_reset(sw); @@ -43,13 +67,13 @@ void stopwatch_free(STOPWATCH* stopwatch) void stopwatch_start(STOPWATCH* stopwatch) { - stopwatch->start = clock(); + stopwatch_set_time(&stopwatch->start); stopwatch->count++; } void stopwatch_stop(STOPWATCH* stopwatch) { - stopwatch->end = clock(); + stopwatch_set_time(&stopwatch->end); stopwatch->elapsed += (stopwatch->end - stopwatch->start); } @@ -63,22 +87,12 @@ void stopwatch_reset(STOPWATCH* stopwatch) double stopwatch_get_elapsed_time_in_seconds(STOPWATCH* stopwatch) { - return ((double) stopwatch->elapsed) / CLOCKS_PER_SEC; + return (stopwatch->elapsed/1000000.0); } void stopwatch_get_elapsed_time_in_useconds(STOPWATCH* stopwatch, UINT32* sec, UINT32* usec) { - double uelapsed; - double clocks_per_usec; - - *sec = ((UINT32) stopwatch->elapsed) / CLOCKS_PER_SEC; - uelapsed = stopwatch->elapsed - ((double)(*sec) * CLOCKS_PER_SEC); - - clocks_per_usec = (CLOCKS_PER_SEC / 1000000); - - if (clocks_per_usec > 0.0) - *usec = (UINT32)(uelapsed / clocks_per_usec); - else - *usec = 0; + *sec = stopwatch->elapsed / 1000000; + *usec = stopwatch->elapsed % 1000000; }