Commit f889476bbd35b4d1667e58522666688bef1f9a89

Jeff Garzik 2011-01-29T01:14:12

Dynamically adjust time spent hashing current work unit, to meet target

diff --git a/cpu-miner.c b/cpu-miner.c
index 8895d50..847e74b 100644
--- a/cpu-miner.c
+++ b/cpu-miner.c
@@ -60,6 +60,7 @@ bool opt_debug = false;
 bool opt_protocol = false;
 bool opt_quiet = false;
 static int opt_retries = 10;
+static int opt_scantime = 5;
 static const bool opt_time = true;
 static enum sha256_algos opt_algo = ALGO_C;
 static int opt_n_threads = 1;
@@ -104,6 +105,10 @@ static struct option_help options_help[] = {
 	  "(-r N) Number of times to retry, if JSON-RPC call fails\n"
 	  "\t(default: 10; use -1 for \"never\")" },
 
+	{ "scantime N",
+	  "(-s N) Upper bound on time spent scanning current work,\n"
+	  "\tin seconds. (default: 5)" },
+
 	{ "threads N",
 	  "(-t N) Number of miner threads (default: 1)" },
 
@@ -124,6 +129,7 @@ static struct option options[] = {
 	{ "protocol-dump", 0, NULL, 'P' },
 	{ "threads", 1, NULL, 't' },
 	{ "retries", 1, NULL, 'r' },
+	{ "scantime", 1, NULL, 's' },
 	{ "url", 1, NULL, 1001 },
 	{ "userpass", 1, NULL, 1002 },
 	{ }
@@ -255,6 +261,7 @@ static void *miner_thread(void *thr_id_int)
 		struct work work __attribute__((aligned(128)));
 		unsigned long hashes_done;
 		struct timeval tv_start, tv_end, diff;
+		uint32_t max_nonce = 0xffffff;
 		json_t *val;
 		bool rc;
 
@@ -302,7 +309,7 @@ static void *miner_thread(void *thr_id_int)
 		case ALGO_C:
 			rc = scanhash_c(work.midstate, work.data + 64,
 				        work.hash1, work.hash,
-					0xffffff, &hashes_done);
+					max_nonce, &hashes_done);
 			break;
 
 #ifdef WANT_SSE2_4WAY
@@ -310,7 +317,7 @@ static void *miner_thread(void *thr_id_int)
 			unsigned int rc4 =
 				ScanHash_4WaySSE2(work.midstate, work.data + 64,
 						  work.hash1, work.hash,
-						  0xffffff, &hashes_done);
+						  max_nonce, &hashes_done);
 			rc = (rc4 == -1) ? false : true;
 			}
 			break;
@@ -318,20 +325,20 @@ static void *miner_thread(void *thr_id_int)
 
 #ifdef WANT_VIA_PADLOCK
 		case ALGO_VIA:
-			rc = scanhash_via(work.data, 0xffffff, &hashes_done);
+			rc = scanhash_via(work.data, max_nonce, &hashes_done);
 			break;
 #endif
 		case ALGO_CRYPTOPP:
 			rc = scanhash_cryptopp(work.midstate, work.data + 64,
 				        work.hash1, work.hash,
-					0xffffff, &hashes_done);
+					max_nonce, &hashes_done);
 			break;
 
 #ifdef WANT_CRYPTOPP_ASM32
 		case ALGO_CRYPTOPP_ASM32:
 			rc = scanhash_asm32(work.midstate, work.data + 64,
 				        work.hash1, work.hash,
-					0xffffff, &hashes_done);
+					max_nonce, &hashes_done);
 			break;
 #endif
 
@@ -340,11 +347,24 @@ static void *miner_thread(void *thr_id_int)
 			return NULL;
 		}
 
+		/* record scanhash elapsed time */
 		gettimeofday(&tv_end, NULL);
 		timeval_subtract(&diff, &tv_end, &tv_start);
 
 		hashmeter(thr_id, &diff, hashes_done);
 
+		/* adjust max_nonce to meet target scan time */
+		if (diff.tv_sec > (opt_scantime * 2))
+			max_nonce /= 2;			/* large decrease */
+		else if (diff.tv_sec > opt_scantime)
+			max_nonce -= 1000;		/* small decrease */
+		else if (diff.tv_sec < (opt_scantime - 1))
+			max_nonce += 1000;		/* small increase */
+
+		/* catch stupidly slow cases, such as simulators */
+		if (max_nonce < 1000)			
+			max_nonce = 1000;
+
 		/* if nonce found, submit work */
 		if (rc)
 			submit_work(&work);
@@ -403,6 +423,13 @@ static void parse_arg (int key, char *arg)
 
 		opt_retries = v;
 		break;
+	case 's':
+		v = atoi(arg);
+		if (v < 1 || v > 9999)	/* sanity check */
+			show_usage();
+
+		opt_scantime = v;
+		break;
 	case 't':
 		v = atoi(arg);
 		if (v < 1 || v > 9999)	/* sanity check */
@@ -433,7 +460,7 @@ static void parse_cmdline(int argc, char *argv[])
 	int key;
 
 	while (1) {
-		key = getopt_long(argc, argv, "a:qDPr:t:h?", options, NULL);
+		key = getopt_long(argc, argv, "a:qDPr:s:t:h?", options, NULL);
 		if (key < 0)
 			break;