From c2131df6aa70f0f031234de9a82ac0e75e3254b1 Mon Sep 17 00:00:00 2001 From: Jan Berdajs Date: Sun, 23 Mar 2014 07:25:55 +0100 Subject: [PATCH] add support for setting algorithm/nfactor for each pool separately, and fix bugged OpenCL thread cleanup (thread shutdown) --- algorithm.c | 5 ++ algorithm.h | 4 ++ api.c | 4 +- doc/configuration.md | 6 ++ driver-opencl.c | 33 +++++++--- miner.h | 10 +-- ocl.c | 12 ++-- ocl.h | 2 +- scrypt.c | 96 ++++------------------------ scrypt.h | 2 +- sgminer.c | 148 +++++++++++++++++++++++++++++++++++++------ 11 files changed, 195 insertions(+), 127 deletions(-) diff --git a/algorithm.c b/algorithm.c index cf09f60c..c823d1c5 100644 --- a/algorithm.c +++ b/algorithm.c @@ -33,3 +33,8 @@ void set_algorithm_nfactor(algorithm_t* algo, const uint8_t nfactor) { return; } + +bool cmp_algorithm(algorithm_t* algo1, algorithm_t* algo2) { + return (strcmp(algo1->name, algo2->name) == 0) && + (algo1->nfactor == algo2->nfactor); +} diff --git a/algorithm.h b/algorithm.h index b6053994..3d5f973e 100644 --- a/algorithm.h +++ b/algorithm.h @@ -2,6 +2,7 @@ #define ALGORITHM_H #include +#include /* Describes the Scrypt parameters and hashing functions used to mine * a specific coin. @@ -18,4 +19,7 @@ void set_algorithm(algorithm_t* algo, const char* name); /* Set to specific N factor. */ void set_algorithm_nfactor(algorithm_t* algo, const uint8_t nfactor); +/* Compare two algorithm parameters */ +bool cmp_algorithm(algorithm_t* algo1, algorithm_t* algo2); + #endif /* ALGORITHM_H */ diff --git a/api.c b/api.c index 4caf65c4..775572be 100644 --- a/api.c +++ b/api.c @@ -2856,7 +2856,7 @@ static void minecoin(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may message(io_data, MSG_MINECOIN, 0, NULL, isjson); io_open = io_add(io_data, isjson ? COMSTR JSON_MINECOIN : _MINECOIN COMSTR); - root = api_add_string(root, "Hash Method", algorithm->name, false); + root = api_add_string(root, "Hash Method", get_devices(0)->algorithm.name, false); cg_rlock(&ch_lock); root = api_add_timeval(root, "Current Block Time", &block_timeval, true); @@ -4027,7 +4027,7 @@ die: pthread_cleanup_pop(true); free(apisock); - + if (opt_debug) applog(LOG_DEBUG, "API: terminating due to: %s", do_a_quit ? "QUIT" : (do_a_restart ? "RESTART" : (bye ? "BYE" : "UNKNOWN!"))); diff --git a/doc/configuration.md b/doc/configuration.md index 6654da30..1f6d3dbb 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -23,6 +23,9 @@ cryptocurrencies. * everything else - currently defaults to `scrypt`, subject to change without warning. +### pool-algorithm + +Allows choosing the algorithm for a specific pool. See `algorithm`. ### nfactor @@ -33,6 +36,9 @@ Overrides the default scrypt parameter N, specified as the factor of 2 *Default:* depends on `algorithm`; otherwise `10`. +### pool-nfactor + +Overrides the default scrypt parameter N for a specific pool. See `nfactor`. ## CLI-only options diff --git a/driver-opencl.c b/driver-opencl.c index a2a18d6c..6a8c2a07 100644 --- a/driver-opencl.c +++ b/driver-opencl.c @@ -283,7 +283,7 @@ char *set_gpu_threads(char *arg) for (i = device; i < MAX_GPUDEVICES; i++) gpus[i].threads = gpus[0].threads; } - + return NULL; } @@ -880,7 +880,7 @@ retry: // TODO: refactor intvar = curses_input("Set GPU scan intensity (d or " MIN_INTENSITY_STR " -> " - MAX_INTENSITY_STR ")"); + MAX_INTENSITY_STR ")"); if (!intvar) { wlogprint("Invalid input\n"); goto retry; @@ -937,14 +937,14 @@ retry: // TODO: refactor } else if (!strncasecmp(&input, "a", 1)) { int rawintensity; char *intvar; - + if (selected) selected = curses_int("Select GPU to change raw intensity on"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } - + intvar = curses_input("Set raw GPU scan intensity (" MIN_RAWINTENSITY_STR " -> " MAX_RAWINTENSITY_STR ")"); if (!intvar) { wlogprint("Invalid input\n"); @@ -1094,6 +1094,8 @@ select_cgpu: cgtime(&thr->sick); if (!pthread_cancel(thr->pth)) { applog(LOG_WARNING, "Thread %d still exists, killing it off", thr_id); + pthread_join(thr->pth, NULL); + thr->cgpu->drv->thread_shutdown(thr); } else applog(LOG_WARNING, "Thread %d no longer exists", thr_id); } @@ -1120,7 +1122,7 @@ select_cgpu: //free(clState); applog(LOG_INFO, "Reinit GPU thread %d", thr_id); - clStates[thr_id] = initCl(virtual_gpu, name, sizeof(name)); + clStates[thr_id] = initCl(virtual_gpu, name, sizeof(name), &cgpu->algorithm); if (!clStates[thr_id]) { applog(LOG_ERR, "Failed to reinit GPU thread %d", thr_id); goto select_cgpu; @@ -1186,6 +1188,7 @@ static void opencl_detect(bool hotplug) cgpu->threads = 1; #endif cgpu->virtual_gpu = i; + cgpu->algorithm = *default_algorithm; add_cgpu(cgpu); } @@ -1261,7 +1264,7 @@ static bool opencl_thread_prepare(struct thr_info *thr) strcpy(name, ""); applog(LOG_INFO, "Init GPU thread %i GPU %i virtual GPU %i", i, gpu, virtual_gpu); - clStates[i] = initCl(virtual_gpu, name, sizeof(name)); + clStates[i] = initCl(virtual_gpu, name, sizeof(name), &cgpu->algorithm); if (!clStates[i]) { #ifdef HAVE_CURSES if (use_curses) @@ -1443,15 +1446,25 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, return hashes; } +// Cleanup OpenCL memory on the GPU +// Note: This function is not thread-safe (clStates modification not atomic) static void opencl_thread_shutdown(struct thr_info *thr) { const int thr_id = thr->id; _clState *clState = clStates[thr_id]; + clStates[thr_id] = NULL; - clReleaseKernel(clState->kernel); - clReleaseProgram(clState->program); - clReleaseCommandQueue(clState->commandQueue); - clReleaseContext(clState->context); + if (clState) { + clFinish(clState->commandQueue); + clReleaseMemObject(clState->outputBuffer); + clReleaseMemObject(clState->CLbuffer0); + clReleaseMemObject(clState->padbuffer8); + clReleaseKernel(clState->kernel); + clReleaseProgram(clState->program); + clReleaseCommandQueue(clState->commandQueue); + clReleaseContext(clState->context); + free(clState); + } } struct device_drv opencl_drv = { diff --git a/miner.h b/miner.h index 9761ff23..5c71f210 100644 --- a/miner.h +++ b/miner.h @@ -241,7 +241,7 @@ enum drv_driver { /* Use DRIVER_PARSE_COMMANDS to generate extern device_drv prototypes */ #ifndef _MSC_VER DRIVER_PARSE_COMMANDS(DRIVER_PROTOTYPE) -#endif +#endif enum alive { LIFE_WELL, @@ -475,6 +475,7 @@ struct cgpu_info { cl_uint vwidth; size_t work_size; cl_ulong max_alloc; + algorithm_t algorithm; int opt_lg, lookup_gap; size_t opt_tc, thread_concurrency; @@ -548,7 +549,6 @@ struct thread_q { struct thr_info { int id; int device_thread; - bool primary_thread; pthread_t pth; cgsem_t sem; @@ -559,6 +559,7 @@ struct thr_info { struct timeval sick; bool pause; + bool paused; bool getwork; double rolling; @@ -1014,8 +1015,7 @@ extern int opt_queue; extern int opt_scantime; extern int opt_expiry; -extern char *opt_algorithm; -extern algorithm_t *algorithm; +extern algorithm_t *default_algorithm; extern cglock_t control_lock; extern pthread_mutex_t hash_lock; @@ -1219,6 +1219,8 @@ struct pool { proxytypes_t rpc_proxytype; char *rpc_proxy; + algorithm_t algorithm; + pthread_mutex_t pool_lock; cglock_t data_lock; diff --git a/ocl.c b/ocl.c index 1910dc10..4dc8aa83 100644 --- a/ocl.c +++ b/ocl.c @@ -31,6 +31,7 @@ #include #include "findnonce.h" +#include "algorithm.h" #include "ocl.h" /* FIXME: only here for global config vars, replace with configuration.h @@ -218,7 +219,7 @@ void patch_opcodes(char *w, unsigned remaining) applog(LOG_DEBUG, "Patched a total of %i BFI_INT instructions", patched); } -_clState *initCl(unsigned int gpu, char *name, size_t nameSize) +_clState *initCl(unsigned int gpu, char *name, size_t nameSize, algorithm_t *algorithm) { _clState *clState = (_clState *)calloc(1, sizeof(_clState)); bool patchbfi = false, prog_built = false; @@ -350,7 +351,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize) find = strstr(extensions, camo); if (find) clState->hasBitAlign = true; - + /* Check for OpenCL >= 1.0 support, needed for global offset parameter usage. */ char * devoclver = (char *)malloc(1024); const char * ocl10 = "OpenCL 1.0"; @@ -382,7 +383,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize) return NULL; } applog(LOG_DEBUG, "Max work group size reported %d", (int)(clState->max_work_size)); - + size_t compute_units = 0; status = clGetDeviceInfo(devices[gpu], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(size_t), (void *)&compute_units, NULL); if (status != CL_SUCCESS) { @@ -732,8 +733,9 @@ built: free(binaries); free(binary_sizes); - applog(LOG_NOTICE, "Initialising kernel %s with%s bitalign, %spatched BFI", - filename, clState->hasBitAlign ? "" : "out", patchbfi ? "" : "un"); + applog(LOG_NOTICE, "Initialising kernel %s with%s bitalign, %spatched BFI, nfactor %d, n %d", + filename, clState->hasBitAlign ? "" : "out", patchbfi ? "" : "un", + algorithm->nfactor, algorithm->n); if (!prog_built) { /* create a cl program executable for all the devices specified */ diff --git a/ocl.h b/ocl.h index edd3aaaf..8e3176b4 100644 --- a/ocl.h +++ b/ocl.h @@ -34,5 +34,5 @@ typedef struct { extern char *file_contents(const char *filename, int *length); extern int clDevicesNum(void); -extern _clState *initCl(unsigned int gpu, char *name, size_t nameSize); +extern _clState *initCl(unsigned int gpu, char *name, size_t nameSize, algorithm_t *algorithm); #endif /* __OCL_H__ */ diff --git a/scrypt.c b/scrypt.c index 3a48ea14..08c3fa03 100644 --- a/scrypt.c +++ b/scrypt.c @@ -204,7 +204,7 @@ PBKDF2_SHA256_80_128(const uint32_t * passwd, uint32_t * buf) uint32_t ihash[8]; uint32_t i; uint32_t pad[16]; - + static const uint32_t innerpad[11] = {0x00000080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xa0040000}; /* If Klen > 64, the key is really SHA256(K). */ @@ -237,7 +237,7 @@ PBKDF2_SHA256_80_128(const uint32_t * passwd, uint32_t * buf) for (i = 0; i < 4; i++) { uint32_t istate[8]; uint32_t ostate[8]; - + memcpy(istate, PShictx.state, 32); PShictx.buf[4] = i + 1; SHA256_Transform(istate, PShictx.buf, 0); @@ -259,7 +259,7 @@ PBKDF2_SHA256_80_128_32(const uint32_t * passwd, const uint32_t * salt, uint32_t /* Compute HMAC state after processing P and S. */ uint32_t pad[16]; - + static const uint32_t ihash_finalblk[16] = {0x00000001,0x80000000,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0x00000620}; /* If Klen > 64, the key is really SHA256(K). */ @@ -358,7 +358,7 @@ salsa20_8(uint32_t B[16], const uint32_t Bx[16]) * scratchpad size needs to be at least (bytes): * 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) */ -static void scrypt_n_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_t *ostate) +static void scrypt_n_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_t *ostate, uint32_t n) { uint32_t * V; uint32_t X[32]; @@ -372,7 +372,7 @@ static void scrypt_n_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_ PBKDF2_SHA256_80_128(input, X); - for (i = 0; i < algorithm->n; i += 2) { + for (i = 0; i < n; i += 2) { memcpy(&V[i * 32], X, 128); salsa20_8(&X[0], &X[16]); @@ -383,8 +383,8 @@ static void scrypt_n_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_ salsa20_8(&X[0], &X[16]); salsa20_8(&X[16], &X[0]); } - for (i = 0; i < algorithm->n; i += 2) { - j = X[16] & (algorithm->n-1); + for (i = 0; i < n; i += 2) { + j = X[16] & (n-1); p2 = (uint64_t *)(&V[j * 32]); for(k = 0; k < 16; k++) p1[k] ^= p2[k]; @@ -392,7 +392,7 @@ static void scrypt_n_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_ salsa20_8(&X[0], &X[16]); salsa20_8(&X[16], &X[0]); - j = X[16] & (algorithm->n-1); + j = X[16] & (n-1); p2 = (uint64_t *)(&V[j * 32]); for(k = 0; k < 16; k++) p1[k] ^= p2[k]; @@ -404,91 +404,19 @@ static void scrypt_n_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_ PBKDF2_SHA256_80_128_32(input, X, ostate); } -void scrypt_regenhash(struct work *work) +void scrypt_regenhash(struct work *work, uint32_t n) { uint32_t data[20]; char *scratchbuf; uint32_t *nonce = (uint32_t *)(work->data + 76); uint32_t *ohash = (uint32_t *)(work->hash); - + be32enc_vect(data, (const uint32_t *)work->data, 19); data[19] = htobe32(*nonce); - scratchbuf = (char *)alloca(algorithm->n * 128 + 512); - scrypt_n_1_1_256_sp(data, scratchbuf, ohash); + scratchbuf = (char *)alloca(n * 128 + 512); + scrypt_n_1_1_256_sp(data, scratchbuf, ohash, n); flip32(ohash, ohash); } static const uint32_t diff1targ = 0x0000ffff; - -/* Used externally as confirmation of correct OCL code */ -/* FIXME: find reference in git blame and see why it was present, remove if obsolete */ -/* -int scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce) -{ - uint32_t tmp_hash7, Htarg = le32toh(((const uint32_t *)ptarget)[7]); - uint32_t data[20], ohash[8]; - char *scratchbuf; - - be32enc_vect(data, (const uint32_t *)pdata, 19); - data[19] = htobe32(nonce); - scratchbuf = (char *)alloca(SCRATCHBUF_SIZE); - scrypt_n_1_1_256_sp(data, scratchbuf, ohash, algorithm->n); - tmp_hash7 = be32toh(ohash[7]); - - applog(LOG_DEBUG, "htarget %08lx diff1 %08lx hash %08lx", - (long unsigned int)Htarg, - (long unsigned int)diff1targ, - (long unsigned int)tmp_hash7); - if (tmp_hash7 > diff1targ) - return -1; - if (tmp_hash7 > Htarg) - return 0; - return 1; -} - -bool scanhash_scrypt(struct thr_info *thr, const unsigned char __maybe_unused *pmidstate, - unsigned char *pdata, unsigned char __maybe_unused *phash1, - unsigned char __maybe_unused *phash, const unsigned char *ptarget, - uint32_t max_nonce, uint32_t *last_nonce, uint32_t n) -{ - uint32_t *nonce = (uint32_t *)(pdata + 76); - char *scratchbuf; - uint32_t data[20]; - uint32_t tmp_hash7; - uint32_t Htarg = le32toh(((const uint32_t *)ptarget)[7]); - bool ret = false; - - be32enc_vect(data, (const uint32_t *)pdata, 19); - - scratchbuf = (char *)malloc(SCRATCHBUF_SIZE); - if (unlikely(!scratchbuf)) { - applog(LOG_ERR, "Failed to malloc scratchbuf in scanhash_scrypt"); - return ret; - } - - while(1) { - uint32_t ostate[8]; - - *nonce = ++n; - data[19] = htobe32(n); - scrypt_n_1_1_256_sp(data, scratchbuf, ostate, algorithm->n); - tmp_hash7 = be32toh(ostate[7]); - - if (unlikely(tmp_hash7 <= Htarg)) { - ((uint32_t *)pdata)[19] = htobe32(n); - *last_nonce = n; - ret = true; - break; - } - - if (unlikely((n >= max_nonce) || thr->work_restart)) { - *last_nonce = n; - break; - } - } - - free(scratchbuf);; - return ret; -} -*/ diff --git a/scrypt.h b/scrypt.h index d967f541..6382ae86 100644 --- a/scrypt.h +++ b/scrypt.h @@ -5,6 +5,6 @@ /* extern int scrypt_test(unsigned char *pdata, const unsigned char *ptarget, */ /* uint32_t nonce); */ -extern void scrypt_regenhash(struct work *work); +extern void scrypt_regenhash(struct work *work, uint32_t n); #endif /* SCRYPT_H */ diff --git a/sgminer.c b/sgminer.c index 3b053e93..85e8484d 100644 --- a/sgminer.c +++ b/sgminer.c @@ -98,8 +98,7 @@ int opt_queue = 1; int opt_scantime = 7; int opt_expiry = 28; -char *opt_algorithm; -algorithm_t *algorithm; +algorithm_t *default_algorithm; static const bool opt_time = true; unsigned long long global_hashrate; @@ -199,6 +198,9 @@ pthread_rwlock_t devices_lock; static pthread_mutex_t lp_lock; 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_cond_t restart_cond; @@ -536,6 +538,9 @@ struct pool *add_pool(void) buf[0] = '\0'; pool->name = strdup(buf); + /* Algorithm */ + pool->algorithm = *default_algorithm; + pools = (struct pool **)realloc(pools, sizeof(struct pool *) * (total_pools + 2)); pools[total_pools++] = pool; mutex_init(&pool->pool_lock); @@ -559,7 +564,7 @@ struct pool *add_pool(void) return pool; } -static struct pool* get_current_pool() +static struct pool* get_current_pool() { while ((json_array_index + 1) > total_pools) add_pool(); @@ -569,8 +574,8 @@ static struct pool* get_current_pool() add_pool(); return pools[total_pools - 1]; } - - return pools[json_array_index]; + + return pools[json_array_index]; } /* Pool variant of test and set */ @@ -769,10 +774,39 @@ static char *set_url(char *arg) 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) { struct pool *pool = get_current_pool(); - + applog(LOG_DEBUG, "Setting pool %i name to %s", pool->pool_no, arg); opt_set_charp(arg, &pool->name); @@ -1030,17 +1064,17 @@ static void load_temp_cutoffs() static char *set_algo(const char *arg) { - set_algorithm(algorithm, arg); - applog(LOG_INFO, "Set algorithm to %s", algorithm->name); + set_algorithm(default_algorithm, arg); + applog(LOG_INFO, "Set default algorithm to %s", default_algorithm->name); return NULL; } 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)", - algorithm->nfactor, algorithm->n); + default_algorithm->nfactor, default_algorithm->n); return NULL; } @@ -1392,6 +1426,12 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--url|-o", set_url, NULL, NULL, "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", set_user, NULL, NULL, "Username for bitcoin JSON-RPC server"), @@ -3779,7 +3819,6 @@ void switch_pools(struct pool *selected) mutex_lock(&lp_lock); pthread_cond_broadcast(&lp_cond); mutex_unlock(&lp_lock); - } void discard_work(struct work *work) @@ -4411,8 +4450,8 @@ void write_config(FILE *fcfg) } if (opt_removedisabled) fprintf(fcfg, ",\n\"remove-disabled\" : true"); - if (strcmp(algorithm->name, "scrypt") != 0) - fprintf(fcfg, ",\n\"algorithm\" : \"%s\"", json_escape(algorithm->name)); + if (strcmp(default_algorithm->name, "scrypt") != 0) + fprintf(fcfg, ",\n\"algorithm\" : \"%s\"", json_escape(default_algorithm->name)); if (opt_api_allow) fprintf(fcfg, ",\n\"api-allow\" : \"%s\"", json_escape(opt_api_allow)); 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); } +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 *work = NULL; @@ -6000,6 +6102,9 @@ struct work *get_work(struct thr_info *thr, const int thr_id) wake_gws(); } } + + get_work_prepare_thread(thr, work); + diff_t = time(NULL) - diff_t; /* 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 @@ -6080,7 +6185,7 @@ static void rebuild_nonce(struct work *work, uint32_t nonce) *work_nonce = htole32(nonce); - scrypt_regenhash(work); + scrypt_regenhash(work, work->pool->algorithm.n); } /* 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); mythr->rolling = mythr->cgpu->rolling = 0; applog(LOG_DEBUG, "Waiting on sem in miner thread"); + mythr->paused = true; cgsem_wait(&mythr->sem); applog(LOG_WARNING, "Thread %d being re-enabled", thr_id); + mythr->paused = false; drv->thread_enable(mythr); } @@ -6226,7 +6333,7 @@ static void hash_sole_work(struct thr_info *mythr) struct sgminer_stats *pool_stats; /* Try to cycle approximately 5 times before each log update */ 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}; uint32_t max_nonce = drv->can_limit_work(mythr); 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); } #endif - + /* Thread is disabled or waiting on getwork */ if (*denable == DEV_DISABLED || thr->getwork) continue; @@ -7737,7 +7844,7 @@ bool add_cgpu(struct cgpu_info *cgpu) { static struct _cgpu_devid_counter *devids = NULL; struct _cgpu_devid_counter *d; - + HASH_FIND_STR(devids, cgpu->drv->name, d); if (d) cgpu->device_id = ++d->lastid; @@ -7831,6 +7938,7 @@ int main(int argc, char *argv[]) rwlock_init(&netacc_lock); rwlock_init(&mining_thr_lock); rwlock_init(&devices_lock); + mutex_init(&algo_switch_lock); mutex_init(&lp_lock); if (unlikely(pthread_cond_init(&lp_cond, NULL))) @@ -7883,8 +7991,8 @@ int main(int argc, char *argv[]) #endif /* Default algorithm specified in algorithm.c ATM */ - algorithm = (algorithm_t *)alloca(sizeof(algorithm_t)); - set_algorithm(algorithm, "scrypt"); + default_algorithm = (algorithm_t *)alloca(sizeof(algorithm_t)); + set_algorithm(default_algorithm, "scrypt"); devcursor = 8; logstart = devcursor + 1; @@ -8180,7 +8288,7 @@ begin_bench: cgpu->rolling = cgpu->total_mhashes = 0; } - + cgtime(&total_tv_start); cgtime(&total_tv_end); get_datestamp(datestamp, sizeof(datestamp), &total_tv_start);