|
|
@ -98,8 +98,7 @@ int opt_queue = 1; |
|
|
|
int opt_scantime = 7; |
|
|
|
int opt_scantime = 7; |
|
|
|
int opt_expiry = 28; |
|
|
|
int opt_expiry = 28; |
|
|
|
|
|
|
|
|
|
|
|
char *opt_algorithm; |
|
|
|
algorithm_t *default_algorithm; |
|
|
|
algorithm_t *algorithm; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const bool opt_time = true; |
|
|
|
static const bool opt_time = true; |
|
|
|
unsigned long long global_hashrate; |
|
|
|
unsigned long long global_hashrate; |
|
|
@ -199,6 +198,9 @@ pthread_rwlock_t devices_lock; |
|
|
|
static pthread_mutex_t lp_lock; |
|
|
|
static pthread_mutex_t lp_lock; |
|
|
|
static pthread_cond_t lp_cond; |
|
|
|
static pthread_cond_t lp_cond; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static pthread_mutex_t algo_switch_lock; |
|
|
|
|
|
|
|
static pthread_t algo_switch_thr = 0; |
|
|
|
|
|
|
|
|
|
|
|
pthread_mutex_t restart_lock; |
|
|
|
pthread_mutex_t restart_lock; |
|
|
|
pthread_cond_t restart_cond; |
|
|
|
pthread_cond_t restart_cond; |
|
|
|
|
|
|
|
|
|
|
@ -536,6 +538,9 @@ struct pool *add_pool(void) |
|
|
|
buf[0] = '\0'; |
|
|
|
buf[0] = '\0'; |
|
|
|
pool->name = strdup(buf); |
|
|
|
pool->name = strdup(buf); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Algorithm */ |
|
|
|
|
|
|
|
pool->algorithm = *default_algorithm; |
|
|
|
|
|
|
|
|
|
|
|
pools = (struct pool **)realloc(pools, sizeof(struct pool *) * (total_pools + 2)); |
|
|
|
pools = (struct pool **)realloc(pools, sizeof(struct pool *) * (total_pools + 2)); |
|
|
|
pools[total_pools++] = pool; |
|
|
|
pools[total_pools++] = pool; |
|
|
|
mutex_init(&pool->pool_lock); |
|
|
|
mutex_init(&pool->pool_lock); |
|
|
@ -559,7 +564,7 @@ struct pool *add_pool(void) |
|
|
|
return pool; |
|
|
|
return pool; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct pool* get_current_pool() |
|
|
|
static struct pool* get_current_pool() |
|
|
|
{ |
|
|
|
{ |
|
|
|
while ((json_array_index + 1) > total_pools) |
|
|
|
while ((json_array_index + 1) > total_pools) |
|
|
|
add_pool(); |
|
|
|
add_pool(); |
|
|
@ -569,8 +574,8 @@ static struct pool* get_current_pool() |
|
|
|
add_pool(); |
|
|
|
add_pool(); |
|
|
|
return pools[total_pools - 1]; |
|
|
|
return pools[total_pools - 1]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return pools[json_array_index]; |
|
|
|
return pools[json_array_index]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Pool variant of test and set */ |
|
|
|
/* Pool variant of test and set */ |
|
|
@ -769,10 +774,39 @@ static char *set_url(char *arg) |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *set_pool_algorithm(char *arg) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct pool *pool; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while ((json_array_index + 1) > total_pools) |
|
|
|
|
|
|
|
add_pool(); |
|
|
|
|
|
|
|
pool = pools[json_array_index]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Setting pool %i algorithm to %s", pool->pool_no, arg); |
|
|
|
|
|
|
|
set_algorithm(&pool->algorithm, arg); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static char *set_pool_nfactor(char *arg) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct pool *pool; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while ((json_array_index + 1) > total_pools) |
|
|
|
|
|
|
|
add_pool(); |
|
|
|
|
|
|
|
pool = pools[json_array_index]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Setting pool %i N-factor to %s", pool->pool_no, arg); |
|
|
|
|
|
|
|
set_algorithm_nfactor(&pool->algorithm, (const uint8_t) atoi(arg)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char *set_poolname(char *arg) |
|
|
|
static char *set_poolname(char *arg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct pool *pool = get_current_pool(); |
|
|
|
struct pool *pool = get_current_pool(); |
|
|
|
|
|
|
|
|
|
|
|
applog(LOG_DEBUG, "Setting pool %i name to %s", pool->pool_no, arg); |
|
|
|
applog(LOG_DEBUG, "Setting pool %i name to %s", pool->pool_no, arg); |
|
|
|
opt_set_charp(arg, &pool->name); |
|
|
|
opt_set_charp(arg, &pool->name); |
|
|
|
|
|
|
|
|
|
|
@ -1030,17 +1064,17 @@ static void load_temp_cutoffs() |
|
|
|
|
|
|
|
|
|
|
|
static char *set_algo(const char *arg) |
|
|
|
static char *set_algo(const char *arg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
set_algorithm(algorithm, arg); |
|
|
|
set_algorithm(default_algorithm, arg); |
|
|
|
applog(LOG_INFO, "Set algorithm to %s", algorithm->name); |
|
|
|
applog(LOG_INFO, "Set default algorithm to %s", default_algorithm->name); |
|
|
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static char *set_nfactor(const char *arg) |
|
|
|
static char *set_nfactor(const char *arg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
set_algorithm_nfactor(algorithm, (uint8_t)atoi(arg)); |
|
|
|
set_algorithm_nfactor(default_algorithm, (const uint8_t) atoi(arg)); |
|
|
|
applog(LOG_INFO, "Set algorithm N-factor to %d (N to %d)", |
|
|
|
applog(LOG_INFO, "Set algorithm N-factor to %d (N to %d)", |
|
|
|
algorithm->nfactor, algorithm->n); |
|
|
|
default_algorithm->nfactor, default_algorithm->n); |
|
|
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
@ -1392,6 +1426,12 @@ static struct opt_table opt_config_table[] = { |
|
|
|
OPT_WITH_ARG("--url|-o", |
|
|
|
OPT_WITH_ARG("--url|-o", |
|
|
|
set_url, NULL, NULL, |
|
|
|
set_url, NULL, NULL, |
|
|
|
"URL for bitcoin JSON-RPC server"), |
|
|
|
"URL for bitcoin JSON-RPC server"), |
|
|
|
|
|
|
|
OPT_WITH_ARG("--pool-algorithm", |
|
|
|
|
|
|
|
set_pool_algorithm, NULL, NULL, |
|
|
|
|
|
|
|
"Set algorithm for pool"), |
|
|
|
|
|
|
|
OPT_WITH_ARG("--pool-nfactor", |
|
|
|
|
|
|
|
set_pool_nfactor, NULL, NULL, |
|
|
|
|
|
|
|
"Set N-factor for pool"), |
|
|
|
OPT_WITH_ARG("--user|-u", |
|
|
|
OPT_WITH_ARG("--user|-u", |
|
|
|
set_user, NULL, NULL, |
|
|
|
set_user, NULL, NULL, |
|
|
|
"Username for bitcoin JSON-RPC server"), |
|
|
|
"Username for bitcoin JSON-RPC server"), |
|
|
@ -3779,7 +3819,6 @@ void switch_pools(struct pool *selected) |
|
|
|
mutex_lock(&lp_lock); |
|
|
|
mutex_lock(&lp_lock); |
|
|
|
pthread_cond_broadcast(&lp_cond); |
|
|
|
pthread_cond_broadcast(&lp_cond); |
|
|
|
mutex_unlock(&lp_lock); |
|
|
|
mutex_unlock(&lp_lock); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void discard_work(struct work *work) |
|
|
|
void discard_work(struct work *work) |
|
|
@ -4411,8 +4450,8 @@ void write_config(FILE *fcfg) |
|
|
|
} |
|
|
|
} |
|
|
|
if (opt_removedisabled) |
|
|
|
if (opt_removedisabled) |
|
|
|
fprintf(fcfg, ",\n\"remove-disabled\" : true"); |
|
|
|
fprintf(fcfg, ",\n\"remove-disabled\" : true"); |
|
|
|
if (strcmp(algorithm->name, "scrypt") != 0) |
|
|
|
if (strcmp(default_algorithm->name, "scrypt") != 0) |
|
|
|
fprintf(fcfg, ",\n\"algorithm\" : \"%s\"", json_escape(algorithm->name)); |
|
|
|
fprintf(fcfg, ",\n\"algorithm\" : \"%s\"", json_escape(default_algorithm->name)); |
|
|
|
if (opt_api_allow) |
|
|
|
if (opt_api_allow) |
|
|
|
fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", json_escape(opt_api_allow)); |
|
|
|
fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", json_escape(opt_api_allow)); |
|
|
|
if (strcmp(opt_api_mcast_addr, API_MCAST_ADDR) != 0) |
|
|
|
if (strcmp(opt_api_mcast_addr, API_MCAST_ADDR) != 0) |
|
|
@ -5984,6 +6023,69 @@ static void gen_stratum_work(struct pool *pool, struct work *work) |
|
|
|
cgtime(&work->tv_staged); |
|
|
|
cgtime(&work->tv_staged); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void *switch_algo_thread(void *arg) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
algorithm_t *new_algo = (algorithm_t *) arg; |
|
|
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pthread_detach(pthread_self()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
applog(LOG_WARNING, "Switching algorithm to %s (%d)", |
|
|
|
|
|
|
|
new_algo->name, new_algo->nfactor); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: When threads are canceled, they may leak memory, for example
|
|
|
|
|
|
|
|
// the "work" variable in get_work.
|
|
|
|
|
|
|
|
rd_lock(&devices_lock); |
|
|
|
|
|
|
|
for (i = 0; i < total_devices; i++) { |
|
|
|
|
|
|
|
devices[i]->algorithm = *new_algo; |
|
|
|
|
|
|
|
reinit_device(devices[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
rd_unlock(&devices_lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wait for reinit_gpu to finish
|
|
|
|
|
|
|
|
while (42) { |
|
|
|
|
|
|
|
struct thread_q *tq = control_thr[gpur_thr_id].q; |
|
|
|
|
|
|
|
bool stop = false; |
|
|
|
|
|
|
|
mutex_lock(&tq->mutex); |
|
|
|
|
|
|
|
stop = list_empty(&tq->q); |
|
|
|
|
|
|
|
mutex_unlock(&tq->mutex); |
|
|
|
|
|
|
|
if (stop) break; |
|
|
|
|
|
|
|
usleep(50000); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(&algo_switch_lock); |
|
|
|
|
|
|
|
algo_switch_thr = 0; |
|
|
|
|
|
|
|
mutex_unlock(&algo_switch_lock); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void wait_to_die(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
mutex_unlock(&algo_switch_lock); |
|
|
|
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
|
|
|
|
|
|
|
sleep(60); |
|
|
|
|
|
|
|
applog(LOG_ERR, "Thread not canceled within 60 seconds"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void get_work_prepare_thread(struct thr_info *mythr, struct work *work) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct cgpu_info *cgpu = mythr->cgpu; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mutex_lock(&algo_switch_lock); |
|
|
|
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); |
|
|
|
|
|
|
|
if (!cmp_algorithm(&work->pool->algorithm, &cgpu->algorithm)) { |
|
|
|
|
|
|
|
// stage work back to queue, we cannot process it yet
|
|
|
|
|
|
|
|
stage_work(work); |
|
|
|
|
|
|
|
if (algo_switch_thr == 0) |
|
|
|
|
|
|
|
pthread_create(&algo_switch_thr, NULL, &switch_algo_thread, &work->pool->algorithm); |
|
|
|
|
|
|
|
wait_to_die(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
mutex_unlock(&algo_switch_lock); |
|
|
|
|
|
|
|
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct work *get_work(struct thr_info *thr, const int thr_id) |
|
|
|
struct work *get_work(struct thr_info *thr, const int thr_id) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct work *work = NULL; |
|
|
|
struct work *work = NULL; |
|
|
@ -6000,6 +6102,9 @@ struct work *get_work(struct thr_info *thr, const int thr_id) |
|
|
|
wake_gws(); |
|
|
|
wake_gws(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_work_prepare_thread(thr, work); |
|
|
|
|
|
|
|
|
|
|
|
diff_t = time(NULL) - diff_t; |
|
|
|
diff_t = time(NULL) - diff_t; |
|
|
|
/* Since this is a blocking function, we need to add grace time to
|
|
|
|
/* Since this is a blocking function, we need to add grace time to
|
|
|
|
* the device's last valid work to not make outages appear to be |
|
|
|
* the device's last valid work to not make outages appear to be |
|
|
@ -6080,7 +6185,7 @@ static void rebuild_nonce(struct work *work, uint32_t nonce) |
|
|
|
|
|
|
|
|
|
|
|
*work_nonce = htole32(nonce); |
|
|
|
*work_nonce = htole32(nonce); |
|
|
|
|
|
|
|
|
|
|
|
scrypt_regenhash(work); |
|
|
|
scrypt_regenhash(work, work->pool->algorithm.n); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* For testing a nonce against diff 1 */ |
|
|
|
/* For testing a nonce against diff 1 */ |
|
|
@ -6208,8 +6313,10 @@ static void mt_disable(struct thr_info *mythr, const int thr_id, |
|
|
|
applog(LOG_WARNING, "Thread %d being disabled", thr_id); |
|
|
|
applog(LOG_WARNING, "Thread %d being disabled", thr_id); |
|
|
|
mythr->rolling = mythr->cgpu->rolling = 0; |
|
|
|
mythr->rolling = mythr->cgpu->rolling = 0; |
|
|
|
applog(LOG_DEBUG, "Waiting on sem in miner thread"); |
|
|
|
applog(LOG_DEBUG, "Waiting on sem in miner thread"); |
|
|
|
|
|
|
|
mythr->paused = true; |
|
|
|
cgsem_wait(&mythr->sem); |
|
|
|
cgsem_wait(&mythr->sem); |
|
|
|
applog(LOG_WARNING, "Thread %d being re-enabled", thr_id); |
|
|
|
applog(LOG_WARNING, "Thread %d being re-enabled", thr_id); |
|
|
|
|
|
|
|
mythr->paused = false; |
|
|
|
drv->thread_enable(mythr); |
|
|
|
drv->thread_enable(mythr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -6226,7 +6333,7 @@ static void hash_sole_work(struct thr_info *mythr) |
|
|
|
struct sgminer_stats *pool_stats; |
|
|
|
struct sgminer_stats *pool_stats; |
|
|
|
/* Try to cycle approximately 5 times before each log update */ |
|
|
|
/* Try to cycle approximately 5 times before each log update */ |
|
|
|
const long cycle = opt_log_interval / 5 ? 5 : 1; |
|
|
|
const long cycle = opt_log_interval / 5 ? 5 : 1; |
|
|
|
const bool primary = (!mythr->device_thread) || mythr->primary_thread; |
|
|
|
const bool primary = mythr->device_thread == 0; |
|
|
|
struct timeval diff, sdiff, wdiff = {0, 0}; |
|
|
|
struct timeval diff, sdiff, wdiff = {0, 0}; |
|
|
|
uint32_t max_nonce = drv->can_limit_work(mythr); |
|
|
|
uint32_t max_nonce = drv->can_limit_work(mythr); |
|
|
|
int64_t hashes_done = 0; |
|
|
|
int64_t hashes_done = 0; |
|
|
@ -7174,7 +7281,7 @@ static void *watchdog_thread(void __maybe_unused *userdata) |
|
|
|
temp, fanpercent, fanspeed, engineclock, memclock, vddc, activity, powertune); |
|
|
|
temp, fanpercent, fanspeed, engineclock, memclock, vddc, activity, powertune); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* Thread is disabled or waiting on getwork */ |
|
|
|
/* Thread is disabled or waiting on getwork */ |
|
|
|
if (*denable == DEV_DISABLED || thr->getwork) |
|
|
|
if (*denable == DEV_DISABLED || thr->getwork) |
|
|
|
continue; |
|
|
|
continue; |
|
|
@ -7737,7 +7844,7 @@ bool add_cgpu(struct cgpu_info *cgpu) |
|
|
|
{ |
|
|
|
{ |
|
|
|
static struct _cgpu_devid_counter *devids = NULL; |
|
|
|
static struct _cgpu_devid_counter *devids = NULL; |
|
|
|
struct _cgpu_devid_counter *d; |
|
|
|
struct _cgpu_devid_counter *d; |
|
|
|
|
|
|
|
|
|
|
|
HASH_FIND_STR(devids, cgpu->drv->name, d); |
|
|
|
HASH_FIND_STR(devids, cgpu->drv->name, d); |
|
|
|
if (d) |
|
|
|
if (d) |
|
|
|
cgpu->device_id = ++d->lastid; |
|
|
|
cgpu->device_id = ++d->lastid; |
|
|
@ -7831,6 +7938,7 @@ int main(int argc, char *argv[]) |
|
|
|
rwlock_init(&netacc_lock); |
|
|
|
rwlock_init(&netacc_lock); |
|
|
|
rwlock_init(&mining_thr_lock); |
|
|
|
rwlock_init(&mining_thr_lock); |
|
|
|
rwlock_init(&devices_lock); |
|
|
|
rwlock_init(&devices_lock); |
|
|
|
|
|
|
|
mutex_init(&algo_switch_lock); |
|
|
|
|
|
|
|
|
|
|
|
mutex_init(&lp_lock); |
|
|
|
mutex_init(&lp_lock); |
|
|
|
if (unlikely(pthread_cond_init(&lp_cond, NULL))) |
|
|
|
if (unlikely(pthread_cond_init(&lp_cond, NULL))) |
|
|
@ -7883,8 +7991,8 @@ int main(int argc, char *argv[]) |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* Default algorithm specified in algorithm.c ATM */ |
|
|
|
/* Default algorithm specified in algorithm.c ATM */ |
|
|
|
algorithm = (algorithm_t *)alloca(sizeof(algorithm_t)); |
|
|
|
default_algorithm = (algorithm_t *)alloca(sizeof(algorithm_t)); |
|
|
|
set_algorithm(algorithm, "scrypt"); |
|
|
|
set_algorithm(default_algorithm, "scrypt"); |
|
|
|
|
|
|
|
|
|
|
|
devcursor = 8; |
|
|
|
devcursor = 8; |
|
|
|
logstart = devcursor + 1; |
|
|
|
logstart = devcursor + 1; |
|
|
@ -8180,7 +8288,7 @@ begin_bench: |
|
|
|
|
|
|
|
|
|
|
|
cgpu->rolling = cgpu->total_mhashes = 0; |
|
|
|
cgpu->rolling = cgpu->total_mhashes = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
cgtime(&total_tv_start); |
|
|
|
cgtime(&total_tv_start); |
|
|
|
cgtime(&total_tv_end); |
|
|
|
cgtime(&total_tv_end); |
|
|
|
get_datestamp(datestamp, sizeof(datestamp), &total_tv_start); |
|
|
|
get_datestamp(datestamp, sizeof(datestamp), &total_tv_start); |
|
|
|