Commit a76b09e4fc41178bd515dc4a6c6bb001d8005a95

Con Kolivas 2013-09-13T13:51:15

Find the greatest common denominator in quotas and use the smallest number of consecutive work items per pool in quota load balance mode to smooth hashrate across pools with large quotas. Give excess quota to priority pool 0 instead of pool 0.

diff --git a/README b/README
index 4fadbcf..54eb796 100644
--- a/README
+++ b/README
@@ -517,9 +517,9 @@ If all pools are set to zero quota or all pools with quota are dead, it will
 fall back to a failover mode. See quota below for more information.
 
 The failover-only flag has special meaning in combination with load-balance
-mode and it will distribute quota back to pool 0 from any pools that are
-unable to provide work for any reason so as to maintain quota ratios between
-the rest of the pools.
+mode and it will distribute quota back to priority pool 0 from any pools that
+are unable to provide work for any reason so as to maintain quota ratios
+between the rest of the pools.
 
 BALANCE:
 This strategy monitors the amount of difficulty 1 shares solved for each pool
diff --git a/api.c b/api.c
index cc769ab..e962bb0 100644
--- a/api.c
+++ b/api.c
@@ -2661,6 +2661,7 @@ static void poolquota(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
 	}
 
 	pool->quota = quota;
+	adjust_quota_gcd();
 	message(io_data, MSG_SETQUOTA, quota, pool->rpc_url, isjson);
 }
 
diff --git a/cgminer.c b/cgminer.c
index 5c5d1f9..de5c6f4 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -100,6 +100,7 @@ int opt_scantime = -1;
 int opt_expiry = 120;
 static const bool opt_time = true;
 unsigned long long global_hashrate;
+unsigned long global_quota_gcd = 1;
 
 #if defined(HAVE_OPENCL) || defined(USE_USBUTILS)
 int nDevs;
@@ -488,6 +489,47 @@ static char *getwork_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\
 
 static char *gbt_req = "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n";
 
+/* Adjust all the pools' quota to the greatest common denominator after a pool
+ * has been added or the quotas changed. */
+void adjust_quota_gcd(void)
+{
+	unsigned long gcd, lowest_quota = ~0UL, quota;
+	struct pool *pool;
+	int i;
+
+	for (i = 0; i < total_pools; i++) {
+		pool = pools[i];
+		quota = pool->quota;
+		if (!quota)
+			continue;
+		if (quota < lowest_quota)
+			lowest_quota = quota;
+	}
+
+	if (likely(lowest_quota < ~0UL)) {
+		gcd = lowest_quota;
+		for (i = 0; i < total_pools; i++) {
+			pool = pools[i];
+			quota = pool->quota;
+			if (!quota)
+				continue;
+			while (quota % gcd)
+				gcd--;
+		}
+	} else
+		gcd = 1;
+
+	for (i = 0; i < total_pools; i++) {
+		pool = pools[i];
+		pool->quota_used *= global_quota_gcd;
+		pool->quota_used /= gcd;
+		pool->quota_gcd = pool->quota / gcd;
+	}
+
+	global_quota_gcd = gcd;
+	applog(LOG_DEBUG, "Global quota greatest common denominator set to %lu", gcd);
+}
+
 /* Return value is ignored if not called from add_pool_details */
 struct pool *add_pool(void)
 {
@@ -513,6 +555,7 @@ struct pool *add_pool(void)
 	pool->rpc_req = getwork_req;
 	pool->rpc_proxy = NULL;
 	pool->quota = 1;
+	adjust_quota_gcd();
 
 	return pool;
 }
@@ -759,6 +802,7 @@ static char *set_quota(char *arg)
 	setup_url(pool, url);
 	pool->quota = quota;
 	applog(LOG_INFO, "Setting pool %d to quota %d", pool->pool_no, pool->quota);
+	adjust_quota_gcd();
 
 	return NULL;
 }
@@ -2840,16 +2884,16 @@ static inline struct pool *select_pool(bool lagging)
 	tested = 0;
 	while (!pool && tested++ < total_pools) {
 		pool = pools[rotating_pool];
-		if (pool->quota_used++ >= pool->quota) {
+		if (pool->quota_used++ >= pool->quota_gcd) {
 			pool->quota_used = 0;
 			pool = NULL;
 		} else {
 			if (!pool_unworkable(pool))
 				break;
 			/* Failover-only flag for load-balance means distribute
-			 * unused quota to pool 0. */
+			 * unused quota to priority pool 0. */
 			if (opt_fail_only)
-				pools[0]->quota++;
+				priority_pool(0)->quota_used--;
 		}
 		pool = NULL;
 		if (++rotating_pool >= total_pools)
@@ -4547,6 +4591,7 @@ retry:
 			goto retry;
 		}
 		pool->quota = selected;
+		adjust_quota_gcd();
 		goto updated;
 	} else if (!strncasecmp(&input, "f", 1)) {
 		opt_fail_only ^= true;
diff --git a/miner.h b/miner.h
index 4fc863b..2f5fc66 100644
--- a/miner.h
+++ b/miner.h
@@ -973,6 +973,7 @@ extern int enabled_pools;
 extern void get_intrange(char *arg, int *val1, int *val2);
 extern bool detect_stratum(struct pool *pool, char *url);
 extern void print_summary(void);
+extern void adjust_quota_gcd(void);
 extern struct pool *add_pool(void);
 extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
 
@@ -1121,6 +1122,7 @@ struct pool {
 	int diff1;
 	char diff[8];
 	int quota;
+	int quota_gcd;
 	int quota_used;
 
 	double diff_accepted;