Commit 8745ba1e6de3cd7c5cadb21afa015a7662579c1b

Con Kolivas 2012-08-15T09:38:45

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.

diff --git a/driver-opencl.c b/driver-opencl.c
index b6dfe12..78908bf 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 af66e85..26d628b 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 822e61d..b104d8a 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;
+}