|
@@ -78,6 +78,7 @@ struct strategies strategies[] = {
|
|
|
{ "Round Robin" },
|
|
{ "Round Robin" },
|
|
|
{ "Rotate" },
|
|
{ "Rotate" },
|
|
|
{ "Load Balance" },
|
|
{ "Load Balance" },
|
|
|
|
|
+ { "Balance" },
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static char packagename[255];
|
|
static char packagename[255];
|
|
@@ -513,6 +514,12 @@ static char *set_devices(char *arg)
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static char *set_balance(enum pool_strategy *strategy)
|
|
|
|
|
+{
|
|
|
|
|
+ *strategy = POOL_BALANCE;
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static char *set_loadbalance(enum pool_strategy *strategy)
|
|
static char *set_loadbalance(enum pool_strategy *strategy)
|
|
|
{
|
|
{
|
|
|
*strategy = POOL_LOADBALANCE;
|
|
*strategy = POOL_LOADBALANCE;
|
|
@@ -783,6 +790,9 @@ static struct opt_table opt_config_table[] = {
|
|
|
opt_set_bool, &opt_autoengine,
|
|
opt_set_bool, &opt_autoengine,
|
|
|
"Automatically adjust all GPU engine clock speeds to maintain a target temperature"),
|
|
"Automatically adjust all GPU engine clock speeds to maintain a target temperature"),
|
|
|
#endif
|
|
#endif
|
|
|
|
|
+ OPT_WITHOUT_ARG("--balance",
|
|
|
|
|
+ set_balance, &pool_strategy,
|
|
|
|
|
+ "Change multipool strategy from failover to even share balance"),
|
|
|
OPT_WITHOUT_ARG("--benchmark",
|
|
OPT_WITHOUT_ARG("--benchmark",
|
|
|
opt_set_bool, &opt_benchmark,
|
|
opt_set_bool, &opt_benchmark,
|
|
|
"Run cgminer in benchmark mode - produces no shares"),
|
|
"Run cgminer in benchmark mode - produces no shares"),
|
|
@@ -889,7 +899,7 @@ static struct opt_table opt_config_table[] = {
|
|
|
#endif
|
|
#endif
|
|
|
OPT_WITHOUT_ARG("--load-balance",
|
|
OPT_WITHOUT_ARG("--load-balance",
|
|
|
set_loadbalance, &pool_strategy,
|
|
set_loadbalance, &pool_strategy,
|
|
|
- "Change multipool strategy from failover to even load balance"),
|
|
|
|
|
|
|
+ "Change multipool strategy from failover to efficiency based balance"),
|
|
|
OPT_WITH_ARG("--log|-l",
|
|
OPT_WITH_ARG("--log|-l",
|
|
|
set_int_0_to_9999, opt_show_intval, &opt_log_interval,
|
|
set_int_0_to_9999, opt_show_intval, &opt_log_interval,
|
|
|
"Interval in seconds between log output"),
|
|
"Interval in seconds between log output"),
|
|
@@ -1455,7 +1465,7 @@ static void curses_print_status(void)
|
|
|
global_queued(), total_staged(), total_stale, total_discarded, new_blocks,
|
|
global_queued(), total_staged(), total_stale, total_discarded, new_blocks,
|
|
|
local_work, total_go, total_ro);
|
|
local_work, total_go, total_ro);
|
|
|
wclrtoeol(statuswin);
|
|
wclrtoeol(statuswin);
|
|
|
- if (pool_strategy == POOL_LOADBALANCE && total_pools > 1)
|
|
|
|
|
|
|
+ if ((pool_strategy == POOL_LOADBALANCE || pool_strategy == POOL_BALANCE) && total_pools > 1)
|
|
|
mvwprintw(statuswin, 4, 0, " Connected to multiple pools with%s LP",
|
|
mvwprintw(statuswin, 4, 0, " Connected to multiple pools with%s LP",
|
|
|
have_longpoll ? "": "out");
|
|
have_longpoll ? "": "out");
|
|
|
else
|
|
else
|
|
@@ -1905,6 +1915,31 @@ out_nofree:
|
|
|
static const char *rpc_req =
|
|
static const char *rpc_req =
|
|
|
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
|
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
|
|
|
|
|
|
|
|
|
+/* In balanced mode, the amount of diff1 solutions per pool is monitored as a
|
|
|
|
|
+ * rolling average per 10 minutes and if pools start getting more, it biases
|
|
|
|
|
+ * away from them to distribute work evenly. The share count is reset to the
|
|
|
|
|
+ * rolling average every 10 minutes to not send all work to one pool after it
|
|
|
|
|
+ * has been disabled/out for an extended period. */
|
|
|
|
|
+static struct pool *select_balanced(struct pool *cp)
|
|
|
|
|
+{
|
|
|
|
|
+ int i, lowest = cp->shares;
|
|
|
|
|
+ struct pool *ret = cp;
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < total_pools; i++) {
|
|
|
|
|
+ struct pool *pool = pools[i];
|
|
|
|
|
+
|
|
|
|
|
+ if (pool->idle || pool->enabled != POOL_ENABLED)
|
|
|
|
|
+ continue;
|
|
|
|
|
+ if (pool->shares < lowest) {
|
|
|
|
|
+ lowest = pool->shares;
|
|
|
|
|
+ ret = pool;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ret->shares++;
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* Select any active pool in a rotating fashion when loadbalance is chosen */
|
|
/* Select any active pool in a rotating fashion when loadbalance is chosen */
|
|
|
static inline struct pool *select_pool(bool lagging)
|
|
static inline struct pool *select_pool(bool lagging)
|
|
|
{
|
|
{
|
|
@@ -1913,6 +1948,9 @@ static inline struct pool *select_pool(bool lagging)
|
|
|
|
|
|
|
|
cp = current_pool();
|
|
cp = current_pool();
|
|
|
|
|
|
|
|
|
|
+ if (pool_strategy == POOL_BALANCE)
|
|
|
|
|
+ return select_balanced(cp);
|
|
|
|
|
+
|
|
|
if (pool_strategy != POOL_LOADBALANCE && (!lagging || opt_fail_only))
|
|
if (pool_strategy != POOL_LOADBALANCE && (!lagging || opt_fail_only))
|
|
|
pool = cp;
|
|
pool = cp;
|
|
|
else
|
|
else
|
|
@@ -2248,7 +2286,7 @@ static inline bool should_roll(struct work *work)
|
|
|
struct timeval now;
|
|
struct timeval now;
|
|
|
time_t expiry;
|
|
time_t expiry;
|
|
|
|
|
|
|
|
- if (work->pool != current_pool() && pool_strategy != POOL_LOADBALANCE)
|
|
|
|
|
|
|
+ if (work->pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE)
|
|
|
return false;
|
|
return false;
|
|
|
|
|
|
|
|
if (work->rolltime > opt_scantime)
|
|
if (work->rolltime > opt_scantime)
|
|
@@ -2468,7 +2506,8 @@ static bool stale_work(struct work *work, bool share)
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (opt_fail_only && !share && pool != current_pool() && !work->mandatory) {
|
|
|
|
|
|
|
+ if (opt_fail_only && !share && pool != current_pool() && !work->mandatory &&
|
|
|
|
|
+ pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
|
|
|
applog(LOG_DEBUG, "Work stale due to fail only pool mismatch");
|
|
applog(LOG_DEBUG, "Work stale due to fail only pool mismatch");
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
@@ -2609,6 +2648,7 @@ void switch_pools(struct pool *selected)
|
|
|
|
|
|
|
|
switch (pool_strategy) {
|
|
switch (pool_strategy) {
|
|
|
/* Both of these set to the master pool */
|
|
/* Both of these set to the master pool */
|
|
|
|
|
+ case POOL_BALANCE:
|
|
|
case POOL_FAILOVER:
|
|
case POOL_FAILOVER:
|
|
|
case POOL_LOADBALANCE:
|
|
case POOL_LOADBALANCE:
|
|
|
for (i = 0; i < total_pools; i++) {
|
|
for (i = 0; i < total_pools; i++) {
|
|
@@ -3171,6 +3211,8 @@ void write_config(FILE *fcfg)
|
|
|
|
|
|
|
|
/* Special case options */
|
|
/* Special case options */
|
|
|
fprintf(fcfg, ",\n\"shares\" : \"%d\"", opt_shares);
|
|
fprintf(fcfg, ",\n\"shares\" : \"%d\"", opt_shares);
|
|
|
|
|
+ if (pool_strategy == POOL_BALANCE)
|
|
|
|
|
+ fputs(",\n\"balance\" : true", fcfg);
|
|
|
if (pool_strategy == POOL_LOADBALANCE)
|
|
if (pool_strategy == POOL_LOADBALANCE)
|
|
|
fputs(",\n\"load-balance\" : true", fcfg);
|
|
fputs(",\n\"load-balance\" : true", fcfg);
|
|
|
if (pool_strategy == POOL_ROUNDROBIN)
|
|
if (pool_strategy == POOL_ROUNDROBIN)
|
|
@@ -4160,6 +4202,8 @@ bool test_nonce(struct work *work, uint32_t nonce)
|
|
|
|
|
|
|
|
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
|
|
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
|
|
|
{
|
|
{
|
|
|
|
|
+ work->pool->diff1++;
|
|
|
|
|
+
|
|
|
/* Do one last check before attempting to submit the work */
|
|
/* Do one last check before attempting to submit the work */
|
|
|
/* Side effect: sets work->data for us */
|
|
/* Side effect: sets work->data for us */
|
|
|
if (!test_nonce(work, nonce)) {
|
|
if (!test_nonce(work, nonce)) {
|
|
@@ -4447,10 +4491,10 @@ static struct pool *select_longpoll_pool(struct pool *cp)
|
|
|
*/
|
|
*/
|
|
|
static void wait_lpcurrent(struct pool *pool)
|
|
static void wait_lpcurrent(struct pool *pool)
|
|
|
{
|
|
{
|
|
|
- if (pool->enabled == POOL_REJECTING || pool_strategy == POOL_LOADBALANCE)
|
|
|
|
|
|
|
+ if (pool->enabled == POOL_REJECTING || pool_strategy == POOL_LOADBALANCE || pool_strategy == POOL_BALANCE)
|
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
- while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE) {
|
|
|
|
|
|
|
+ while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
|
|
|
mutex_lock(&lp_lock);
|
|
mutex_lock(&lp_lock);
|
|
|
pthread_cond_wait(&lp_cond, &lp_lock);
|
|
pthread_cond_wait(&lp_cond, &lp_lock);
|
|
|
mutex_unlock(&lp_lock);
|
|
mutex_unlock(&lp_lock);
|
|
@@ -4588,12 +4632,16 @@ static void reap_curl(struct pool *pool)
|
|
|
|
|
|
|
|
static void *watchpool_thread(void __maybe_unused *userdata)
|
|
static void *watchpool_thread(void __maybe_unused *userdata)
|
|
|
{
|
|
{
|
|
|
|
|
+ int intervals = 0;
|
|
|
|
|
+
|
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
|
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
|
|
|
|
|
|
|
|
while (42) {
|
|
while (42) {
|
|
|
struct timeval now;
|
|
struct timeval now;
|
|
|
int i;
|
|
int i;
|
|
|
|
|
|
|
|
|
|
+ if (++intervals > 20)
|
|
|
|
|
+ intervals = 0;
|
|
|
gettimeofday(&now, NULL);
|
|
gettimeofday(&now, NULL);
|
|
|
|
|
|
|
|
for (i = 0; i < total_pools; i++) {
|
|
for (i = 0; i < total_pools; i++) {
|
|
@@ -4610,6 +4658,15 @@ static void *watchpool_thread(void __maybe_unused *userdata)
|
|
|
if (pool_active(pool, true) && pool_tclear(pool, &pool->idle))
|
|
if (pool_active(pool, true) && pool_tclear(pool, &pool->idle))
|
|
|
pool_resus(pool);
|
|
pool_resus(pool);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /* Get a rolling utility per pool over 10 mins */
|
|
|
|
|
+ if (intervals > 19) {
|
|
|
|
|
+ int shares = pool->diff1 - pool->last_shares;
|
|
|
|
|
+
|
|
|
|
|
+ pool->last_shares = pool->diff1;
|
|
|
|
|
+ pool->utility = (pool->utility + (double)shares * 0.63) / 1.63;
|
|
|
|
|
+ pool->shares = pool->utility;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (pool_strategy == POOL_ROTATE && now.tv_sec - rotate_tv.tv_sec > 60 * opt_rotate_period) {
|
|
if (pool_strategy == POOL_ROTATE && now.tv_sec - rotate_tv.tv_sec > 60 * opt_rotate_period) {
|
|
@@ -4618,6 +4675,7 @@ static void *watchpool_thread(void __maybe_unused *userdata)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
sleep(30);
|
|
sleep(30);
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|