diff --git a/Makefile.am b/Makefile.am index 43ebec65..97953303 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,6 +42,7 @@ sgminer_SOURCES += findnonce.c findnonce.h sgminer_SOURCES += adl.c adl.h adl_functions.h sgminer_SOURCES += pool.c pool.h sgminer_SOURCES += algorithm.c algorithm.h +sgminer_SOURCES += config_parser.c config_parser.h sgminer_SOURCES += ocl/patch_kernel.c ocl/patch_kernel.h sgminer_SOURCES += ocl/build_kernel.c ocl/build_kernel.h sgminer_SOURCES += ocl/binary_kernel.c ocl/binary_kernel.h diff --git a/config_parser.c b/config_parser.c new file mode 100644 index 00000000..04dc69b3 --- /dev/null +++ b/config_parser.c @@ -0,0 +1,657 @@ +/* + * Copyright 2013-2014 sgminer developers (see AUTHORS.md) + * Copyright 2011-2013 Con Kolivas + * Copyright 2011-2012 Luke Dashjr + * Copyright 2010 Jeff Garzik + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) + * any later version. See COPYING for more details. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "compat.h" +#include "miner.h" +#include "config_parser.h" +#include "driver-opencl.h" +#include "bench_block.h" + +#include "algorithm.h" +#include "pool.h" + +#if defined(unix) || defined(__APPLE__) + #include + #include + #include +#endif + +char *cnfbuf = NULL; //config file loaded +int fileconf_load; //config file load status +const char def_conf[] = "sgminer.conf"; +char *default_config; +bool config_loaded; +//static int include_count; + +int json_array_index = -1; //current array index being parsed +char *last_json_error = NULL; //last json_error +//#define JSON_INCLUDE_CONF "include" +#define JSON_LOAD_ERROR "JSON decode of file '%s' failed\n %s" +#define JSON_LOAD_ERROR_LEN strlen(JSON_LOAD_ERROR) +/*#define JSON_MAX_DEPTH 10 +#define JSON_MAX_DEPTH_ERR "Too many levels of JSON includes (limit 10) or a loop"*/ + +/******************************************* + * Profile list functions + *******************************************/ +struct profile default_profile; +struct profile **profiles; +int total_profiles; + +static struct profile *add_profile() +{ + struct profile *profile; + char buf[32]; + + if(!(profile = (struct profile *)calloc(sizeof(struct profile), 1))) + quit(1, "Failed to calloc profile in add_profile"); + profile->profile_no = total_profiles; + + //default profile name is the profile index + sprintf(buf, "%d", profile->profile_no); + profile->name = strdup(buf); + + profiles = (struct profile **)realloc(profiles, sizeof(struct profile *) * (total_profiles + 2)); + profiles[total_profiles++] = profile; + + return profile; +} + +//only used while loading config +static struct profile *get_current_profile() +{ + while ((json_array_index + 1) > total_profiles) + add_profile(); + + if (json_array_index < 0) + { + if (!total_profiles) + add_profile(); + return profiles[total_profiles - 1]; + } + + return profiles[json_array_index]; +} + +//find a profile by name +static struct profile *get_profile(char *name) +{ + int i; + + for(i=total_profiles;i--;) + { + if(!strcasecmp(profiles[i]->name, name)) + return profiles[i]; + } + + return NULL; +} + +/******* Default profile functions used during config parsing *****/ +char *set_default_intensity(const char *arg) +{ + default_profile.intensity = arg; + return NULL; +} + +char *set_default_xintensity(const char *arg) +{ + default_profile.xintensity = arg; + return NULL; +} + +char *set_default_rawintensity(const char *arg) +{ + default_profile.rawintensity = arg; + return NULL; +} + +char *set_default_thread_concurrency(const char *arg) +{ + default_profile.thread_concurrency = arg; + return NULL; +} + +#ifdef HAVE_ADL + + char *set_default_gpu_engine(const char *arg) + { + default_profile.gpu_engine = arg; + return NULL; + } + + char *set_default_gpu_memclock(const char *arg) + { + default_profile.gpu_memclock = arg; + return NULL; + } + + char *set_default_gpu_threads(const char *arg) + { + default_profile.gpu_threads = arg; + return NULL; + } + + char *set_default_gpu_fan(const char *arg) + { + default_profile.gpu_fan = arg; + return NULL; + } + +#endif + +char *set_default_profile(char *arg) +{ + default_profile.name = arg; + return NULL; +} + +/****** Profile functions used in during config parsing ********/ +char *set_profile_name(char *arg) +{ + struct profile *profile = get_current_profile(); + + applog(LOG_DEBUG, "Setting profile %i name to %s", profile->profile_no, arg); + opt_set_charp(arg, &profile->name); + + return NULL; +} + +char *set_profile_algorithm(const char *arg) +{ + struct profile *profile = get_current_profile(); + + //applog(LOG_DEBUG, "Setting profile %s algorithm to %s", profile->name, arg); + set_algorithm(&profile->algorithm, arg); + + return NULL; +} + +char *set_profile_intensity(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->intensity = arg; + return NULL; +} + +char *set_profile_xintensity(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->xintensity = arg; + return NULL; +} + +char *set_profile_rawintensity(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->rawintensity = arg; + return NULL; +} + +char *set_profile_thread_concurrency(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->thread_concurrency = arg; + return NULL; +} + +#ifdef HAVE_ADL + + char *set_profile_gpu_engine(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_engine = arg; + return NULL; + } + + char *set_profile_gpu_memclock(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_memclock = arg; + return NULL; + } + + char *set_profile_gpu_threads(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_threads = arg; + return NULL; + } + + char *set_profile_gpu_fan(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_fan = arg; + return NULL; + } + +#endif + +char *set_profile_nfactor(const char *arg) +{ + struct profile *profile = get_current_profile(); + + applog(LOG_DEBUG, "Setting profile %s N-factor to %s", profile->name, arg); + set_algorithm_nfactor(&profile->algorithm, (const uint8_t) atoi(arg)); + + return NULL; +} + +/*************************************** +* Helper Functions +****************************************/ +//set last json error +void set_last_json_error(const char *fmt, ...) +{ + va_list args; + size_t bufsize; + + //build args + va_start(args, fmt); + //get final string buffer size + bufsize = vsnprintf(NULL, 0, JSON_LOAD_ERROR, args); + va_end(args); + + //if NULL allocate memory... otherwise reallocate + if(!last_json_error) + { + if(!(last_json_error = (char *)malloc(bufsize+1))) + quit(1, "Malloc failure in json error"); + } + else + { + if(!(last_json_error = (char *)realloc(last_json_error, bufsize+1))) + quit(1, "Realloc failure in json error"); + } + + //zero out buffer + memset(last_json_error, '\0', bufsize+1); + + //get args again + va_start(args, fmt); + vsnprintf(last_json_error, bufsize, JSON_LOAD_ERROR, args); + va_end(args); +} + +//find opt by name in an opt table +static struct opt_table *opt_find(struct opt_table *tbl, char *optname) +{ + struct opt_table *opt; + char *p, *name; + + for(opt = tbl;opt->type != OPT_END;opt++) + { + /* We don't handle subtables. */ + assert(!(opt->type & OPT_SUBTABLE)); + + if(!opt->names) + continue; + + /* Pull apart the option name(s). */ + name = strdup(opt->names); + for(p = strtok(name, "|");p;p = strtok(NULL, "|")) + { + /* Ignore short options. */ + if(p[1] != '-') + continue; + + //if this is the opt we're looking for, return it... + if(!strcasecmp(optname, p)) + { + free(name); + return opt; + } + } + free(name); + } + + return NULL; +} + + +/*************************************** +* Config Parsing Functions +****************************************/ +//Handle parsing JSON objects +void parse_config_object(json_t *obj, const char *parentkey, bool fileconf, int parent_iteration) +{ + //char *err = NULL; + const char *key; + json_t *val; + + json_object_foreach(obj, key, val) + { + //process include + if(!strcasecmp(key, "include")) + { + if(val && json_is_string(val)) + load_config(json_string_value(val), parentkey, NULL); + } + else + parse_config(val, key, parentkey, fileconf, parent_iteration); + /* + { + if((err = parse_config(val, key, parentkey, fileconf, parent_iteration))) + return err; + }*/ + } +} + +//Handle parsing JSON arrays +static char *parse_config_array(json_t *obj, char *parentkey, bool fileconf) +{ + char *err = NULL; + size_t idx; + json_t *val; + + //fix parent key - remove extra "s" to match opt names (e.g. --pool-gpu-memclock not --pools-gpu-memclock) + if(!strcasecmp(parentkey, "pools") || !strcasecmp(parentkey, "profiles")) + parentkey[(strlen(parentkey) - 1)] = '\0'; + + json_array_foreach(obj, idx, val) + { + //abort on error + if((err = parse_config(val, "", parentkey, fileconf, idx))) + return err; + } + + return NULL; +} + +//Parse JSON values from config file +char *parse_config(json_t *val, const char *key, const char *parentkey, bool fileconf, int parent_iteration) +{ + static char err_buf[200]; + char *err = NULL; + struct opt_table *opt; + char optname[255]; + /*const char *key + json_t *val;*/ + + json_array_index = parent_iteration; + + if (fileconf && !fileconf_load) + fileconf_load = 1; + + /* + parse the json config items into opts instead of looking for opts in the json config... + This adds greater flexibility with config files. + */ + switch(json_typeof(val)) + { + //json value is an object + case JSON_OBJECT: + parse_config_object(val, parentkey, false, parent_iteration); + break; + + //json value is an array + case JSON_ARRAY: + err = parse_config_array(val, (char *)key, fileconf); + break; + + //other json types process here + default: + //convert json key to opt name + sprintf(optname, "--%s%s%s", ((!empty_string(parentkey))?parentkey:""), ((!empty_string(parentkey))?"-":""), key); + + //look up opt name in config table + if((opt = opt_find(opt_config_table, optname)) != NULL) + { + //strings + if ((opt->type & OPT_HASARG) && json_is_string(val)) + err = opt->cb_arg(json_string_value(val), opt->u.arg); + //boolean values + else if ((opt->type & OPT_NOARG) && json_is_true(val)) + err = opt->cb(opt->u.arg); + else + err = "Invalid value"; + } + else + err = "Invalid option"; + + break; + } + + //error processing JSON... + if(err) + { + /* Allow invalid values to be in configuration + * file, just skipping over them provided the + * JSON is still valid after that. */ + if(fileconf) + { + applog(LOG_WARNING, "Skipping config option %s: %s", optname+2, err); + fileconf_load = -1; + } + else + { + snprintf(err_buf, sizeof(err_buf), "Error parsing JSON option %s: %s", optname+2, err); + return err_buf; + } + } + + return NULL; +} + +char *load_config(const char *arg, const char *parentkey, void __maybe_unused *unused) +{ + json_error_t err; + json_t *config; + + //most likely useless but leaving it here for now... + if(!cnfbuf) + cnfbuf = strdup(arg); + + //no need to restrict the number of includes... if it causes problems, restore it later + /*if(++include_count > JSON_MAX_DEPTH) + return JSON_MAX_DEPTH_ERR; + */ + +#if JANSSON_MAJOR_VERSION > 1 + config = json_load_file(arg, 0, &err); +#else + config = json_load_file(arg, &err); +#endif + + //if json root is not an object, error out + if(!json_is_object(config)) + { + set_last_json_error(JSON_LOAD_ERROR, arg, err.text); + return last_json_error; + } + + config_loaded = true; + + /* Parse the config now, so we can override it. That can keep pointers + * so don't free config object. */ + return parse_config(config, "", parentkey, true, -1); +} + +char *set_default_config(const char *arg) +{ + opt_set_charp(arg, &default_config); + return NULL; +} + +void load_default_config(void) +{ + cnfbuf = (char *)malloc(PATH_MAX); + + default_save_file(cnfbuf); + + if (!access(cnfbuf, R_OK)) + load_config(cnfbuf, "", NULL); + else { + free(cnfbuf); + cnfbuf = NULL; + } +} + +/******************************************* + * Startup functions + * *****************************************/ + +//assign default settings from default profile if set +void load_default_profile() +{ + struct profile *profile; + + //if a default profile name is set + if(!empty_string(default_profile.name)) + { + //find profile and copy settings + if((profile = get_profile(default_profile.name))) + { + default_profile.algorithm = profile->algorithm; + default_profile.intensity = profile->intensity; + default_profile.xintensity = profile->xintensity; + default_profile.rawintensity = profile->rawintensity; + default_profile.thread_concurrency = profile->thread_concurrency; +#ifdef HAVE_ADL + default_profile.gpu_engine = profile->gpu_engine; + default_profile.gpu_memclock = profile->gpu_memclock; + default_profile.gpu_threads = profile->gpu_threads; + default_profile.gpu_fan = profile->gpu_fan; +#endif + } + } +} + +//apply default settings +void apply_defaults() +{ + set_algorithm(opt_algorithm, default_profile.algorithm.name); + + if(!empty_string(default_profile.intensity)) + set_intensity(default_profile.intensity); + + if(!empty_string(default_profile.xintensity)) + set_xintensity(default_profile.xintensity); + + if(!empty_string(default_profile.rawintensity)) + set_rawintensity(default_profile.rawintensity); + + if(!empty_string(default_profile.thread_concurrency)) + set_thread_concurrency(default_profile.thread_concurrency); + +#ifdef HAVE_ADL + if(!empty_string(default_profile.gpu_engine)) + set_gpu_engine(default_profile.gpu_engine); + + if(!empty_string(default_profile.gpu_memclock)) + set_gpu_memclock(default_profile.gpu_memclock); + + if(!empty_string(default_profile.gpu_threads)) + set_gpu_threads(default_profile.gpu_threads); + + if(!empty_string(default_profile.gpu_fan)) + set_gpu_fan(default_profile.gpu_fan); +#endif +} + +//apply profile settings to pools +void apply_pool_profiles() +{ + struct profile *profile; + int i; + + for(i=total_pools;i--;) + { + //if the pool has a profile set + if(!empty_string(pools[i]->profile)) + { + applog(LOG_DEBUG, "Loading settings from profile \"%s\" for pool %i", pools[i]->profile, pools[i]->pool_no); + + //find profile and apply settings to the pool + if((profile = get_profile(pools[i]->profile))) + { + pools[i]->algorithm = profile->algorithm; + applog(LOG_DEBUG, "Pool %i Algorithm set to \"%s\"", pools[i]->pool_no, pools[i]->algorithm.name); + + if(!empty_string(profile->intensity)) + { + pools[i]->intensity = profile->intensity; + applog(LOG_DEBUG, "Pool %i Intensity set to \"%s\"", pools[i]->pool_no, pools[i]->intensity); + } + + if(!empty_string(profile->xintensity)) + { + pools[i]->xintensity = profile->xintensity; + applog(LOG_DEBUG, "Pool %i XIntensity set to \"%s\"", pools[i]->pool_no, pools[i]->xintensity); + } + + if(!empty_string(profile->rawintensity)) + { + pools[i]->rawintensity = profile->rawintensity; + applog(LOG_DEBUG, "Pool %i Raw Intensity set to \"%s\"", pools[i]->pool_no, pools[i]->rawintensity); + } + + if(!empty_string(profile->thread_concurrency)) + { + pools[i]->thread_concurrency = profile->thread_concurrency; + applog(LOG_DEBUG, "Pool %i Thread Concurrency set to \"%s\"", pools[i]->pool_no, pools[i]->thread_concurrency); + } + +#ifdef HAVE_ADL + if(!empty_string(profile->gpu_engine)) + { + pools[i]->gpu_engine = profile->gpu_engine; + applog(LOG_DEBUG, "Pool %i GPU Clock set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_engine); + } + + if(!empty_string(profile->gpu_memclock)) + { + pools[i]->gpu_memclock = profile->gpu_memclock; + applog(LOG_DEBUG, "Pool %i GPU Memory clock set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_memclock); + } + + if(!empty_string(profile->gpu_threads)) + { + pools[i]->gpu_threads = profile->gpu_threads; + applog(LOG_DEBUG, "Pool %i GPU Threads set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_threads); + } + + if(!empty_string(profile->gpu_fan)) + { + pools[i]->gpu_fan = profile->gpu_fan; + applog(LOG_DEBUG, "Pool %i GPU Fan set to \"%s\"", pools[i]->pool_no, pools[i]->gpu_fan); + } +#endif + } + else + applog(LOG_DEBUG, "Profile load failed for pool %i: profile %s not found.", pools[i]->pool_no, pools[i]->profile); + } + } +} diff --git a/config_parser.h b/config_parser.h new file mode 100644 index 00000000..5953b456 --- /dev/null +++ b/config_parser.h @@ -0,0 +1,88 @@ +#ifndef CONFIG_PARSER_H +#define CONFIG_PARSER_H + +#include "config.h" + +#include "miner.h" +#include "algorithm.h" + +//helper to check for empty or NULL strings +#ifndef empty_string + #define empty_string(str) ((str && str[0] != '\0')?0:1) +#endif + +//profile structure +struct profile { + int profile_no; + char *name; + + algorithm_t algorithm; + const char *intensity; + const char *xintensity; + const char *rawintensity; + const char *thread_concurrency; + const char *gpu_engine; + const char *gpu_memclock; + const char *gpu_threads; + const char *gpu_fan; +}; + +/* globals needed outside */ +extern char *cnfbuf; +extern int fileconf_load; +extern const char def_conf[]; +extern char *default_config; +extern bool config_loaded; + +extern int json_array_index; + +extern struct profile default_profile; + +/* option parser functions */ +extern char *set_default_intensity(const char *arg); +extern char *set_default_xintensity(const char *arg); +extern char *set_default_rawintensity(const char *arg); +extern char *set_default_thread_concurrency(const char *arg); +#ifdef HAVE_ADL + extern char *set_default_gpu_engine(const char *arg); + extern char *set_default_gpu_memclock(const char *arg); + extern char *set_default_gpu_threads(const char *arg); + extern char *set_default_gpu_fan(const char *arg); +#endif +extern char *set_default_profile(char *arg); + +extern char *set_profile_name(char *arg); +extern char *set_profile_algorithm(const char *arg); +extern char *set_profile_intensity(const char *arg); +extern char *set_profile_xintensity(const char *arg); +extern char *set_profile_rawintensity(const char *arg); +extern char *set_profile_thread_concurrency(const char *arg); +#ifdef HAVE_ADL + extern char *set_profile_gpu_engine(const char *arg); + extern char *set_profile_gpu_memclock(const char *arg); + extern char *set_profile_gpu_threads(const char *arg); + extern char *set_profile_gpu_fan(const char *arg); +#endif +extern char *set_profile_nfactor(const char *arg); + +/* helpers */ +//void set_last_json_error(const char *fmt, ...); +//struct opt_table *opt_find(struct opt_table *tbl, char *optname); + +/* config parser functions */ +//void parse_config_object(json_t *obj, const char *parentkey, bool fileconf, int parent_iteration); +//char *parse_config_array(json_t *obj, char *parentkey, bool fileconf); +extern char *parse_config(json_t *val, const char *key, const char *parentkey, bool fileconf, int parent_iteration); +extern char *load_config(const char *arg, const char *parentkey, void __maybe_unused *unused); +extern char *set_default_config(const char *arg); +extern void load_default_config(void); + +/*struct profile *add_profile(); +struct profile *get_current_profile(); +struct profile *get_profile(char *name);*/ + +extern void load_default_profile(); +extern void apply_defaults(); +extern void apply_pool_profiles(); + +#endif // CONFIG_PARSER_H diff --git a/miner.h b/miner.h index fcf419ef..37c899ea 100644 --- a/miner.h +++ b/miner.h @@ -124,6 +124,8 @@ static inline int fsync (int fd) #include "ADL_SDK/adl_sdk.h" #endif +#include + #if (!defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \ || (defined(WIN32) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) #ifndef bswap_16 @@ -1081,6 +1083,9 @@ extern double best_diff; extern struct timeval block_timeval; extern char *workpadding; +//config options table +extern struct opt_table opt_config_table[]; + typedef struct _dev_blk_ctx { cl_uint ctx_a; cl_uint ctx_b; cl_uint ctx_c; cl_uint ctx_d; cl_uint ctx_e; cl_uint ctx_f; cl_uint ctx_g; cl_uint ctx_h; @@ -1192,6 +1197,7 @@ struct pool { proxytypes_t rpc_proxytype; char *rpc_proxy; + char *profile; algorithm_t algorithm; const char *intensity; const char *xintensity; diff --git a/sgminer.c b/sgminer.c index 009d6110..7fad68af 100644 --- a/sgminer.c +++ b/sgminer.c @@ -58,6 +58,7 @@ char *curly = ":D"; #include "algorithm.h" #include "pool.h" +#include "config_parser.h" #if defined(unix) || defined(__APPLE__) #include @@ -233,9 +234,6 @@ enum pool_strategy pool_strategy = POOL_FAILOVER; int opt_rotate_period; static int total_urls; -/* Used in config parsing, e.g. pool array. */ -static int json_array_index = -1; - static #ifndef HAVE_CURSES const @@ -280,16 +278,6 @@ static struct stratum_share *stratum_shares = NULL; char *opt_socks_proxy = NULL; -static const char def_conf[] = "sgminer.conf"; -static char *default_config; -static bool config_loaded; -static int include_count; -#define JSON_INCLUDE_CONF "include" -#define JSON_LOAD_ERROR "JSON decode of file '%s' failed\n %s" -#define JSON_LOAD_ERROR_LEN strlen(JSON_LOAD_ERROR) -#define JSON_MAX_DEPTH 10 -#define JSON_MAX_DEPTH_ERR "Too many levels of JSON includes (limit 10) or a loop" - #if defined(unix) || defined(__APPLE__) static char *opt_stderr_cmd = NULL; static int forkpid; @@ -526,6 +514,7 @@ struct pool *add_pool(void) char buf[32]; buf[0] = '\0'; pool->name = strdup(buf); + pool->profile = strdup(buf); //profile blank by default /* Algorithm */ pool->algorithm = opt_algorithm; @@ -854,6 +843,16 @@ static char *set_pool_name(char *arg) return NULL; } +static char *set_pool_profile(char *arg) +{ + struct pool *pool = get_current_pool(); + + applog(LOG_DEBUG, "Setting pool %i profile to %s", pool->pool_no, arg); + opt_set_charp(arg, &pool->profile); + + return NULL; +} + static char *set_poolname_deprecated(char *arg) { applog(LOG_ERR, "Specifying pool name by --poolname is deprecated. Use --name instead."); @@ -1198,7 +1197,7 @@ char *set_difficulty_multiplier(char *arg) } /* These options are available from config file or commandline */ -static struct opt_table opt_config_table[] = { +struct opt_table opt_config_table[] = { OPT_WITH_ARG("--algorithm", set_algo, NULL, NULL, "Set mining algorithm and most common defaults, default: scrypt"), @@ -1257,6 +1256,9 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--debug|-D", enable_debug, &opt_debug, "Enable debug output"), + OPT_WITH_ARG("--default-profile", + set_default_profile, NULL, NULL, + "Set Default Profile"), OPT_WITH_ARG("--description", set_pool_description, NULL, NULL, "Pool description"), @@ -1291,19 +1293,23 @@ static struct opt_table opt_config_table[] = { "Number of threads per GPU (1 - 10)"), #else OPT_WITH_ARG("--gpu-threads|-g", - set_gpu_threads, NULL, NULL, +// set_gpu_threads, NULL, NULL, + set_default_gpu_threads, NULL, NULL, "Number of threads per GPU - one value or comma separated list (e.g. 1,2,1)"), OPT_WITH_ARG("--gpu-engine", - set_gpu_engine, NULL, NULL, +// set_gpu_engine, NULL, NULL, + set_default_gpu_engine, NULL, NULL, "GPU engine (over)clock range in Mhz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)"), OPT_WITH_ARG("--gpu-fan", - set_gpu_fan, NULL, NULL, +// set_gpu_fan, NULL, NULL, + set_default_gpu_fan, NULL, NULL, "GPU fan percentage range - one value, range and/or comma separated list (e.g. 0-85,85,65)"), OPT_WITH_ARG("--gpu-map", set_gpu_map, NULL, NULL, "Map OpenCL to ADL device order manually, paired CSV (e.g. 1:0,2:1 maps OpenCL 1 to ADL 0, 2 to 1)"), OPT_WITH_ARG("--gpu-memclock", - set_gpu_memclock, NULL, NULL, +// set_gpu_memclock, NULL, NULL, + set_default_gpu_memclock, NULL, NULL, "Set the GPU memory (over)clock in Mhz - one value for all or separate by commas for per card"), OPT_WITH_ARG("--gpu-memdiff", set_gpu_memdiff, NULL, NULL, @@ -1317,18 +1323,6 @@ static struct opt_table opt_config_table[] = { OPT_WITH_ARG("--gpu-vddc", set_gpu_vddc, NULL, NULL, "Set the GPU voltage in Volts - one value for all or separate by commas for per card"), - OPT_WITH_ARG("--pool-gpu-engine", - set_pool_gpu_engine, NULL, NULL, - "GPU engine (over)clock range in Mhz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)"), - OPT_WITH_ARG("--pool-gpu-memclock", - set_pool_gpu_memclock, NULL, NULL, - "Set the GPU memory (over)clock in Mhz - one value for all or separate by commas for per card"), - OPT_WITH_ARG("--pool-gpu-threads", - set_pool_gpu_threads, NULL, NULL, - "Number of threads per GPU for pool"), - OPT_WITH_ARG("--pool-gpu-fan", - set_pool_gpu_fan, NULL, NULL, - "GPU fan for pool"), #endif OPT_WITH_ARG("--lookup-gap", set_lookup_gap, NULL, NULL, @@ -1344,28 +1338,16 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--more-notices", opt_set_bool, &opt_morenotices, "Shows work restart and new block notices, hidden by default"), - OPT_WITH_ARG("--intensity|-I", - set_intensity, NULL, NULL, - "Intensity of GPU scanning (d or " MIN_INTENSITY_STR - " -> " MAX_INTENSITY_STR - ",default: d to maintain desktop interactivity), overridden by --xintensity or --rawintensity."), OPT_WITH_ARG("--xintensity|-X", - set_xintensity, NULL, NULL, +// set_xintensity, NULL, NULL, + set_default_xintensity, NULL, NULL, "Shader based intensity of GPU scanning (" MIN_XINTENSITY_STR " to " MAX_XINTENSITY_STR "), overrides --intensity|-I, overridden by --rawintensity."), OPT_WITH_ARG("--rawintensity", - set_rawintensity, NULL, NULL, +// set_rawintensity, NULL, NULL, + set_default_rawintensity, NULL, NULL, "Raw intensity of GPU scanning (" MIN_RAWINTENSITY_STR " to " MAX_RAWINTENSITY_STR "), overrides --intensity|-I and --xintensity|-X."), - OPT_WITH_ARG("--pool-intensity", - set_pool_intensity, NULL, NULL, - "Intensity of GPU scanning (pool-specific)"), - OPT_WITH_ARG("--pool-xintensity", - set_pool_xintensity, NULL, NULL, - "Shader based intensity of GPU scanning (pool-specific)"), - OPT_WITH_ARG("--pool-rawintensity", - set_pool_rawintensity, NULL, NULL, - "Raw intensity of GPU scanning (pool-specific)"), OPT_WITH_ARG("--kernel-path|-K", opt_set_charp, opt_show_charp, &opt_kernel_path, "Specify a path to where kernel files are"), @@ -1386,7 +1368,7 @@ static struct opt_table opt_config_table[] = { opt_set_charp, NULL, &opt_stderr_cmd, "Use custom pipe cmd for output messages"), #endif // defined(unix) - OPT_WITH_ARG("--name", + OPT_WITH_ARG("--name|--pool-name", set_pool_name, NULL, NULL, "Name of pool"), OPT_WITHOUT_ARG("--net-delay", @@ -1418,18 +1400,92 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--no-extranonce-subscribe", set_no_extranonce_subscribe, NULL, "Disable 'extranonce' stratum subscribe for pool"), - OPT_WITH_ARG("--pass|-p", + OPT_WITH_ARG("--pass|--pool-pass|-p", set_pass, NULL, NULL, "Password for bitcoin JSON-RPC server"), OPT_WITHOUT_ARG("--per-device-stats", opt_set_bool, &want_per_device_stats, "Force verbose mode and output per-device statistics"), + OPT_WITH_ARG("--poolname", /* TODO: Backward compatibility, to be removed. */ set_poolname_deprecated, NULL, NULL, opt_hidden), - OPT_WITH_ARG("--priority", + OPT_WITH_ARG("--pool-algorithm", + set_pool_algorithm, NULL, NULL, + "Set algorithm for pool"), +#ifdef HAVE_ADL + OPT_WITH_ARG("--pool-gpu-engine", + set_pool_gpu_engine, NULL, NULL, + "Pool GPU engine (over)clock range in Mhz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)"), + OPT_WITH_ARG("--pool-gpu-fan", + set_pool_gpu_fan, NULL, NULL, + "GPU fan for pool"), + OPT_WITH_ARG("--pool-gpu-memclock", + set_pool_gpu_memclock, NULL, NULL, + "Set the Pool GPU memory (over)clock in Mhz - one value for all or separate by commas for per card"), + OPT_WITH_ARG("--pool-gpu-threads", + set_pool_gpu_threads, NULL, NULL, + "Number of threads per GPU for pool"), +#endif + OPT_WITH_ARG("--pool-intensity", + set_pool_intensity, NULL, NULL, + "Intensity of GPU scanning (pool-specific)"), + OPT_WITH_ARG("--pool-nfactor", + set_pool_nfactor, NULL, NULL, + "Set N-factor for pool"), + OPT_WITH_ARG("--pool-profile", + set_pool_profile, NULL, NULL, + "Profile to use with the pool"), + OPT_WITH_ARG("--pool-rawintensity", + set_pool_rawintensity, NULL, NULL, + "Raw intensity of GPU scanning (pool-specific)"), + OPT_WITH_ARG("--pool-thread-concurrency", + set_pool_thread_concurrency, NULL, NULL, + "Set thread concurrency for pool"), + OPT_WITH_ARG("--pool-xintensity", + set_pool_xintensity, NULL, NULL, + "Shader based intensity of GPU scanning (pool-specific)"), + + OPT_WITH_ARG("--priority|--pool-priority", set_pool_priority, NULL, NULL, "Pool priority"), + + OPT_WITH_ARG("--profile-algorithm", + set_profile_algorithm, NULL, NULL, + "Set algorithm for profile"), +#ifdef HAVE_ADL + OPT_WITH_ARG("--profile-gpu-engine", + set_profile_gpu_engine, NULL, NULL, + "Profile GPU engine (over)clock range in Mhz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)"), + OPT_WITH_ARG("--profile-gpu-fan", + set_profile_gpu_fan, NULL, NULL, + "GPU fan for profile"), + OPT_WITH_ARG("--profile-gpu-memclock", + set_profile_gpu_memclock, NULL, NULL, + "Set the Profile GPU memory (over)clock in Mhz - one value for all or separate by commas for per card"), + OPT_WITH_ARG("--profile-gpu-threads", + set_profile_gpu_threads, NULL, NULL, + "Number of threads per GPU for profile"), +#endif + OPT_WITH_ARG("--profile-intensity", + set_profile_intensity, NULL, NULL, + "Intensity of GPU scanning (profile-specific)"), + OPT_WITH_ARG("--profile-name", + set_profile_name, NULL, NULL, + "Profile Name"), + OPT_WITH_ARG("--profile-nfactor", + set_profile_nfactor, NULL, NULL, + "Set N-factor for profile"), + OPT_WITH_ARG("--profile-rawintensity", + set_profile_rawintensity, NULL, NULL, + "Raw intensity of GPU scanning (profile-specific)"), + OPT_WITH_ARG("--profile-thread-concurrency", + set_profile_thread_concurrency, NULL, NULL, + "Set thread concurrency for profile"), + OPT_WITH_ARG("--profile-xintensity", + set_profile_xintensity, NULL, NULL, + "Shader based intensity of GPU scanning (profile-specific)"), + OPT_WITHOUT_ARG("--protocol-dump|-P", opt_set_bool, &opt_protocol, "Verbose dump of protocol-level activities"), @@ -1439,7 +1495,7 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--quiet|-q", opt_set_bool, &opt_quiet, "Disable logging output, display status and errors"), - OPT_WITH_ARG("--quota|-U", + OPT_WITH_ARG("--quota|--pool-quota|-U", set_quota, NULL, NULL, "quota;URL combination for server with load-balance strategy quotas"), OPT_WITHOUT_ARG("--real-quiet", @@ -1525,21 +1581,13 @@ static struct opt_table opt_config_table[] = { opt_hidden), #endif OPT_WITH_ARG("--thread-concurrency", - set_thread_concurrency, NULL, NULL, +// set_thread_concurrency, NULL, NULL, + set_default_thread_concurrency, NULL, NULL, "Set GPU thread concurrency for scrypt mining, comma separated"), - OPT_WITH_ARG("--url|-o", + OPT_WITH_ARG("--url|--pool-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("--pool-thread-concurrency", - set_pool_thread_concurrency, NULL, NULL, - "Set thread concurrency for pool"), - OPT_WITH_ARG("--user|-u", + OPT_WITH_ARG("--user|--pool-user|-u", set_user, NULL, NULL, "Username for bitcoin JSON-RPC server"), OPT_WITH_ARG("--vectors", @@ -1561,153 +1609,16 @@ static struct opt_table opt_config_table[] = { "Display extra work time debug information"), OPT_WITH_ARG("--pools", opt_set_bool, NULL, NULL, opt_hidden), + OPT_WITH_ARG("--profiles", + opt_set_bool, NULL, NULL, opt_hidden), OPT_WITH_ARG("--difficulty-multiplier", set_difficulty_multiplier, NULL, NULL, "Difficulty multiplier for jobs received from stratum pools"), OPT_ENDTABLE }; -static char *load_config(const char *arg, void __maybe_unused *unused); - -static int fileconf_load; - -static char *parse_config(json_t *config, bool fileconf, int parent_iteration) -{ - static char err_buf[200]; - struct opt_table *opt; - json_t *val; - - json_array_index = parent_iteration; - - if (fileconf && !fileconf_load) - fileconf_load = 1; - - for (opt = opt_config_table; opt->type != OPT_END; opt++) { - char *p, *name; - - /* We don't handle subtables. */ - assert(!(opt->type & OPT_SUBTABLE)); - - if (!opt->names) - continue; - - /* Pull apart the option name(s). */ - name = strdup(opt->names); - for (p = strtok(name, "|"); p; p = strtok(NULL, "|")) { - char *err = NULL; - - /* Ignore short options. */ - if (p[1] != '-') - continue; - - val = json_object_get(config, p+2); - if (!val) - continue; - - if ((opt->type & OPT_HASARG) && json_is_string(val)) { - err = opt->cb_arg(json_string_value(val), - opt->u.arg); - } else if ((opt->type & OPT_HASARG) && json_is_array(val)) { - size_t n, size = json_array_size(val); - - for (n = 0; n < size && !err; n++) { - if (json_is_string(json_array_get(val, n))) - err = opt->cb_arg(json_string_value(json_array_get(val, n)), opt->u.arg); - else if (json_is_object(json_array_get(val, n))) - { - err = parse_config(json_array_get(val, n), false, n); - } - } - } else if ((opt->type & OPT_NOARG) && json_is_true(val)) - err = opt->cb(opt->u.arg); - else - err = "Invalid value"; - - if (err) { - /* Allow invalid values to be in configuration - * file, just skipping over them provided the - * JSON is still valid after that. */ - if (fileconf) { - applog(LOG_WARNING, "Skipping config option %s: %s", p, err); - fileconf_load = -1; - } else { - snprintf(err_buf, sizeof(err_buf), "Error parsing JSON option %s: %s", - p, err); - return err_buf; - } - } - } - free(name); - } - - val = json_object_get(config, JSON_INCLUDE_CONF); - if (val && json_is_string(val)) - return load_config(json_string_value(val), NULL); - - return NULL; -} - -char *cnfbuf = NULL; - -static char *load_config(const char *arg, void __maybe_unused *unused) -{ - json_error_t err; - json_t *config; - char *json_error; - size_t siz; - - if (!cnfbuf) - cnfbuf = strdup(arg); - - if (++include_count > JSON_MAX_DEPTH) - return JSON_MAX_DEPTH_ERR; - -#if JANSSON_MAJOR_VERSION > 1 - config = json_load_file(arg, 0, &err); -#else - config = json_load_file(arg, &err); -#endif - if (!json_is_object(config)) { - siz = JSON_LOAD_ERROR_LEN + strlen(arg) + strlen(err.text); - // TODO: memory leak - json_error = (char *)malloc(siz); - if (!json_error) - quit(1, "Malloc failure in json error"); - - snprintf(json_error, siz, JSON_LOAD_ERROR, arg, err.text); - return json_error; - } - - config_loaded = true; - - /* Parse the config now, so we can override it. That can keep pointers - * so don't free config object. */ - return parse_config(config, true, -1); -} - -static char *set_default_config(const char *arg) -{ - opt_set_charp(arg, &default_config); - - return NULL; -} - void default_save_file(char *filename); -static void load_default_config(void) -{ - cnfbuf = (char *)malloc(PATH_MAX); - - default_save_file(cnfbuf); - - if (!access(cnfbuf, R_OK)) - load_config(cnfbuf, NULL); - else { - free(cnfbuf); - cnfbuf = NULL; - } -} - extern const char *opt_argv0; static char *opt_verusage_and_exit(const char *extra) @@ -6195,32 +6106,49 @@ static void get_work_prepare_thread(struct thr_info *mythr, struct work *work) // Apply other pool-specific settings // TODO: when config parser is improved, add else statements and set // to default intensity - if (work->pool->intensity) + if(!empty_string(work->pool->intensity)) set_intensity(work->pool->intensity); - if (work->pool->xintensity) + else if(!empty_string(default_profile.intensity)) + set_intensity(default_profile.intensity); + + if (!empty_string(work->pool->xintensity)) set_xintensity(work->pool->xintensity); - if (work->pool->rawintensity) + else if(!empty_string(default_profile.xintensity)) + set_xintensity(default_profile.xintensity); + + if (!empty_string(work->pool->rawintensity)) set_rawintensity(work->pool->rawintensity); - if (work->pool->thread_concurrency) + else if(!empty_string(default_profile.rawintensity)) + set_rawintensity(default_profile.rawintensity); + + if (!empty_string(work->pool->thread_concurrency)) set_thread_concurrency(work->pool->thread_concurrency); - #ifdef HAVE_ADL - if (work->pool->gpu_engine) { + else if(!empty_string(default_profile.thread_concurrency)) + set_thread_concurrency(default_profile.thread_concurrency); + +#ifdef HAVE_ADL + if(!empty_string(work->pool->gpu_engine)) + { set_gpu_engine(work->pool->gpu_engine); for (i = 0; i < nDevs; i++) set_engineclock(i, gpus[i].min_engine); } - if (work->pool->gpu_memclock) { + + if(!empty_string(work->pool->gpu_memclock)) + { set_gpu_memclock(work->pool->gpu_memclock); for (i = 0; i < nDevs; i++) set_memoryclock(i, gpus[i].gpu_memclock); } - if (work->pool->gpu_fan) { + + if(!empty_string(work->pool->gpu_fan)) + { set_gpu_fan(work->pool->gpu_fan); for (i = 0; i < nDevs; i++) if (gpus[i].min_fan == gpus[i].gpu_fan) set_fanspeed(i, gpus[i].gpu_fan); } - #endif +#endif // Change algorithm for each thread (thread_prepare calls initCl) for (i = 0; i < mining_threads; i++) { struct thr_info *thr = mining_thr[i]; @@ -7952,6 +7880,15 @@ int main(int argc, char *argv[]) if (!config_loaded) load_default_config(); + //load default profile if specified in config + load_default_profile(); + + //apply default settings + apply_defaults(); + + //apply pool-specific config from profiles + apply_pool_profiles(); + if (opt_benchmark) { struct pool *pool;