From 8745ba1e6de3cd7c5cadb21afa015a7662579c1b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Wed, 15 Aug 2012 09:38:45 +1000 Subject: [PATCH] Windows' timer resolution is limited to 15ms accuracy. This was breaking dynamic intensity since it tries to measure below this. Since we are repeatedly sampling similar timeframes, we can average the gpu_us result over 5 different values to get very fine precision. --- driver-opencl.c | 26 ++++++++++++++++++-------- miner.h | 6 ++++-- util.c | 6 ++++++ 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/driver-opencl.c b/driver-opencl.c index b6dfe12e..78908bff 100644 --- a/driver-opencl.c +++ b/driver-opencl.c @@ -1490,6 +1490,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, _clState *clState = clStates[thr_id]; const cl_kernel *kernel = &clState->kernel; const int dynamic_us = opt_dynamic_interval * 1000; + struct timeval tv_gpuend; cl_bool blocking; cl_int status; @@ -1508,13 +1509,17 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, clFinish(clState->commandQueue); if (gpu->dynamic) { - struct timeval diff; - suseconds_t gpu_us; - - gettimeofday(&gpu->tv_gpuend, NULL); - timersub(&gpu->tv_gpuend, &gpu->tv_gpustart, &diff); - gpu_us = diff.tv_sec * 1000000 + diff.tv_usec; - if (likely(gpu_us >= 0)) { + double gpu_us; + + /* Windows returns the same time for gettimeofday due to its + * 15ms timer resolution, so we must average the result over + * at least 5 values that are actually different to get an + * accurate result */ + gpu->intervals++; + gettimeofday(&tv_gpuend, NULL); + gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpumid); + if (gpu_us > 0 && ++gpu->hit > 4) { + gpu_us = us_tdiff(&tv_gpuend, &gpu->tv_gpustart) / gpu->intervals; gpu->gpu_us_average = (gpu->gpu_us_average + gpu_us * 0.63) / 1.63; /* Try to not let the GPU be out for longer than @@ -1527,6 +1532,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, if (gpu->intensity < MAX_INTENSITY) ++gpu->intensity; } + gpu->intervals = gpu->hit = 0; } } set_threads_hashes(clState->vwidth, &threads, &hashes, globalThreads, @@ -1562,7 +1568,11 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, clFinish(clState->commandQueue); } - gettimeofday(&gpu->tv_gpustart, NULL); + gettimeofday(&gpu->tv_gpumid, NULL); + if (!gpu->intervals) { + gpu->tv_gpustart.tv_sec = gpu->tv_gpumid.tv_sec; + gpu->tv_gpustart.tv_usec = gpu->tv_gpumid.tv_usec; + } if (clState->goffset) { size_t global_work_offset[1]; diff --git a/miner.h b/miner.h index af66e85f..26d628bb 100644 --- a/miner.h +++ b/miner.h @@ -366,9 +366,10 @@ struct cgpu_info { int opt_tc, thread_concurrency; int shaders; #endif - struct timeval tv_gpustart;; - struct timeval tv_gpuend; + struct timeval tv_gpustart; + struct timeval tv_gpumid; double gpu_us_average; + int intervals, hit; #endif float temp; @@ -440,6 +441,7 @@ extern int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*s extern void thr_info_cancel(struct thr_info *thr); extern void thr_info_freeze(struct thr_info *thr); extern void nmsleep(unsigned int msecs); +extern double us_tdiff(struct timeval *end, struct timeval *start); struct string_elist { char *string; diff --git a/util.c b/util.c index 822e61df..b104d8a3 100644 --- a/util.c +++ b/util.c @@ -705,3 +705,9 @@ void nmsleep(unsigned int msecs) ret = nanosleep(&twait, &tleft); } while (ret == -1 && errno == EINTR); } + +/* Returns the microseconds difference between end and start times as a double */ +double us_tdiff(struct timeval *end, struct timeval *start) +{ + return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec; +}