From 3ae5f97b94c574e9be23ec6b6e5729a74dfff5d1 Mon Sep 17 00:00:00 2001 From: ystarnaud Date: Sat, 28 Jun 2014 00:54:17 -0400 Subject: [PATCH] Algorithm Switcher Update Updated Algorithm switcher to change on pool rather than on algorithm. This way if, for example, 2 pools use the same algorithm but different GPU settings, the settings will be applied when changing pool. Additionally: * Included a "common" algorithm type in API pool/profile listing. For example using "marucoin-mod" will return "X13", "darkcoin-mod" will return "X11", scrypt + nfactor != 10 will return "NScrypt", etc... * Added "kernel" config option to be backwards compatible with other miners' configs. * Added a few algorithm aliases: x11mod -> darkcoin-mod, x13mod -> marucoin-mod... * New config keyword: "includes", which holds an array of include files. This is to counter the JSON limitation not allowing multiple values with the same name, thus preventing inclusion of multiple files. --- algorithm.c | 71 +++- algorithm.h | 16 + api.c | 12 +- config_parser.c | 28 +- driver-opencl.c | 1 + miner.h | 37 +++ sgminer.c | 843 +++++++++++++++++++++++++++++------------------- 7 files changed, 654 insertions(+), 354 deletions(-) diff --git a/algorithm.c b/algorithm.c index 3edbc233..55443670 100644 --- a/algorithm.c +++ b/algorithm.c @@ -31,6 +31,21 @@ #include #include + + +const char *algorithm_type_str[] = { + "Unknown", + "Scrypt", + "NScrypt", + "X11", + "X13", + "Keccak", + "Quarkcoin", + "Twecoin", + "Fugue256", + "NIST" +}; + void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) { sph_sha256_context ctx_sha2; @@ -308,6 +323,7 @@ static cl_int queue_talkcoin_mod_kernel(struct __clState *clState, struct _dev_b typedef struct _algorithm_settings_t { const char *name; /* Human-readable identifier */ + algorithm_type_t type; //common algorithm type double diff_multiplier1; double diff_multiplier2; double share_diff_multiplier; @@ -329,7 +345,7 @@ typedef struct _algorithm_settings_t { static algorithm_settings_t algos[] = { // kernels starting from this will have difficulty calculated by using litecoin algorithm #define A_SCRYPT(a) \ - { a, 1, 65536, 65536, 0, 0, 0xFF, 0x0000ffff00000000ULL, 0xFFFFFFFFULL, 0x0000ffffUL, 0, -1, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, scrypt_regenhash, queue_scrypt_kernel, gen_hash, append_scrypt_compiler_options} + { a, ALGO_SCRYPT, 1, 65536, 65536, 0, 0, 0xFF, 0x0000ffff00000000ULL, 0xFFFFFFFFULL, 0x0000ffffUL, 0, -1, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, scrypt_regenhash, queue_scrypt_kernel, gen_hash, append_scrypt_compiler_options} A_SCRYPT( "ckolivas" ), A_SCRYPT( "alexkarnew" ), A_SCRYPT( "alexkarnold" ), @@ -340,7 +356,7 @@ static algorithm_settings_t algos[] = { // kernels starting from this will have difficulty calculated by using quarkcoin algorithm #define A_QUARK(a, b) \ - { a, 256, 256, 256, 0, 0, 0xFF, 0x000000ffff000000ULL, 0xFFFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, b, queue_sph_kernel, gen_hash, NULL} + { a, ALGO_QUARK, 256, 256, 256, 0, 0, 0xFF, 0x000000ffff000000ULL, 0xFFFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, b, queue_sph_kernel, gen_hash, NULL} A_QUARK( "quarkcoin", quarkcoin_regenhash), A_QUARK( "qubitcoin", qubitcoin_regenhash), A_QUARK( "animecoin", animecoin_regenhash), @@ -349,31 +365,31 @@ static algorithm_settings_t algos[] = { // kernels starting from this will have difficulty calculated by using bitcoin algorithm #define A_DARK(a, b) \ - { a, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, b, queue_sph_kernel, gen_hash, NULL} + { a, ALGO_X11, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, b, queue_sph_kernel, gen_hash, NULL} A_DARK( "darkcoin", darkcoin_regenhash), A_DARK( "inkcoin", inkcoin_regenhash), A_DARK( "myriadcoin-groestl", myriadcoin_groestl_regenhash), #undef A_DARK - { "twecoin", 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, twecoin_regenhash, queue_sph_kernel, sha256, NULL}, - { "maxcoin", 1, 256, 1, 4, 15, 0x0F, 0x00000000ffff0000ULL, 0xFFFFULL, 0x000000ffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, maxcoin_regenhash, queue_maxcoin_kernel, sha256, NULL}, - { "darkcoin-mod", 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 10, 8 * 16 * 4194304, 0, darkcoin_regenhash, queue_darkcoin_mod_kernel, gen_hash, NULL}, + { "twecoin", ALGO_TWE, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, twecoin_regenhash, queue_sph_kernel, sha256, NULL}, + { "maxcoin", ALGO_KECCAK, 1, 256, 1, 4, 15, 0x0F, 0x00000000ffff0000ULL, 0xFFFFULL, 0x000000ffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, maxcoin_regenhash, queue_maxcoin_kernel, sha256, NULL}, + { "darkcoin-mod", ALGO_X11, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 10, 8 * 16 * 4194304, 0, darkcoin_regenhash, queue_darkcoin_mod_kernel, gen_hash, NULL}, - { "marucoin", 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, marucoin_regenhash, queue_sph_kernel, gen_hash, append_hamsi_compiler_options}, - { "marucoin-mod", 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 12, 8 * 16 * 4194304, 0, marucoin_regenhash, queue_marucoin_mod_kernel, gen_hash, append_hamsi_compiler_options}, - { "marucoin-modold", 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 10, 8 * 16 * 4194304, 0, marucoin_regenhash, queue_marucoin_mod_old_kernel, gen_hash, append_hamsi_compiler_options}, + { "marucoin", ALGO_X13, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, marucoin_regenhash, queue_sph_kernel, gen_hash, append_hamsi_compiler_options}, + { "marucoin-mod", ALGO_X13, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 12, 8 * 16 * 4194304, 0, marucoin_regenhash, queue_marucoin_mod_kernel, gen_hash, append_hamsi_compiler_options}, + { "marucoin-modold", ALGO_X13, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 10, 8 * 16 * 4194304, 0, marucoin_regenhash, queue_marucoin_mod_old_kernel, gen_hash, append_hamsi_compiler_options}, - { "talkcoin-mod", 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 4, 8 * 16 * 4194304, 0, talkcoin_regenhash, queue_talkcoin_mod_kernel, gen_hash, NULL}, + { "talkcoin-mod", ALGO_NIST, 1, 1, 1, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 4, 8 * 16 * 4194304, 0, talkcoin_regenhash, queue_talkcoin_mod_kernel, gen_hash, NULL}, // kernels starting from this will have difficulty calculated by using fuguecoin algorithm #define A_FUGUE(a, b) \ - { a, 1, 256, 256, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, b, queue_sph_kernel, sha256, NULL} + { a, ALGO_FUGUE, 1, 256, 256, 0, 0, 0xFF, 0x00000000ffff0000ULL, 0xFFFFULL, 0x0000ffffUL, 0, 0, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, b, queue_sph_kernel, sha256, NULL} A_FUGUE( "fuguecoin", fuguecoin_regenhash), A_FUGUE( "groestlcoin", groestlcoin_regenhash), #undef A_FUGUE // Terminator (do not remove) - { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL} + { NULL, ALGO_UNK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL} }; void copy_algorithm_settings(algorithm_t* dest, const char* algo) @@ -381,10 +397,13 @@ void copy_algorithm_settings(algorithm_t* dest, const char* algo) algorithm_settings_t* src; // Find algorithm settings and copy - for (src = algos; src->name; src++) { - if (strcmp(src->name, algo) == 0) { + for (src = algos; src->name; src++) + { + if (strcmp(src->name, algo) == 0) + { strcpy(dest->name, src->name); - + dest->type = src->type; + dest->diff_multiplier1 = src->diff_multiplier1; dest->diff_multiplier2 = src->diff_multiplier2; dest->share_diff_multiplier = src->share_diff_multiplier; @@ -406,7 +425,8 @@ void copy_algorithm_settings(algorithm_t* dest, const char* algo) } // if not found - if (src->name == NULL) { + if (src->name == NULL) + { applog(LOG_WARNING, "Algorithm %s not found, using %s.", algo, algos->name); copy_algorithm_settings(dest, algos->name); } @@ -457,6 +477,25 @@ void set_algorithm_nfactor(algorithm_t* algo, const uint8_t nfactor) { algo->nfactor = nfactor; algo->n = (1 << nfactor); + + //adjust algo type accordingly + switch (algo->type) + { + case ALGO_SCRYPT: + //if nfactor isnt 10, switch to NSCRYPT + if(algo->nfactor != 10) + algo->type = ALGO_NSCRYPT; + break; + //nscrypt + case ALGO_NSCRYPT: + //if nfactor is 10, switch to SCRYPT + if(algo->nfactor == 10) + algo->type = ALGO_SCRYPT; + break; + //ignore rest + default: + break; + } } bool cmp_algorithm(algorithm_t* algo1, algorithm_t* algo2) diff --git a/algorithm.h b/algorithm.h index 4493613e..45549b4d 100644 --- a/algorithm.h +++ b/algorithm.h @@ -10,6 +10,21 @@ #include #include +typedef enum { + ALGO_UNK, + ALGO_SCRYPT, + ALGO_NSCRYPT, + ALGO_X11, + ALGO_X13, + ALGO_KECCAK, + ALGO_QUARK, + ALGO_TWE, + ALGO_FUGUE, + ALGO_NIST +} algorithm_type_t; + +extern const char *algorithm_type_str[]; + extern void gen_hash(const unsigned char *data, unsigned int len, unsigned char *hash); struct __clState; @@ -23,6 +38,7 @@ struct work; */ typedef struct _algorithm_t { char name[20]; /* Human-readable identifier */ + algorithm_type_t type; //algorithm type uint32_t n; /* N (CPU/Memory tradeoff parameter) */ uint8_t nfactor; /* Factor of N above (n = 2^nfactor) */ double diff_multiplier1; diff --git a/api.c b/api.c index 1b8328c3..92bd440f 100644 --- a/api.c +++ b/api.c @@ -31,6 +31,7 @@ #include "pool.h" #include "util.h" #include "pool.h" +#include "algorithm.h" #include "config_parser.h" @@ -1602,8 +1603,14 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m root = api_add_string(root, "Name", get_pool_name(pool), true); mutex_unlock(&pool->stratum_lock); root = api_add_escape(root, "URL", pool->rpc_url, false); - root = api_add_string(root, "Profile", pool->profile, false); - root = api_add_string(root, "Algorithm", pool->algorithm.name, false); + root = api_add_escape(root, "Profile", pool->profile, false); + root = api_add_escape(root, "Algorithm", pool->algorithm.name, false); + root = api_add_escape(root, "Algorithm Type", (char *)algorithm_type_str[pool->algorithm.type], false); + + //show nfactor for nscrypt + if(pool->algorithm.type == ALGO_NSCRYPT) + root = api_add_int(root, "Algorithm NFactor", (int *)&(pool->algorithm.nfactor), false); + root = api_add_string(root, "Description", pool->description, false); root = api_add_string(root, "Status", status, false); root = api_add_int(root, "Priority", &(pool->prio), false); @@ -1620,6 +1627,7 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m root = api_add_escape(root, "User", pool->rpc_user, false); root = api_add_time(root, "Last Share Time", &(pool->last_share_time), false); root = api_add_double(root, "Diff1 Shares", &(pool->diff1), false); + if (pool->rpc_proxy) { root = api_add_const(root, "Proxy Type", proxytype(pool->rpc_proxytype), false); root = api_add_escape(root, "Proxy", pool->rpc_proxy, false); diff --git a/config_parser.c b/config_parser.c index dccb7a54..0d5c1bd4 100644 --- a/config_parser.c +++ b/config_parser.c @@ -499,7 +499,8 @@ void parse_config_object(json_t *obj, const char *parentkey, bool fileconf, int { //char *err = NULL; const char *key; - json_t *val; + size_t idx; + json_t *val, *subval; json_object_foreach(obj, key, val) { @@ -509,6 +510,18 @@ void parse_config_object(json_t *obj, const char *parentkey, bool fileconf, int if(val && json_is_string(val)) load_config(json_string_value(val), parentkey, NULL); } + //process includes - multi include + else if(!strcasecmp(key, "includes")) + { + if(val && json_is_array(val)) + { + json_array_foreach(val, idx, subval) + { + if(subval && json_is_string(subval)) + load_config(json_string_value(subval), parentkey, NULL); + } + } + } else parse_config(val, key, parentkey, fileconf, parent_iteration); /* @@ -689,7 +702,7 @@ void load_default_profile() // ... and copy settings if(!empty_string(profile->algorithm.name)) - set_algorithm(&default_profile.algorithm, profile->algorithm.name); + default_profile.algorithm = profile->algorithm; if(!empty_string(profile->devices)) default_profile.devices = profile->devices; @@ -743,8 +756,10 @@ void apply_defaults() set_algorithm(&default_profile.algorithm, "scrypt"); //by default all unless specified - if (empty_string(default_profile.devices)) + if(empty_string(default_profile.devices)) default_profile.devices = strdup("all"); + + applog(LOG_DEBUG, "Default Devices = %s", default_profile.devices); set_devices((char *)default_profile.devices); //set raw intensity first @@ -1919,7 +1934,12 @@ void api_profile_list(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __ma root = api_add_escape(root, "Name", profile->name, true); root = api_add_bool(root, "IsDefault", &b, false); root = api_add_escape(root, "Algorithm", isnull((char *)profile->algorithm.name, ""), true); - root = api_add_int(root, "NFactor", (int *)&profile->algorithm.nfactor, false); + root = api_add_escape(root, "Algorithm Type", (char *)algorithm_type_str[profile->algorithm.type], false); + + //show nfactor for nscrypt + if(profile->algorithm.type == ALGO_NSCRYPT) + root = api_add_int(root, "Algorithm NFactor", (int *)&(profile->algorithm.nfactor), false); + root = api_add_escape(root, "LookupGap", isnull((char *)profile->lookup_gap, ""), true); root = api_add_escape(root, "Devices", isnull((char *)profile->devices, ""), true); root = api_add_escape(root, "Intensity", isnull((char *)profile->intensity, ""), true); diff --git a/driver-opencl.c b/driver-opencl.c index 8e24c2a8..66956862 100644 --- a/driver-opencl.c +++ b/driver-opencl.c @@ -1320,6 +1320,7 @@ static bool opencl_thread_init(struct thr_info *thr) static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work) { work->blk.work = work; + thr->pool_no = work->pool->pool_no; return true; } diff --git a/miner.h b/miner.h index b7a68263..46a05f36 100644 --- a/miner.h +++ b/miner.h @@ -321,9 +321,45 @@ struct gpu_adl { }; #endif +/*********************************** + * Switcher stuff + ****************************************/ #ifndef opt_isset #define opt_isset(opt, val) (((opt & val) == val)?1:0) #endif +#ifndef get_pool_setting + #define get_pool_setting(val, default_val) ((!empty_string(val))?val:((!empty_string(default_val))?default_val:"")) +#endif + +enum switcher_mode { + SWITCH_OFF, + SWITCH_ALGO, + SWITCH_POOL +}; + +extern int opt_switchmode; + +enum switcher_options { + SWITCHER_APPLY_NONE = 0x00, + SWITCHER_APPLY_ALGO = 0x01, + SWITCHER_APPLY_DEVICE = 0x02, + SWITCHER_APPLY_GT = 0x04, + SWITCHER_APPLY_LG = 0x08, + SWITCHER_APPLY_RAWINT = 0x10, + SWITCHER_APPLY_XINT = 0x20, + SWITCHER_APPLY_INT = 0x40, + SWITCHER_APPLY_INT8 = 0x80, + SWITCHER_APPLY_SHADER = 0x100, + SWITCHER_APPLY_TC = 0x200, + SWITCHER_APPLY_WORKSIZE = 0x400, + SWITCHER_APPLY_GPU_ENGINE = 0x800, + SWITCHER_APPLY_GPU_MEMCLOCK = 0x1000, + SWITCHER_APPLY_GPU_FAN = 0x2000, + SWITCHER_APPLY_GPU_POWERTUNE = 0x4000, + SWITCHER_APPLY_GPU_VDDC = 0x8000, + SWITCHER_SOFT_RESET = 0x4000000, + SWITCHER_HARD_RESET = 0x8000000 +}; enum gpu_adl_options { APPLY_ENGINE = 1, @@ -572,6 +608,7 @@ struct thr_info { struct thread_q *q; struct cgpu_info *cgpu; void *cgpu_data; + int pool_no; struct timeval last; struct timeval sick; diff --git a/sgminer.c b/sgminer.c index d19cb6d6..a5ad084d 100644 --- a/sgminer.c +++ b/sgminer.c @@ -332,6 +332,9 @@ enum pool_strategy pool_strategy = POOL_FAILOVER; int opt_rotate_period; static int total_urls; +//default mode apply algorithm/gpu settings when pool changes +int opt_switchmode = SWITCH_POOL; + static #ifndef HAVE_CURSES const @@ -730,17 +733,17 @@ void get_intrange(char *arg, int *val1, int *val2) char *set_devices(char *arg) { int i, val1 = 0, val2 = 0; - char *nextptr; - - if(*arg) + char *p, *nextptr; + + if(arg[0] != '\0') { - if (*arg == '?') + if(!strcasecmp(arg, "?")) { opt_display_devs = true; return NULL; } //all devices enabled - else if(*arg == '*' || !strcasecmp(arg, "all")) + else if(!strcasecmp(arg, "*") || !strcasecmp(arg, "all")) { applog(LOG_DEBUG, "set_devices(all)"); opt_devs_enabled = 0; @@ -752,33 +755,33 @@ char *set_devices(char *arg) applog(LOG_DEBUG, "set_devices(%s)", arg); - nextptr = strtok(arg, ","); - if (nextptr == NULL) - return "Invalid parameters for set devices"; - get_intrange(nextptr, &val1, &val2); - if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || - val1 > val2) { - return "Invalid value passed to set devices"; - } - - for (i = val1; i <= val2; i++) { - devices_enabled[i] = true; - opt_devs_enabled++; - } - - while ((nextptr = strtok(NULL, ",")) != NULL) { + p = strdup(arg); + nextptr = strtok(p, ","); + + do { + if (nextptr == NULL) + { + free(p); + return "Invalid parameters for set devices"; + } get_intrange(nextptr, &val1, &val2); - if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || - val1 > val2) { + + if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES || val1 > val2) + { + free(p); return "Invalid value passed to set devices"; } - - for (i = val1; i <= val2; i++) { + + for (i = val1; i <= val2; i++) + { devices_enabled[i] = true; opt_devs_enabled++; } - } + } while ((nextptr = strtok(NULL, ",")) != NULL); + applog(LOG_DEBUG, "set_devices(%s) done.", arg); + + free(p); return NULL; } @@ -1074,6 +1077,21 @@ static char *set_pool_state(char *arg) return NULL; } +static char *set_switcher_mode(char *arg) +{ + if(!strcasecmp(arg, "off")) + opt_switchmode = SWITCH_OFF; + else if(!strcasecmp(arg, "algorithm")) + opt_switchmode = SWITCH_ALGO; + else if(!strcasecmp(arg, "pool")) + opt_switchmode = SWITCH_POOL; + else + return NULL; + + applog(LOG_INFO, "Setting switcher mode to %s", arg); + return NULL; +} + static char *set_quota(char *arg) { char *semicolon = strchr(arg, ';'), *url; @@ -1320,7 +1338,7 @@ char *set_difficulty_multiplier(char *arg) /* These options are available from config file or commandline */ struct opt_table opt_config_table[] = { - OPT_WITH_ARG("--algorithm", + OPT_WITH_ARG("--algorithm|--kernel|-k", set_default_algorithm, NULL, NULL, "Set mining algorithm and most common defaults, default: scrypt"), OPT_WITH_ARG("--api-allow", @@ -1542,7 +1560,7 @@ struct opt_table opt_config_table[] = { OPT_WITH_ARG("--poolname", /* TODO: Backward compatibility, to be removed. */ set_poolname_deprecated, NULL, NULL, opt_hidden), - OPT_WITH_ARG("--pool-algorithm", + OPT_WITH_ARG("--pool-algorithm|--pool-kernel", set_pool_algorithm, NULL, NULL, "Set algorithm for pool"), OPT_WITH_ARG("--pool-device", @@ -1600,7 +1618,7 @@ struct opt_table opt_config_table[] = { set_pool_priority, NULL, NULL, "Pool priority"), - OPT_WITH_ARG("--profile-algorithm", + OPT_WITH_ARG("--profile-algorithm|--profile-kernel", set_profile_algorithm, NULL, NULL, "Set algorithm for profile"), OPT_WITH_ARG("--profile-device", @@ -1711,6 +1729,9 @@ struct opt_table opt_config_table[] = { OPT_WITH_ARG("--state|--pool-state", set_pool_state, NULL, NULL, "Specify pool state at startup (default: enabled)"), + OPT_WITH_ARG("--switcher-mode", + set_switcher_mode, NULL, NULL, + "Algorithm/gpu settings switcher mode."), #ifdef HAVE_SYSLOG_H OPT_WITHOUT_ARG("--syslog", opt_set_bool, &use_syslog, @@ -5988,10 +6009,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work) static void apply_initial_gpu_settings(struct pool *pool) { int i; + const char *opt; unsigned char options; //gpu adl options to apply unsigned int start_threads = mining_threads, //initial count of mining threads before we change devices needed_threads = 0; //number of mining threads needed after we change devices + applog(LOG_NOTICE, "Startup Pool No = %d", pool->pool_no); + //apply gpu settings rd_lock(&mining_thr_lock); @@ -6001,68 +6025,32 @@ static void apply_initial_gpu_settings(struct pool *pool) devices_enabled[i] = false; //assign pool devices if any - if(!empty_string(pool->devices)) - set_devices((char *)pool->devices); - //assign default devices if any - else if(!empty_string(default_profile.devices)) - set_devices((char *)default_profile.devices); + if(!empty_string((opt = get_pool_setting(pool->devices, ((!empty_string(default_profile.devices))?default_profile.devices:"all"))))) + set_devices((char *)opt); //lookup gap - if(!empty_string(pool->lookup_gap)) - set_lookup_gap((char *)pool->lookup_gap); - else if(!empty_string(default_profile.lookup_gap)) - set_lookup_gap((char *)default_profile.lookup_gap); - - //raw intensity from pool - if (!empty_string(pool->rawintensity)) - set_rawintensity(pool->rawintensity); - //raw intensity from default profile - else if(!empty_string(default_profile.rawintensity)) - set_rawintensity(default_profile.rawintensity); - //if no rawintensity is set try xintensity - else - { - //xintensity from pool - if (!empty_string(pool->xintensity)) - set_xintensity(pool->xintensity); - //xintensity from default profile - else if(!empty_string(default_profile.xintensity)) - set_xintensity(default_profile.xintensity); - //no xintensity set try intensity - else - { - //intensity from pool - if(!empty_string(pool->intensity)) - set_intensity(pool->intensity); - //intensity from defaults - else if(!empty_string(default_profile.intensity)) - set_intensity(default_profile.intensity); - //nothing set anywhere, use 8 - else - { - default_profile.intensity = strdup("8"); - set_intensity(default_profile.intensity); - } - } - } + if(!empty_string((opt = get_pool_setting(pool->lookup_gap, default_profile.lookup_gap)))) + set_lookup_gap((char *)opt); + + //set intensity + if(!empty_string((opt = get_pool_setting(pool->rawintensity, default_profile.rawintensity)))) + set_rawintensity((char *)opt); + else if(!empty_string((opt = get_pool_setting(pool->xintensity, default_profile.xintensity)))) + set_xintensity((char *)opt); + else if(!empty_string((opt = get_pool_setting(pool->intensity, ((!empty_string(default_profile.intensity))?default_profile.intensity:"8"))))) + set_intensity((char *)opt); //shaders - if (!empty_string(pool->shaders)) - set_shaders((char *)pool->shaders); - else if(!empty_string(default_profile.shaders)) - set_shaders((char *)default_profile.shaders); + if(!empty_string((opt = get_pool_setting(pool->shaders, default_profile.shaders)))) + set_shaders((char *)opt); //thread-concurrency - if (!empty_string(pool->thread_concurrency)) - set_thread_concurrency((char *)pool->thread_concurrency); - else if(!empty_string(default_profile.thread_concurrency)) - set_thread_concurrency((char *)default_profile.thread_concurrency); - + if(!empty_string((opt = get_pool_setting(pool->thread_concurrency, default_profile.thread_concurrency)))) + set_thread_concurrency((char *)opt); + //worksize - if (!empty_string(pool->worksize)) - set_worksize((char *)pool->worksize); - else if(!empty_string(default_profile.worksize)) - set_worksize((char *)default_profile.worksize); + if(!empty_string((opt = get_pool_setting(pool->worksize, default_profile.worksize)))) + set_worksize((char *)opt); //apply algorithm for (i = 0; i < nDevs; i++) @@ -6072,42 +6060,32 @@ static void apply_initial_gpu_settings(struct pool *pool) options = APPLY_ENGINE | APPLY_MEMCLOCK | APPLY_FANSPEED | APPLY_POWERTUNE | APPLY_VDDC; //GPU clock - if(!empty_string(pool->gpu_engine)) - set_gpu_engine(pool->gpu_engine); - else if(!empty_string(default_profile.gpu_engine)) - set_gpu_engine(default_profile.gpu_engine); + if(!empty_string((opt = get_pool_setting(pool->gpu_engine, default_profile.gpu_engine)))) + set_gpu_engine((char *)opt); else options ^= APPLY_ENGINE; //GPU memory clock - if(!empty_string(pool->gpu_memclock)) - set_gpu_memclock(pool->gpu_memclock); - else if(!empty_string(default_profile.gpu_memclock)) - set_gpu_memclock(default_profile.gpu_memclock); + if(!empty_string((opt = get_pool_setting(pool->gpu_memclock, default_profile.gpu_memclock)))) + set_gpu_memclock((char *)opt); else options ^= APPLY_MEMCLOCK; //GPU fans - if(!empty_string(pool->gpu_fan)) - set_gpu_fan(pool->gpu_fan); - else if(!empty_string(default_profile.gpu_fan)) - set_gpu_fan(default_profile.gpu_fan); + if(!empty_string((opt = get_pool_setting(pool->gpu_fan, default_profile.gpu_fan)))) + set_gpu_fan((char *)opt); else options ^= APPLY_FANSPEED; //GPU powertune - if(!empty_string(pool->gpu_powertune)) - set_gpu_powertune((char *)pool->gpu_powertune); - else if(!empty_string(default_profile.gpu_powertune)) - set_gpu_powertune((char *)default_profile.gpu_powertune); + if(!empty_string((opt = get_pool_setting(pool->gpu_powertune, default_profile.gpu_powertune)))) + set_gpu_powertune((char *)opt); else options ^= APPLY_POWERTUNE; //GPU vddc - if(!empty_string(pool->gpu_vddc)) - set_gpu_vddc((char *)pool->gpu_vddc); - else if(!empty_string(default_profile.gpu_vddc)) - set_gpu_vddc((char *)default_profile.gpu_vddc); + if(!empty_string((opt = get_pool_setting(pool->gpu_vddc, default_profile.gpu_vddc)))) + set_gpu_vddc((char *)opt); else options ^= APPLY_VDDC; @@ -6160,10 +6138,8 @@ static void apply_initial_gpu_settings(struct pool *pool) //recount the number of needed mining threads #ifdef HAVE_ADL - if(!empty_string(pool->gpu_threads)) - set_gpu_threads(pool->gpu_threads); - else if(!empty_string(default_profile.gpu_threads)) - set_gpu_threads(default_profile.gpu_threads); + if(!empty_string((opt = get_pool_setting(pool->gpu_threads, default_profile.gpu_threads)))) + set_gpu_threads((char *)opt); for (i = 0; i < total_devices; i++) needed_threads += devices[i]->threads; @@ -6181,23 +6157,189 @@ static void apply_initial_gpu_settings(struct pool *pool) restart_mining_threads(needed_threads); } +static unsigned long compare_pool_settings(struct pool *pool1, struct pool *pool2) +{ + unsigned int options = 0; + const char *opt1, *opt2; + + if(!pool1 || !pool2) + return 0; + + //compare algorithm + if(!cmp_algorithm(&pool1->algorithm, &pool2->algorithm)) + options |= (SWITCHER_APPLY_ALGO | SWITCHER_HARD_RESET); + + //compare pool devices + opt1 = get_pool_setting(pool1->devices, ((!empty_string(default_profile.devices))?default_profile.devices:"all")); + opt2 = get_pool_setting(pool2->devices, ((!empty_string(default_profile.devices))?default_profile.devices:"all")); + + //changing devices means a hard reset of mining threads + if(strcasecmp(opt1, opt2) != 0) + options |= (SWITCHER_APPLY_DEVICE | SWITCHER_HARD_RESET); + + //compare gpu threads + opt1 = get_pool_setting(pool1->gpu_threads, default_profile.gpu_threads); + opt2 = get_pool_setting(pool2->gpu_threads, default_profile.gpu_threads); + + //changing gpu threads means a hard reset of mining threads + if(strcasecmp(opt1, opt2) != 0) + options |= (SWITCHER_APPLY_GT | SWITCHER_HARD_RESET); + + //lookup gap + opt1 = get_pool_setting(pool1->lookup_gap, default_profile.lookup_gap); + opt2 = get_pool_setting(pool2->lookup_gap, default_profile.lookup_gap); + + //lookup gap means soft reset but only if hard reset isnt set + if(strcasecmp(opt1, opt2) != 0) + options |= (SWITCHER_APPLY_LG | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + + //intensities + opt1 = get_pool_setting(pool1->rawintensity, default_profile.rawintensity); + opt2 = get_pool_setting(pool2->rawintensity, default_profile.rawintensity); + + if(strcasecmp(opt1, opt2) != 0) + { + //intensity is soft reset + if(!empty_string(opt2)) + options |= (SWITCHER_APPLY_RAWINT | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + } + + //xintensity -- only if raw intensity not set + if(!opt_isset(options, SWITCHER_APPLY_RAWINT)) + { + opt1 = get_pool_setting(pool1->xintensity, default_profile.xintensity); + opt2 = get_pool_setting(pool2->xintensity, default_profile.xintensity); + + //if different... + if(strcasecmp(opt1, opt2) != 0) + { + //intensity is soft reset + if(!empty_string(opt2)) + options |= (SWITCHER_APPLY_XINT | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + } + } + + //intensity -- only if raw intensity and xintensity not set + if(!opt_isset(options, SWITCHER_APPLY_RAWINT) && !opt_isset(options, SWITCHER_APPLY_XINT)) + { + opt1 = get_pool_setting(pool1->intensity, default_profile.intensity); + opt2 = get_pool_setting(pool2->intensity, default_profile.intensity); + + //if different... + if(strcasecmp(opt1, opt2) != 0) + { + //intensity is soft reset + if(!empty_string(opt2)) + options |= (SWITCHER_APPLY_INT | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + //if blank, set default profile to intensity 8 and apply + else + options |= (SWITCHER_APPLY_INT8 | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + } + } + + //shaders + opt1 = get_pool_setting(pool1->shaders, default_profile.shaders); + opt2 = get_pool_setting(pool2->shaders, default_profile.shaders); + + if(strcasecmp(opt1, opt2) != 0) + { + //shaders is soft reset + if(!empty_string(opt2)) + options |= (SWITCHER_APPLY_SHADER | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + } + + //thread-concurrency + opt1 = get_pool_setting(pool1->thread_concurrency, default_profile.thread_concurrency); + opt2 = get_pool_setting(pool2->thread_concurrency, default_profile.thread_concurrency); + + //thread-concurrency is soft reset + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= (SWITCHER_APPLY_TC | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + + //worksize + opt1 = get_pool_setting(pool1->worksize, default_profile.worksize); + opt2 = get_pool_setting(pool2->worksize, default_profile.worksize); + + //worksize is soft reset + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= (SWITCHER_APPLY_WORKSIZE | ((!opt_isset(options, SWITCHER_HARD_RESET))?SWITCHER_SOFT_RESET:0)); + + #ifdef HAVE_ADL + //gpu-engine + opt1 = get_pool_setting(pool1->gpu_engine, default_profile.gpu_engine); + opt2 = get_pool_setting(pool2->gpu_engine, default_profile.gpu_engine); + + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= SWITCHER_APPLY_GPU_ENGINE; + + //gpu-memclock + opt1 = get_pool_setting(pool1->gpu_memclock, default_profile.gpu_memclock); + opt2 = get_pool_setting(pool2->gpu_memclock, default_profile.gpu_memclock); + + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= SWITCHER_APPLY_GPU_MEMCLOCK; + + //GPU fans + opt1 = get_pool_setting(pool1->gpu_fan, default_profile.gpu_fan); + opt2 = get_pool_setting(pool2->gpu_fan, default_profile.gpu_fan); + + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= SWITCHER_APPLY_GPU_FAN; + + //GPU powertune + opt1 = get_pool_setting(pool1->gpu_powertune, default_profile.gpu_powertune); + opt2 = get_pool_setting(pool2->gpu_powertune, default_profile.gpu_powertune); + + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= SWITCHER_APPLY_GPU_POWERTUNE; + + //GPU vddc + opt1 = get_pool_setting(pool1->gpu_vddc, default_profile.gpu_vddc); + opt2 = get_pool_setting(pool2->gpu_vddc, default_profile.gpu_vddc); + + if(strcasecmp(opt1, opt2) != 0 && !empty_string(opt2)) + options |= SWITCHER_APPLY_GPU_VDDC; + #endif + + return options; +} + static void get_work_prepare_thread(struct thr_info *mythr, struct work *work) { int i; int active_threads; //number of actual active threads int start_threads; //number of threads at start before devices enabled change - unsigned char options; //gpu adl options to apply + unsigned long options; + const char *opt; + + //if switcher is disabled + if(opt_switchmode == SWITCH_OFF) + return; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); mutex_lock(&algo_switch_lock); - if (cmp_algorithm(&work->pool->algorithm, &mythr->cgpu->algorithm) && (algo_switch_n == 0)) + //switcher mode - switch on algorithm change + if(opt_switchmode == SWITCH_ALGO) { - mutex_unlock(&algo_switch_lock); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - return; + if(cmp_algorithm(&work->pool->algorithm, &mythr->cgpu->algorithm) && (algo_switch_n == 0)) + { + mutex_unlock(&algo_switch_lock); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + return; + } } - + //switcher mode - switch on pool change + else if(opt_switchmode == SWITCH_POOL) + { + if((work->pool->pool_no == mythr->pool_no) && (algo_switch_n == 0)) + { + mutex_unlock(&algo_switch_lock); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + return; + } + } + algo_switch_n++; //get the number of active threads to know when to switch... if we only check total threads, we may wait for ever on a disabled GPU @@ -6207,260 +6349,286 @@ static void get_work_prepare_thread(struct thr_info *mythr, struct work *work) struct thr_info *thr = mining_thr[i]; if(thr->cgpu->deven != DEV_DISABLED) - active_threads ++; + active_threads++; } // If all threads are waiting now - if (algo_switch_n >= active_threads) + if(algo_switch_n >= active_threads) { start_threads = mining_threads; //use start_threads below - - bool soft_restart = !work->pool->gpu_threads; - rd_lock(&mining_thr_lock); - // Shutdown all threads first (necessary) - if (soft_restart) + + //compare pools to figure out what we need to apply, if options is 0, don't change anything... + if((options = compare_pool_settings(pools[mythr->pool_no], work->pool))) { - for (i = 0; i < start_threads; i++) + rd_lock(&mining_thr_lock); + + // Shutdown all threads first (necessary) + if(opt_isset(options, SWITCHER_SOFT_RESET)) { - struct thr_info *thr = mining_thr[i]; - thr->cgpu->drv->thread_shutdown(thr); + applog(LOG_DEBUG, "Soft Reset... Shutdown threads..."); + for (i = 0; i < start_threads; i++) + { + struct thr_info *thr = mining_thr[i]; + thr->cgpu->drv->thread_shutdown(thr); + } } - } - // Reset stats (e.g. for working_diff to be set properly in hash_sole_work) - zero_stats(); + // Reset stats (e.g. for working_diff to be set properly in hash_sole_work) + zero_stats(); - // Apply other pool-specific settings or revert to defaults - - //reset devices flags - opt_devs_enabled = 0; - for (i = 0; i < MAX_DEVICES; i++) - devices_enabled[i] = false; - - //assign pool devices if any - if(!empty_string(work->pool->devices)) - set_devices((char *)work->pool->devices); - //assign default devices if any - else if(!empty_string(default_profile.devices)) - set_devices((char *)default_profile.devices); - - //lookup gap - if(!empty_string(work->pool->lookup_gap)) - set_lookup_gap((char *)work->pool->lookup_gap); - else if(!empty_string(default_profile.lookup_gap)) - set_lookup_gap((char *)default_profile.lookup_gap); + //devices + if(opt_isset(options, SWITCHER_APPLY_DEVICE)) + { + //reset devices flags + opt_devs_enabled = 0; + for (i = 0; i < MAX_DEVICES; i++) + devices_enabled[i] = false; + + //assign pool devices if any + if(!empty_string((opt = get_pool_setting(work->pool->devices, ((!empty_string(default_profile.devices))?default_profile.devices:"all"))))) + set_devices((char *)opt); + } + + //lookup gap + if(opt_isset(options, SWITCHER_APPLY_LG)) + { + if(!empty_string((opt = get_pool_setting(work->pool->lookup_gap, default_profile.lookup_gap)))) + set_lookup_gap((char *)opt); + } - //raw intensity from pool - if (!empty_string(work->pool->rawintensity)) - set_rawintensity(work->pool->rawintensity); - //raw intensity from default profile - else if(!empty_string(default_profile.rawintensity)) - set_rawintensity(default_profile.rawintensity); - //if no rawintensity is set try xintensity - else - { - //xintensity from pool - if (!empty_string(work->pool->xintensity)) - set_xintensity(work->pool->xintensity); - //xintensity from default profile - else if(!empty_string(default_profile.xintensity)) - set_xintensity(default_profile.xintensity); - //no xintensity set try intensity - else + //raw intensity from pool + if(opt_isset(options, SWITCHER_APPLY_RAWINT)) { - //intensity from pool - if(!empty_string(work->pool->intensity)) - set_intensity(work->pool->intensity); - //intensity from defaults - else if(!empty_string(default_profile.intensity)) - set_intensity(default_profile.intensity); - //nothing set anywhere, use 8 - else - { - default_profile.intensity = strdup("8"); - set_intensity(default_profile.intensity); - } + if(!empty_string((opt = get_pool_setting(work->pool->rawintensity, default_profile.rawintensity)))) + set_rawintensity((char *)opt); + } + //xintensity + else if(opt_isset(options, SWITCHER_APPLY_XINT)) + { + if(!empty_string((opt = get_pool_setting(work->pool->xintensity, default_profile.xintensity)))) + set_xintensity((char *)opt); + } + //intensity + else if(opt_isset(options, SWITCHER_APPLY_INT)) + { + if(!empty_string((opt = get_pool_setting(work->pool->intensity, default_profile.intensity)))) + set_intensity((char *)opt); + } + //default basic intensity + else if(opt_isset(options, SWITCHER_APPLY_INT8)) + { + default_profile.intensity = strdup("8"); + set_intensity(default_profile.intensity); } - } - //shaders - if (!empty_string(work->pool->shaders)) - set_shaders((char *)work->pool->shaders); - else if(!empty_string(default_profile.shaders)) - set_shaders((char *)default_profile.shaders); - - //thread-concurrency - if (!empty_string(work->pool->thread_concurrency)) - set_thread_concurrency((char *)work->pool->thread_concurrency); - else if(!empty_string(default_profile.thread_concurrency)) - set_thread_concurrency((char *)default_profile.thread_concurrency); - - //worksize - if (!empty_string(work->pool->worksize)) - set_worksize((char *)work->pool->worksize); - else if(!empty_string(default_profile.worksize)) - set_worksize((char *)default_profile.worksize); - - #ifdef HAVE_ADL - options = APPLY_ENGINE | APPLY_MEMCLOCK | APPLY_FANSPEED | APPLY_POWERTUNE | APPLY_VDDC; - - //GPU clock - if(!empty_string(work->pool->gpu_engine)) - set_gpu_engine(work->pool->gpu_engine); - else if(!empty_string(default_profile.gpu_engine)) - set_gpu_engine(default_profile.gpu_engine); - else - options ^= APPLY_ENGINE; - - //GPU memory clock - if(!empty_string(work->pool->gpu_memclock)) - set_gpu_memclock(work->pool->gpu_memclock); - else if(!empty_string(default_profile.gpu_memclock)) - set_gpu_memclock(default_profile.gpu_memclock); - else - options ^= APPLY_MEMCLOCK; - - //GPU fans - if(!empty_string(work->pool->gpu_fan)) - set_gpu_fan(work->pool->gpu_fan); - else if(!empty_string(default_profile.gpu_fan)) - set_gpu_fan(default_profile.gpu_fan); - else - options ^= APPLY_FANSPEED; - - //GPU powertune - if(!empty_string(work->pool->gpu_powertune)) - set_gpu_powertune((char *)work->pool->gpu_powertune); - else if(!empty_string(default_profile.gpu_powertune)) - set_gpu_powertune((char *)default_profile.gpu_powertune); - else - options ^= APPLY_POWERTUNE; + //shaders + if(opt_isset(options, SWITCHER_APPLY_SHADER)) + { + if(!empty_string((opt = get_pool_setting(work->pool->shaders, default_profile.shaders)))) + set_shaders((char *)opt); + } - //GPU vddc - if(!empty_string(work->pool->gpu_vddc)) - set_gpu_vddc((char *)work->pool->gpu_vddc); - else if(!empty_string(default_profile.gpu_vddc)) - set_gpu_vddc((char *)default_profile.gpu_vddc); - else - options ^= APPLY_VDDC; + //thread-concurrency + if(opt_isset(options, SWITCHER_APPLY_TC)) + { + if(!empty_string((opt = get_pool_setting(work->pool->thread_concurrency, default_profile.thread_concurrency)))) + set_thread_concurrency((char *)opt); + } - //apply gpu settings - for (i = 0; i < nDevs; i++) + //worksize + if(opt_isset(options, SWITCHER_APPLY_WORKSIZE)) { - if(opt_isset(options, APPLY_ENGINE)) - set_engineclock(i, gpus[i].min_engine); - if(opt_isset(options, APPLY_MEMCLOCK)) - set_memoryclock(i, gpus[i].gpu_memclock); - if(opt_isset(options, APPLY_FANSPEED)) - set_fanspeed(i, gpus[i].min_fan); - if(opt_isset(options, APPLY_POWERTUNE)) - set_powertune(i, gpus[i].gpu_powertune); - if(opt_isset(options, APPLY_VDDC)) - set_vddc(i, gpus[i].gpu_vddc); + if(!empty_string((opt = get_pool_setting(work->pool->worksize, default_profile.worksize)))) + set_worksize((char *)opt); } - #endif - // Change algorithm for each thread (thread_prepare calls initCl) - for (i = 0; i < start_threads; i++) - { - struct thr_info *thr = mining_thr[i]; - thr->cgpu->algorithm = work->pool->algorithm; - if (soft_restart) + //apply algorithm + if(opt_isset(options, SWITCHER_APPLY_ALGO)) { - thr->cgpu->drv->thread_prepare(thr); - thr->cgpu->drv->thread_init(thr); + for (i = 0; i < nDevs; i++) + gpus[i].algorithm = work->pool->algorithm; } - // Necessary because algorithms can have dramatically different diffs - thr->cgpu->drv->working_diff = 1; - } - - rd_unlock(&mining_thr_lock); + #ifdef HAVE_ADL + //GPU clock + if(opt_isset(options, SWITCHER_APPLY_GPU_ENGINE)) + { + if(!empty_string((opt = get_pool_setting(work->pool->gpu_engine, default_profile.gpu_engine)))) + set_gpu_engine((char *)opt); + } + + //GPU memory clock + if(opt_isset(options, SWITCHER_APPLY_GPU_MEMCLOCK)) + { + if(!empty_string((opt = get_pool_setting(work->pool->gpu_memclock, default_profile.gpu_memclock)))) + set_gpu_memclock((char *)opt); + } - // Finish switching pools - algo_switch_n = 0; - mutex_unlock(&algo_switch_lock); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - // Hard restart (when gpu_threads is changed) - if (!soft_restart) - { - //enable/disable devices based on profile/pool/defaults - sgminer_id_count = 0; //reset sgminer_ids - mining_threads = 0; //mining threads gets added inside each enable_device() so reset - if(opt_devs_enabled) + //GPU fans + if(opt_isset(options, SWITCHER_APPLY_GPU_FAN)) + { + if(!empty_string((opt = get_pool_setting(work->pool->gpu_fan, default_profile.gpu_fan)))) + set_gpu_fan((char *)opt); + } + + //GPU powertune + if(opt_isset(options, SWITCHER_APPLY_GPU_POWERTUNE)) + { + if(!empty_string((opt = get_pool_setting(work->pool->gpu_powertune, default_profile.gpu_powertune)))) + set_gpu_powertune((char *)opt); + } + + //GPU vddc + if(opt_isset(options, SWITCHER_APPLY_GPU_VDDC)) + { + if(!empty_string((opt = get_pool_setting(work->pool->gpu_vddc, default_profile.gpu_vddc)))) + set_gpu_vddc((char *)opt); + } + + //apply gpu settings + for (i = 0; i < nDevs; i++) + { + if(opt_isset(options, SWITCHER_APPLY_GPU_ENGINE)) + set_engineclock(i, gpus[i].min_engine); + if(opt_isset(options, SWITCHER_APPLY_GPU_MEMCLOCK)) + set_memoryclock(i, gpus[i].gpu_memclock); + if(opt_isset(options, SWITCHER_APPLY_GPU_FAN)) + set_fanspeed(i, gpus[i].min_fan); + if(opt_isset(options, SWITCHER_APPLY_GPU_POWERTUNE)) + set_powertune(i, gpus[i].gpu_powertune); + if(opt_isset(options, SWITCHER_APPLY_GPU_VDDC)) + set_vddc(i, gpus[i].gpu_vddc); + } + #endif + + // Change algorithm for each thread (thread_prepare calls initCl) + if(opt_isset(options, SWITCHER_SOFT_RESET)) { - for (i = 0; i < MAX_DEVICES; i++) + struct thr_info *thr; + applog(LOG_DEBUG, "Soft Reset... Restarting threads..."); + + for (i = 0; i < start_threads; i++) { - //device should be enabled - if(devices_enabled[i] && i < total_devices) + thr = mining_thr[i]; + thr->pool_no = work->pool->pool_no; //set thread on new pool + + if(opt_isset(options, SWITCHER_SOFT_RESET)) { - applog(LOG_DEBUG, "Enabling device %d", i); - enable_device(devices[i]); + thr->cgpu->drv->thread_prepare(thr); + thr->cgpu->drv->thread_init(thr); } - else if(i < total_devices) + + // Necessary because algorithms can have dramatically different diffs + thr->cgpu->drv->working_diff = 1; + } + } + + rd_unlock(&mining_thr_lock); + + // Finish switching pools + algo_switch_n = 0; + mutex_unlock(&algo_switch_lock); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + // Hard restart if needed + if(opt_isset(options, SWITCHER_HARD_RESET)) + { + applog(LOG_DEBUG, "Hard Reset Mining Threads..."); + + //if devices changed... enable/disable as needed + if(opt_isset(options, SWITCHER_APPLY_DEVICE)) + { + sgminer_id_count = 0; //reset sgminer_ids + mining_threads = 0; //mining threads gets added inside each enable_device() so reset + if(opt_devs_enabled) { - applog(LOG_DEBUG, "Disabling device %d", i); - //if option is set to not remove disabled, enable device - if(!opt_removedisabled) + for (i = 0; i < MAX_DEVICES; i++) + { + //device should be enabled + if(devices_enabled[i] && i < total_devices) + enable_device(devices[i]); + else if(i < total_devices) + { + //if option is set to not remove disabled, enable device + if(!opt_removedisabled) + enable_device(devices[i]); + + //mark as disabled + devices[i]->deven = DEV_DISABLED; + } + } + } + //enable all devices + else + { + for (i = 0; i < total_devices; ++i) enable_device(devices[i]); - - //mark as disabled - devices[i]->deven = DEV_DISABLED; } } + + //figure out how many mining threads we'll need + unsigned int n_threads = 0; + pthread_t restart_thr; + + #ifdef HAVE_ADL + //change gpu threads if needed + if(opt_isset(options, SWITCHER_APPLY_GT)) + { + if(!empty_string((opt = get_pool_setting(work->pool->gpu_threads, default_profile.gpu_threads)))) + set_gpu_threads(opt); + } + + for (i = 0; i < total_devices; i++) + n_threads += devices[i]->threads; + #else + n_threads = mining_threads; + #endif + + /*use start_threads to close original threads... mining_threads was recounted above and would cause crashes + when trying to close a thread index that doesn't exist.*/ + mining_threads = start_threads; + + if (unlikely(pthread_create(&restart_thr, NULL, restart_mining_threads_thread, (void *) (intptr_t) n_threads))) + quit(1, "restart_mining_threads create thread failed"); + sleep(60); + + #ifdef __TEMP_ALGO_SWITCH_FIX__ + //if restart thread is done, then abort... + if(!thread_fix_search(restart_thr)) + { + applog(LOG_DEBUG, "thread %d not found in fix list, don't exit sgminer", restart_thr); + pthread_cancel(restart_thr); + mutex_lock(&algo_switch_wait_lock); + pthread_cond_broadcast(&algo_switch_wait_cond); + mutex_unlock(&algo_switch_wait_lock); + return; + } + #endif /* __TEMP_ALGO_SWITCH_FIX__ */ + + quit(1, "thread was not cancelled in 60 seconds after restart_mining_threads"); } - //enable all devices - else + } + //nothing changed... new pool uses same settings + else + { + //apply new pool_no to all mining threads + for (i = 0; i < start_threads; i++) { - for (i = 0; i < total_devices; ++i) - enable_device(devices[i]); + struct thr_info *thr = mining_thr[i]; + thr->pool_no = work->pool->pool_no; } - - //devices reset - assign gpu-threads as needed - unsigned int n_threads = 0; - pthread_t restart_thr; - #ifdef HAVE_ADL - if(!empty_string(work->pool->gpu_threads)) - set_gpu_threads(work->pool->gpu_threads); - else if(!empty_string(default_profile.gpu_threads)) - set_gpu_threads(default_profile.gpu_threads); - - for (i = 0; i < total_devices; ++i) - n_threads += devices[i]->threads; - #else - n_threads = mining_threads; - #endif - - /*use start_threads to close original threads... mining_threads was recounted above and would cause crashes - when trying to close a thread index that doesn't exist.*/ - mining_threads = start_threads; - - if (unlikely(pthread_create(&restart_thr, NULL, restart_mining_threads_thread, (void *) (intptr_t) n_threads))) - quit(1, "restart_mining_threads create thread failed"); - sleep(60); - - #ifdef __TEMP_ALGO_SWITCH_FIX__ - //if restart thread is done, then abort... - if(!thread_fix_search(restart_thr)) - { - applog(LOG_DEBUG, "thread %d not found in fix list, don't exit sgminer", restart_thr); - pthread_cancel(restart_thr); - mutex_lock(&algo_switch_wait_lock); - pthread_cond_broadcast(&algo_switch_wait_cond); - mutex_unlock(&algo_switch_wait_lock); - return; - } - #endif /* __TEMP_ALGO_SWITCH_FIX__ */ - - quit(1, "thread was not cancelled in 60 seconds after restart_mining_threads"); + algo_switch_n = 0; + mutex_unlock(&algo_switch_lock); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); } + // Signal other threads to start working now mutex_lock(&algo_switch_wait_lock); pthread_cond_broadcast(&algo_switch_wait_cond); mutex_unlock(&algo_switch_wait_lock); - // Not all threads are waiting, join the waiting list - } + // Not all threads are waiting, join the waiting list + } else { mutex_unlock(&algo_switch_lock); @@ -7942,13 +8110,16 @@ static void restart_mining_threads(unsigned int new_n_threads) unsigned int i, j, k; // Stop and free threads - if (mining_thr) { + if (mining_thr) + { rd_lock(&mining_thr_lock); - for (i = 0; i < mining_threads; i++) { + for (i = 0; i < mining_threads; i++) + { applog(LOG_DEBUG, "Shutting down thread %d", i); mining_thr[i]->cgpu->shutdown = true; } rd_unlock(&mining_thr_lock); + // kill_mining will rd lock mining_thr_lock kill_mining(); rd_lock(&mining_thr_lock); @@ -7963,13 +8134,16 @@ static void restart_mining_threads(unsigned int new_n_threads) wr_lock(&mining_thr_lock); - if (mining_thr) { - for (i = 0; i < total_devices; ++i) { + if (mining_thr) + { + for (i = 0; i < total_devices; i++) { free(devices[i]->thr); } + for (i = 0; i < mining_threads; i++) { free(mining_thr[i]); } + free(mining_thr); } @@ -7988,7 +8162,10 @@ static void restart_mining_threads(unsigned int new_n_threads) } rd_lock(&devices_lock); + // Start threads + struct pool *pool = current_pool(); + k = 0; for (i = 0; i < total_devices; ++i) { struct cgpu_info *cgpu = devices[i]; @@ -7996,9 +8173,11 @@ static void restart_mining_threads(unsigned int new_n_threads) cgpu->thr[cgpu->threads] = NULL; cgpu->status = LIFE_INIT; - for (j = 0; j < cgpu->threads; ++j, ++k) { + for (j = 0; j < cgpu->threads; ++j, ++k) + { thr = mining_thr[k]; thr->id = k; + thr->pool_no = pool->pool_no; thr->cgpu = cgpu; thr->device_thread = j;