@ -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 loa d balance " ) ,
" Change multipool strategy from failover to efficiency base d 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 ;
}
}