diff --git a/AUTHORS.md b/AUTHORS.md index 20d634e5..41e3ba98 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -2,12 +2,19 @@ ## Core -* Multiple algorithms and switching: Jan Berdajs 15bULC8snaKAMeFb3xBmmhbWj1xyTmBUfm -* Historical scrypt-only refactor: Noel Maersk 12jF1VExtmmMu8D36vo4Y4CYqLK5yCtLC4 -* Core: Martin Danielsen 1DNBcSEENBwDKrcTyTW61ezWhzsPy5imkn +* Jan Berdajs 15bULC8snaKAMeFb3xBmmhbWj1xyTmBUfm +* Noel Maersk 12jF1VExtmmMu8D36vo4Y4CYqLK5yCtLC4 +* troky Letoqz4yEnJxjWw9B7Ysn8h9VDQTMDnT29 +* ystarnaud <**FIXME**> +* lasybear <**FIXME**> +* Luke Dashjr 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh +* Andrew Smith 1Jjk2LmktEQKnv8r2cZ9MvLiZwZ9gxabKm + + +## Core (history) + * Core: Con Kolivas 15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ -* Core: Luke Dashjr 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh -* API: Andrew Smith 1Jjk2LmktEQKnv8r2cZ9MvLiZwZ9gxabKm +* Martin Danielsen 1DNBcSEENBwDKrcTyTW61ezWhzsPy5imkn ## Cross-platform support @@ -21,6 +28,8 @@ ## OpenCL kernels +**FIXME**: this section is outdated. + All current kernels are based on `scrypt`, originally by Colin Percival, updated by many others. diff --git a/Makefile.am b/Makefile.am index 43ebec65..d89c4776 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,7 @@ sgminer_CPPFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\" endif sgminer_SOURCES := sgminer.c -sgminer_SOURCES += api.c +sgminer_SOURCES += api.c api.h sgminer_SOURCES += elist.h miner.h compat.h bench_block.h sgminer_SOURCES += util.c util.h uthash.h sgminer_SOURCES += logging.c logging.h @@ -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/NEWS.md b/NEWS.md index 73c66f92..b935396a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,11 +4,19 @@ * Added support for animecoin, darkcoin, fuguecoin, groestlcoin, inkcoin, marucoin, myriadcoin-groestl, quarkcoin, qubitcoin, sifcoin, twecoin, - darkcoin-mod ("X11-mod"), marucoin-mod ("X13-mod"), maxcoin (by mrbrdo). -* intensity, xintensity, rawintensity, gpu-memclock, gpu-engine, - thread-concurrency, gpu-threads now also have a `pool-*` version to - configure them for each pool separately (by mrbrdo). -* Extranonce support for stratum (by bitbandi). + darkcoin-mod ("X11-mod"), marucoin-mod ("X13-mod"), maxcoin (by + _mrbrdo_). +* `intensity`, `xintensity`, `rawintensity`, `gpu-memclock`, + `gpu-engine`, `thread-concurrency`, `gpu-threads` now also have a + `pool-*` version to configure them for each pool separately + (by _mrbrdo_). +* Initial configuration system revamping (by _ystarnaud_). +* Algorithm profile configuration (by _ystarnaud_). +* Complete configuration documentation, see `doc/configuration.md` (by + _ystarnaud_). +* API documentation update, see `doc/API.md` (by _ystarnaud_). +* Extranonce support for stratum (by _bitbandi_). + ## Version 4.2.1 - 22nd May 2014 diff --git a/adl.c b/adl.c index ca70701e..b71dd730 100644 --- a/adl.c +++ b/adl.c @@ -1208,7 +1208,7 @@ int set_fanspeed(int gpu, int iFanSpeed) } #ifdef HAVE_CURSES -static int set_powertune(int gpu, int iPercentage) +int set_powertune(int gpu, int iPercentage) { struct gpu_adl *ga; int dummy, ret = 1; diff --git a/adl.h b/adl.h index 7bdfa4ee..bf1eef4a 100644 --- a/adl.h +++ b/adl.h @@ -15,6 +15,7 @@ float gpu_vddc(int gpu); int gpu_activity(int gpu); int gpu_fanspeed(int gpu); int gpu_fanpercent(int gpu); +extern int set_powertune(int gpu, int iPercentage); bool gpu_stats(int gpu, float *temp, int *engineclock, int *memclock, float *vddc, int *activity, int *fanspeed, int *fanpercent, int *powertune); void change_gpusettings(int gpu); diff --git a/api.c b/api.c index 6983f927..c59448fb 100644 --- a/api.c +++ b/api.c @@ -26,77 +26,17 @@ #include #include "compat.h" +#include "api.h" #include "miner.h" #include "pool.h" #include "util.h" #include "pool.h" -// BUFSIZ varies on Windows and Linux -#define TMPBUFSIZ 8192 +#include "config_parser.h" -// Number of requests to queue - normally would be small -#define QUEUE 100 - -#if defined WIN32 +#ifdef WIN32 static char WSAbuf[1024]; -struct WSAERRORS { - int id; - char *code; -} WSAErrors[] = { - { 0, "No error" }, - { WSAEINTR, "Interrupted system call" }, - { WSAEBADF, "Bad file number" }, - { WSAEACCES, "Permission denied" }, - { WSAEFAULT, "Bad address" }, - { WSAEINVAL, "Invalid argument" }, - { WSAEMFILE, "Too many open sockets" }, - { WSAEWOULDBLOCK, "Operation would block" }, - { WSAEINPROGRESS, "Operation now in progress" }, - { WSAEALREADY, "Operation already in progress" }, - { WSAENOTSOCK, "Socket operation on non-socket" }, - { WSAEDESTADDRREQ, "Destination address required" }, - { WSAEMSGSIZE, "Message too long" }, - { WSAEPROTOTYPE, "Protocol wrong type for socket" }, - { WSAENOPROTOOPT, "Bad protocol option" }, - { WSAEPROTONOSUPPORT, "Protocol not supported" }, - { WSAESOCKTNOSUPPORT, "Socket type not supported" }, - { WSAEOPNOTSUPP, "Operation not supported on socket" }, - { WSAEPFNOSUPPORT, "Protocol family not supported" }, - { WSAEAFNOSUPPORT, "Address family not supported" }, - { WSAEADDRINUSE, "Address already in use" }, - { WSAEADDRNOTAVAIL, "Can't assign requested address" }, - { WSAENETDOWN, "Network is down" }, - { WSAENETUNREACH, "Network is unreachable" }, - { WSAENETRESET, "Net connection reset" }, - { WSAECONNABORTED, "Software caused connection abort" }, - { WSAECONNRESET, "Connection reset by peer" }, - { WSAENOBUFS, "No buffer space available" }, - { WSAEISCONN, "Socket is already connected" }, - { WSAENOTCONN, "Socket is not connected" }, - { WSAESHUTDOWN, "Can't send after socket shutdown" }, - { WSAETOOMANYREFS, "Too many references, can't splice" }, - { WSAETIMEDOUT, "Connection timed out" }, - { WSAECONNREFUSED, "Connection refused" }, - { WSAELOOP, "Too many levels of symbolic links" }, - { WSAENAMETOOLONG, "File name too long" }, - { WSAEHOSTDOWN, "Host is down" }, - { WSAEHOSTUNREACH, "No route to host" }, - { WSAENOTEMPTY, "Directory not empty" }, - { WSAEPROCLIM, "Too many processes" }, - { WSAEUSERS, "Too many users" }, - { WSAEDQUOT, "Disc quota exceeded" }, - { WSAESTALE, "Stale NFS file handle" }, - { WSAEREMOTE, "Too many levels of remote in path" }, - { WSASYSNOTREADY, "Network system is unavailable" }, - { WSAVERNOTSUPPORTED, "Winsock version out of range" }, - { WSANOTINITIALISED, "WSAStartup not yet called" }, - { WSAEDISCON, "Graceful shutdown in progress" }, - { WSAHOST_NOT_FOUND, "Host not found" }, - { WSANO_DATA, "No host data of that type was found" }, - { -1, "Unknown error code" } -}; - char *WSAErrorMsg(void) { int i; int id = WSAGetLastError(); @@ -112,236 +52,8 @@ char *WSAErrorMsg(void) { } #endif -static const char *UNAVAILABLE = " - API will not be available"; -static const char *MUNAVAILABLE = " - API multicast listener will not be available"; - -static const char *BLANK = ""; -static const char *COMMA = ","; -#define COMSTR "," -static const char SEPARATOR = '|'; -#define SEPSTR "|" -static const char GPUSEP = ','; - -#define CMDJOIN '+' -#define JOIN_CMD "CMD=" -#define BETWEEN_JOIN SEPSTR - -static const char *APIVERSION = "3.2"; -static const char *DEAD = "Dead"; -static const char *SICK = "Sick"; -static const char *NOSTART = "NoStart"; -static const char *INIT = "Initialising"; -static const char *DISABLED = "Disabled"; -static const char *ALIVE = "Alive"; -static const char *REJECTING = "Rejecting"; -static const char *UNKNOWN = "Unknown"; -#define _DYNAMIC "D" -static const char *DYNAMIC = _DYNAMIC; - -static __maybe_unused const char *NONE = "None"; - -static const char *YES = "Y"; -static const char *NO = "N"; -static const char *NULLSTR = "(null)"; - -static const char *TRUESTR = "true"; -static const char *FALSESTR = "false"; - -static const char *DEVICECODE = "GPU "; - -static const char *OSINFO = -#if defined(__linux__) - "Linux"; -#elif defined(__APPLE__) - "Apple"; -#elif defined(WIN32) - "Windows"; -#elif defined(__CYGWIN__) - "Cygwin"; -#elif defined(__unix__) - "Unix"; -#else - "Unknown"; -#endif - -#define _DEVS "DEVS" -#define _POOLS "POOLS" -#define _SUMMARY "SUMMARY" -#define _STATUS "STATUS" -#define _VERSION "VERSION" -#define _MINECONFIG "CONFIG" -#define _GPU "GPU" - -#define _GPUS "GPUS" -#define _NOTIFY "NOTIFY" -#define _DEVDETAILS "DEVDETAILS" -#define _BYE "BYE" -#define _RESTART "RESTART" -#define _MINESTATS "STATS" -#define _CHECK "CHECK" -#define _MINECOIN "COIN" -#define _DEBUGSET "DEBUG" -#define _SETCONFIG "SETCONFIG" - -static const char ISJSON = '{'; -#define JSON0 "{" -#define JSON1 "\"" -#define JSON2 "\":[" -#define JSON3 "]" -#define JSON4 ",\"id\":1" -// If anyone cares, id=0 for truncated output -#define JSON4_TRUNCATED ",\"id\":0" -#define JSON5 "}" - -#define JSON_START JSON0 -#define JSON_DEVS JSON1 _DEVS JSON2 -#define JSON_POOLS JSON1 _POOLS JSON2 -#define JSON_SUMMARY JSON1 _SUMMARY JSON2 -#define JSON_STATUS JSON1 _STATUS JSON2 -#define JSON_VERSION JSON1 _VERSION JSON2 -#define JSON_MINECONFIG JSON1 _MINECONFIG JSON2 -#define JSON_GPU JSON1 _GPU JSON2 - -#define JSON_GPUS JSON1 _GPUS JSON2 -#define JSON_NOTIFY JSON1 _NOTIFY JSON2 -#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2 -#define JSON_CLOSE JSON3 -#define JSON_MINESTATS JSON1 _MINESTATS JSON2 -#define JSON_CHECK JSON1 _CHECK JSON2 -#define JSON_MINECOIN JSON1 _MINECOIN JSON2 -#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 -#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 - -#define JSON_END JSON4 JSON5 -#define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 -#define JSON_BETWEEN_JOIN "," - -static const char *JSON_COMMAND = "command"; -static const char *JSON_PARAMETER = "parameter"; - -#define MSG_INVGPU 1 -#define MSG_ALRENA 2 -#define MSG_ALRDIS 3 -#define MSG_GPUMRE 4 -#define MSG_GPUREN 5 -#define MSG_GPUNON 6 -#define MSG_POOL 7 -#define MSG_NOPOOL 8 -#define MSG_DEVS 9 -#define MSG_NODEVS 10 -#define MSG_SUMM 11 -#define MSG_GPUDIS 12 -#define MSG_GPUREI 13 -#define MSG_INVCMD 14 -#define MSG_MISID 15 -#define MSG_GPUDEV 17 - -#define MSG_NUMGPU 20 - -#define MSG_VERSION 22 -#define MSG_INVJSON 23 -#define MSG_MISCMD 24 -#define MSG_MISPID 25 -#define MSG_INVPID 26 -#define MSG_SWITCHP 27 -#define MSG_MISVAL 28 -#define MSG_NOADL 29 -#define MSG_NOGPUADL 30 -#define MSG_INVINT 31 -#define MSG_GPUINT 32 -#define MSG_MINECONFIG 33 -#define MSG_GPUMERR 34 -#define MSG_GPUMEM 35 -#define MSG_GPUEERR 36 -#define MSG_GPUENG 37 -#define MSG_GPUVERR 38 -#define MSG_GPUVDDC 39 -#define MSG_GPUFERR 40 -#define MSG_GPUFAN 41 -#define MSG_MISFN 42 -#define MSG_BADFN 43 -#define MSG_SAVED 44 -#define MSG_ACCDENY 45 -#define MSG_ACCOK 46 -#define MSG_ENAPOOL 47 -#define MSG_DISPOOL 48 -#define MSG_ALRENAP 49 -#define MSG_ALRDISP 50 -#define MSG_MISPDP 52 -#define MSG_INVPDP 53 -#define MSG_TOOMANYP 54 -#define MSG_ADDPOOL 55 - -#define MSG_NOTIFY 60 - -#define MSG_REMLASTP 66 -#define MSG_ACTPOOL 67 -#define MSG_REMPOOL 68 -#define MSG_DEVDETAILS 69 -#define MSG_MINESTATS 70 -#define MSG_MISCHK 71 -#define MSG_CHECK 72 -#define MSG_POOLPRIO 73 -#define MSG_DUPPID 74 -#define MSG_MISBOOL 75 -#define MSG_INVBOOL 76 -#define MSG_FOO 77 -#define MSG_MINECOIN 78 -#define MSG_DEBUGSET 79 -#define MSG_SETCONFIG 82 -#define MSG_UNKCON 83 -#define MSG_INVNUM 84 -#define MSG_CONPAR 85 -#define MSG_CONVAL 86 - -#define MSG_NOUSTA 88 - -#define MSG_ZERMIS 94 -#define MSG_ZERINV 95 -#define MSG_ZERSUM 96 -#define MSG_ZERNOSUM 97 - -#define MSG_BYE 0x101 - -#define MSG_INVNEG 121 -#define MSG_SETQUOTA 122 -#define MSG_LOCKOK 123 -#define MSG_LOCKDIS 124 - -enum code_severity { - SEVERITY_ERR, - SEVERITY_WARN, - SEVERITY_INFO, - SEVERITY_SUCC, - SEVERITY_FAIL -}; - -enum code_parameters { - PARAM_GPU, - PARAM_PID, - PARAM_GPUMAX, - PARAM_PMAX, - PARAM_POOLMAX, - -// Single generic case: have the code resolve it - see below - PARAM_DMAX, - - PARAM_CMD, - PARAM_POOL, - PARAM_STR, - PARAM_BOTH, - PARAM_BOOL, - PARAM_SET, - PARAM_INT, - PARAM_NONE -}; -struct CODES { - const enum code_severity severity; - const int code; - const enum code_parameters params; - const char *description; -} codes[] = { +struct CODES codes[] = { { SEVERITY_ERR, MSG_INVGPU, PARAM_GPUMAX, "Invalid GPU id %d - range is 0 - %d" }, { SEVERITY_INFO, MSG_ALRENA, PARAM_GPU, "GPU %d already enabled" }, { SEVERITY_INFO, MSG_ALRDIS, PARAM_GPU, "GPU %d already disabled" }, @@ -424,10 +136,78 @@ struct CODES { { SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" }, { SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" }, { SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" }, + { SEVERITY_SUCC, MSG_CHSTRAT, PARAM_STR, "Multipool strategy changed to '%s'" }, + { SEVERITY_ERR, MSG_MISSTRAT, PARAM_NONE, "Missing multipool strategy" }, + { SEVERITY_ERR, MSG_INVSTRAT, PARAM_NONE, "Invalid multipool strategy %d" }, + { SEVERITY_ERR, MSG_MISSTRATINT, PARAM_NONE, "Missing rotate interval" }, + + { SEVERITY_SUCC, MSG_PROFILE, PARAM_PRMAX, "%d Profile(s)" }, + { SEVERITY_ERR, MSG_NOPROFILE, PARAM_NONE, "No profiles" }, + + { SEVERITY_ERR, MSG_PROFILEEXIST, PARAM_STR, "Profile '%s' already exists" }, + { SEVERITY_ERR, MSG_MISPRD, PARAM_NONE, "Missing addprofile details" }, + { SEVERITY_SUCC, MSG_ADDPROFILE, PARAM_STR, "Added profile '%s'" }, + + { SEVERITY_ERR, MSG_MISPRID, PARAM_STR, "Profile name missing" }, + { SEVERITY_ERR, MSG_PRNOEXIST, PARAM_STR, "Profile '%s' doesn't exist" }, + { SEVERITY_ERR, MSG_PRISDEFAULT, PARAM_STR, "Profile '%s' is the default profile" }, + { SEVERITY_ERR, MSG_PRINUSE, PARAM_STR, "Profile '%s' is used by a pool" }, + { SEVERITY_SUCC, MSG_REMPROFILE, PARAM_BOTH, "Removed pool %d:'%s'" }, + + { SEVERITY_SUCC, MSG_CHPOOLPR, PARAM_BOTH, "Changed pool %d to profile '%s'" }, + { SEVERITY_SUCC, MSG_BYE, PARAM_STR, "%s" }, { SEVERITY_FAIL, 0, (enum code_parameters)0, NULL } }; + +static const char *UNAVAILABLE = " - API will not be available"; +static const char *MUNAVAILABLE = " - API multicast listener will not be available"; + +static const char *BLANK = ""; +static const char *COMMA = ","; +static const char SEPARATOR = '|'; +static const char GPUSEP = ','; +static const char *APIVERSION = "4.0"; +static const char *DEAD = "Dead"; +static const char *SICK = "Sick"; +static const char *NOSTART = "NoStart"; +static const char *INIT = "Initialising"; +static const char *DISABLED = "Disabled"; +static const char *ALIVE = "Alive"; +static const char *REJECTING = "Rejecting"; +static const char *UNKNOWN = "Unknown"; +static const char *DYNAMIC = _DYNAMIC; + +static __maybe_unused const char *NONE = "None"; + +static const char *YES = "Y"; +static const char *NO = "N"; +static const char *NULLSTR = "(null)"; + +static const char *TRUESTR = "true"; +static const char *FALSESTR = "false"; + +static const char *DEVICECODE = "GPU "; + +static const char *OSINFO = +#if defined(__linux__) + "Linux"; +#elif defined(__APPLE__) + "Apple"; +#elif defined(WIN32) + "Windows"; +#elif defined(__CYGWIN__) + "Cygwin"; +#elif defined(__unix__) + "Unix"; +#else + "Unknown"; +#endif + +static const char *JSON_COMMAND = "command"; +static const char *JSON_PARAMETER = "parameter"; +static const char ISJSON = '{'; static const char *localaddr = "127.0.0.1"; static int my_thr_id = 0; @@ -441,50 +221,11 @@ static bool do_a_restart; static time_t when = 0; // when the request occurred -struct IP4ACCESS { - in_addr_t ip; - in_addr_t mask; - char group; -}; - -#define GROUP(g) (toupper(g)) -#define PRIVGROUP GROUP('W') -#define NOPRIVGROUP GROUP('R') -#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) -#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) -#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) -#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) -#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) - -struct APIGROUPS { - // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search - char *commands; -} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) - static struct IP4ACCESS *ipaccess = NULL; static int ips = 0; -struct io_data { - size_t siz; - char *ptr; - char *cur; - bool sock; - bool close; -}; - -struct io_list { - struct io_data *io_data; - struct io_list *prev; - struct io_list *next; -}; - static struct io_list *io_head = NULL; -#define SOCKBUFALLOCSIZ 65536 - -#define io_new(init) _io_new(init, false) -#define sock_io_new() _io_new(SOCKBUFALLOCSIZ, true) - static void io_reinit(struct io_data *io_data) { io_data->cur = io_data->ptr; @@ -521,7 +262,7 @@ static struct io_data *_io_new(size_t initial, bool socket_buf) return io_data; } -static bool io_add(struct io_data *io_data, char *buf) +bool io_add(struct io_data *io_data, char *buf) { size_t len, dif, tot; @@ -547,12 +288,12 @@ static bool io_add(struct io_data *io_data, char *buf) return true; } -static void io_close(struct io_data *io_data) +void io_close(struct io_data *io_data) { io_data->close = true; } -static void io_free() +void io_free() { struct io_list *io_list, *io_next; @@ -902,7 +643,7 @@ struct api_data *api_add_avg(struct api_data *root, char *name, float *data, boo return api_add_data_full(root, name, API_AVG, (void *)data, copy_data); } -static struct api_data *print_data(struct api_data *root, char *buf, bool isjson, bool precom) +struct api_data *print_data(struct api_data *root, char *buf, bool isjson, bool precom) { struct api_data *tmp; bool first = true; @@ -1045,7 +786,7 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson // All replies (except BYE and RESTART) start with a message // thus for JSON, message() inserts JSON_START at the front // and send_result() adds JSON_END at the end -static void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson) +void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson) { struct api_data *root = NULL; char buf[TMPBUFSIZ]; @@ -1091,6 +832,9 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p case PARAM_PMAX: sprintf(buf, codes[i].description, total_pools); break; + case PARAM_PRMAX: + sprintf(buf, codes[i].description, total_profiles); + break; case PARAM_POOLMAX: sprintf(buf, codes[i].description, paramid, total_pools - 1); break; @@ -1147,49 +891,6 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p #if LOCK_TRACKING -#define LOCK_FMT_FFL " - called from %s %s():%d" - -#define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__) -#define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__) -#define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum) -#define LOCKMSGFLUSH() fflush(stderr) - -typedef struct lockstat { - uint64_t lock_id; - const char *file; - const char *func; - int linenum; - struct timeval tv; -} LOCKSTAT; - -typedef struct lockline { - struct lockline *prev; - struct lockstat *stat; - struct lockline *next; -} LOCKLINE; - -typedef struct lockinfo { - void *lock; - enum cglock_typ typ; - const char *file; - const char *func; - int linenum; - uint64_t gets; - uint64_t gots; - uint64_t tries; - uint64_t dids; - uint64_t didnts; // should be tries - dids - uint64_t unlocks; - LOCKSTAT lastgot; - LOCKLINE *lockgets; - LOCKLINE *locktries; -} LOCKINFO; - -typedef struct locklist { - LOCKINFO *info; - struct locklist *next; -} LOCKLIST; - static uint64_t lock_id = 1; static LOCKLIST *lockhead; @@ -1532,6 +1233,23 @@ void show_locks() } #endif +static void copyadvanceafter(char ch, char **param, char **buf) +{ +#define src_p (*param) +#define dst_b (*buf) + + while (*src_p && *src_p != ch) { + if (*src_p == '\\' && *(src_p+1) != '\0') + src_p++; + + *(dst_b++) = *(src_p++); + } + if (*src_p) + src_p++; + + *(dst_b++) = '\0'; +} + static void lockstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) { #if LOCK_TRACKING @@ -1822,6 +1540,7 @@ 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_string(root, "Description", pool->description, false); root = api_add_string(root, "Status", status, false); @@ -2099,25 +1818,74 @@ static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha message(io_data, MSG_SWITCHP, id, NULL, isjson); } -static void copyadvanceafter(char ch, char **param, char **buf) +static void api_pool_strategy(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { -#define src_p (*param) -#define dst_b (*buf) + char *p; + int strategy; + + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } - while (*src_p && *src_p != ch) { - if (*src_p == '\\' && *(src_p+1) != '\0') - src_p++; + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISSTRAT, 0, NULL, isjson); + return; + } - *(dst_b++) = *(src_p++); + //get strategy in parameter 1 + if(!(p = strtok(param, ","))) + { + message(io_data, MSG_MISSTRAT, 0, NULL, isjson); + return; } - if (*src_p) - src_p++; + + strategy = atoi(p); - *(dst_b++) = '\0'; + //invalid strategy + if(strategy < 0 || strategy > TOP_STRATEGY) + { + message(io_data, MSG_INVSTRAT, strategy, NULL, isjson); + return; + } + + //if set to rotate, get second param + if(strategy == POOL_ROTATE) + { + //if second param is missing then invalid + if(!(p = strtok(NULL, ","))) + { + message(io_data, MSG_MISSTRATINT, 0, NULL, isjson); + return; + } + + //get interval in parameter 2 + int interval; + interval = atoi(p); + + //interval can only be between 0 and 9999 + if(interval < 0 || interval > 9999) + { + message(io_data, MSG_INVNUM, interval, "interval", isjson); + return; + } + + //set interval + opt_rotate_period = interval; + } + + //set pool strategy + pool_strategy = (enum pool_strategy)strategy; + //initiate new strategy + switch_pools(NULL); + + message(io_data, MSG_CHSTRAT, 0, (char *)strategies[strategy].s, isjson); } static bool pooldetails(char *param, char **url, char **user, char **pass, - char **name, char **desc, char **algo) + char **name, char **desc, char **profile, char **algo) { char *ptr, *buf; @@ -2132,23 +1900,28 @@ static bool pooldetails(char *param, char **url, char **user, char **pass, *user = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing pass + if (!(*param)) // missing pass goto exitsama; *pass = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing name (allowed) + if (!(*param)) // missing name (allowed) return true; *name = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing desc - goto exitsama; + if (!(*param)) // missing desc + return true; *desc = buf; copyadvanceafter(',', ¶m, &buf); - if (!*param) // missing algo - goto exitsama; + if (!(*param)) // missing profile + return true; + + *profile = buf; + copyadvanceafter(',', ¶m, &buf); + if (!(*param)) // missing algo + return true; *algo = buf; copyadvanceafter(',', ¶m, &buf); @@ -2163,7 +1936,7 @@ exitsama: static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char *url, *user, *pass; - char *name = NULL, *desc = NULL, *algo = NULL; + char *name = NULL, *desc = NULL, *algo = NULL, *profile = NULL; struct pool *pool; char *ptr; @@ -2173,7 +1946,7 @@ static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char * } if (!pooldetails(param, &url, &user, &pass, - &name, &desc, &algo)) { + &name, &desc, &profile, &algo)) { ptr = escape_string(param, isjson); message(io_data, MSG_INVPDP, 0, ptr, isjson); if (ptr != param) @@ -2183,13 +1956,14 @@ static void addpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char * } /* If API client is old, it might not have provided all fields. */ - if (name == NULL) name = strdup(""); - if (desc == NULL) desc = strdup(""); - if (algo == NULL) algo = strdup("scrypt"); // FIXME? + name = ((name == NULL)?strdup(""):name); + desc = ((desc == NULL)?strdup(""):desc); + profile = ((profile == NULL)?strdup(""):profile); + algo = ((algo == NULL)?strdup(""):algo); pool = add_pool(); detect_stratum(pool, url); - add_pool_details(pool, true, url, user, pass, name, desc, algo); + add_pool_details(pool, true, url, user, pass, name, desc, profile, algo); ptr = escape_string(url, isjson); message(io_data, MSG_ADDPOOL, 0, ptr, isjson); @@ -2727,7 +2501,7 @@ static void devdetails(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) { char filename[PATH_MAX]; - FILE *fcfg; +// FILE *fcfg; char *ptr; if (param == NULL || *param == '\0') { @@ -2735,7 +2509,7 @@ void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, b param = filename; } - fcfg = fopen(param, "w"); + /*fcfg = fopen(param, "w"); if (!fcfg) { ptr = escape_string(param, isjson); message(io_data, MSG_BADFN, 0, ptr, isjson); @@ -2743,10 +2517,10 @@ void dosave(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, b free(ptr); ptr = NULL; return; - } + }*/ - write_config(fcfg); - fclose(fcfg); + write_config(param); + //fclose(fcfg); ptr = escape_string(param, isjson); message(io_data, MSG_SAVED, 0, ptr, isjson); @@ -3062,6 +2836,7 @@ struct CMDS { { "config", minerconfig, false, true }, { "devs", devstatus, false, true }, { "pools", poolstatus, false, true }, + { "profiles", api_profile_list, false, true }, { "summary", summary, false, true }, { "gpuenable", gpuenable, true, false }, { "gpudisable", gpudisable, true, false }, @@ -3069,12 +2844,16 @@ struct CMDS { { "gpu", gpudev, false, false }, { "gpucount", gpucount, false, true }, { "switchpool", switchpool, true, false }, + { "changestrategy", api_pool_strategy, true, false }, { "addpool", addpool, true, false }, { "poolpriority", poolpriority, true, false }, { "poolquota", poolquota, true, false }, { "enablepool", enablepool, true, false }, { "disablepool", disablepool, true, false }, { "removepool", removepool, true, false }, + { "changepoolprofile", api_pool_profile, true, false }, + { "addprofile", api_profile_add, true, false }, + { "removeprofile", api_profile_remove, true, false }, { "gpuintensity", gpuintensity, true, false }, { "gpumem", gpumem, true, false }, { "gpuengine", gpuengine, true, false }, diff --git a/api.h b/api.h new file mode 100644 index 00000000..243753eb --- /dev/null +++ b/api.h @@ -0,0 +1,398 @@ +#ifndef API_H +#define API_H + +#include "config.h" + +#include "miner.h" + +// BUFSIZ varies on Windows and Linux +#define TMPBUFSIZ 8192 + +// Number of requests to queue - normally would be small +#define QUEUE 100 + +#ifdef WIN32 +struct WSAERRORS { + int id; + char *code; +} WSAErrors[] = { + { 0, "No error" }, + { WSAEINTR, "Interrupted system call" }, + { WSAEBADF, "Bad file number" }, + { WSAEACCES, "Permission denied" }, + { WSAEFAULT, "Bad address" }, + { WSAEINVAL, "Invalid argument" }, + { WSAEMFILE, "Too many open sockets" }, + { WSAEWOULDBLOCK, "Operation would block" }, + { WSAEINPROGRESS, "Operation now in progress" }, + { WSAEALREADY, "Operation already in progress" }, + { WSAENOTSOCK, "Socket operation on non-socket" }, + { WSAEDESTADDRREQ, "Destination address required" }, + { WSAEMSGSIZE, "Message too long" }, + { WSAEPROTOTYPE, "Protocol wrong type for socket" }, + { WSAENOPROTOOPT, "Bad protocol option" }, + { WSAEPROTONOSUPPORT, "Protocol not supported" }, + { WSAESOCKTNOSUPPORT, "Socket type not supported" }, + { WSAEOPNOTSUPP, "Operation not supported on socket" }, + { WSAEPFNOSUPPORT, "Protocol family not supported" }, + { WSAEAFNOSUPPORT, "Address family not supported" }, + { WSAEADDRINUSE, "Address already in use" }, + { WSAEADDRNOTAVAIL, "Can't assign requested address" }, + { WSAENETDOWN, "Network is down" }, + { WSAENETUNREACH, "Network is unreachable" }, + { WSAENETRESET, "Net connection reset" }, + { WSAECONNABORTED, "Software caused connection abort" }, + { WSAECONNRESET, "Connection reset by peer" }, + { WSAENOBUFS, "No buffer space available" }, + { WSAEISCONN, "Socket is already connected" }, + { WSAENOTCONN, "Socket is not connected" }, + { WSAESHUTDOWN, "Can't send after socket shutdown" }, + { WSAETOOMANYREFS, "Too many references, can't splice" }, + { WSAETIMEDOUT, "Connection timed out" }, + { WSAECONNREFUSED, "Connection refused" }, + { WSAELOOP, "Too many levels of symbolic links" }, + { WSAENAMETOOLONG, "File name too long" }, + { WSAEHOSTDOWN, "Host is down" }, + { WSAEHOSTUNREACH, "No route to host" }, + { WSAENOTEMPTY, "Directory not empty" }, + { WSAEPROCLIM, "Too many processes" }, + { WSAEUSERS, "Too many users" }, + { WSAEDQUOT, "Disc quota exceeded" }, + { WSAESTALE, "Stale NFS file handle" }, + { WSAEREMOTE, "Too many levels of remote in path" }, + { WSASYSNOTREADY, "Network system is unavailable" }, + { WSAVERNOTSUPPORTED, "Winsock version out of range" }, + { WSANOTINITIALISED, "WSAStartup not yet called" }, + { WSAEDISCON, "Graceful shutdown in progress" }, + { WSAHOST_NOT_FOUND, "Host not found" }, + { WSANO_DATA, "No host data of that type was found" }, + { -1, "Unknown error code" } +}; +#endif + +#define COMSTR "," +#define SEPSTR "|" + +#define CMDJOIN '+' +#define JOIN_CMD "CMD=" +#define BETWEEN_JOIN SEPSTR +#define _DYNAMIC "D" + +#define _DEVS "DEVS" +#define _POOLS "POOLS" +#define _PROFILES "PROFILES" +#define _SUMMARY "SUMMARY" +#define _STATUS "STATUS" +#define _VERSION "VERSION" +#define _MINECONFIG "CONFIG" +#define _GPU "GPU" + +#define _GPUS "GPUS" +#define _NOTIFY "NOTIFY" +#define _DEVDETAILS "DEVDETAILS" +#define _BYE "BYE" +#define _RESTART "RESTART" +#define _MINESTATS "STATS" +#define _CHECK "CHECK" +#define _MINECOIN "COIN" +#define _DEBUGSET "DEBUG" +#define _SETCONFIG "SETCONFIG" + +#define JSON0 "{" +#define JSON1 "\"" +#define JSON2 "\":[" +#define JSON3 "]" +#define JSON4 ",\"id\":1" +// If anyone cares, id=0 for truncated output +#define JSON4_TRUNCATED ",\"id\":0" +#define JSON5 "}" + +#define JSON_START JSON0 +#define JSON_DEVS JSON1 _DEVS JSON2 +#define JSON_POOLS JSON1 _POOLS JSON2 +#define JSON_PROFILES JSON1 _POOLS JSON2 +#define JSON_SUMMARY JSON1 _SUMMARY JSON2 +#define JSON_STATUS JSON1 _STATUS JSON2 +#define JSON_VERSION JSON1 _VERSION JSON2 +#define JSON_MINECONFIG JSON1 _MINECONFIG JSON2 +#define JSON_GPU JSON1 _GPU JSON2 + +#define JSON_GPUS JSON1 _GPUS JSON2 +#define JSON_NOTIFY JSON1 _NOTIFY JSON2 +#define JSON_DEVDETAILS JSON1 _DEVDETAILS JSON2 +#define JSON_CLOSE JSON3 +#define JSON_MINESTATS JSON1 _MINESTATS JSON2 +#define JSON_CHECK JSON1 _CHECK JSON2 +#define JSON_MINECOIN JSON1 _MINECOIN JSON2 +#define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 +#define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 + +#define JSON_END JSON4 JSON5 +#define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 +#define JSON_BETWEEN_JOIN "," + +#define MSG_INVGPU 1 +#define MSG_ALRENA 2 +#define MSG_ALRDIS 3 +#define MSG_GPUMRE 4 +#define MSG_GPUREN 5 +#define MSG_GPUNON 6 +#define MSG_POOL 7 +#define MSG_NOPOOL 8 +#define MSG_DEVS 9 +#define MSG_NODEVS 10 +#define MSG_SUMM 11 +#define MSG_GPUDIS 12 +#define MSG_GPUREI 13 +#define MSG_INVCMD 14 +#define MSG_MISID 15 +#define MSG_GPUDEV 17 + +#define MSG_NUMGPU 20 + +#define MSG_VERSION 22 +#define MSG_INVJSON 23 +#define MSG_MISCMD 24 +#define MSG_MISPID 25 +#define MSG_INVPID 26 +#define MSG_SWITCHP 27 +#define MSG_MISVAL 28 +#define MSG_NOADL 29 +#define MSG_NOGPUADL 30 +#define MSG_INVINT 31 +#define MSG_GPUINT 32 +#define MSG_MINECONFIG 33 +#define MSG_GPUMERR 34 +#define MSG_GPUMEM 35 +#define MSG_GPUEERR 36 +#define MSG_GPUENG 37 +#define MSG_GPUVERR 38 +#define MSG_GPUVDDC 39 +#define MSG_GPUFERR 40 +#define MSG_GPUFAN 41 +#define MSG_MISFN 42 +#define MSG_BADFN 43 +#define MSG_SAVED 44 +#define MSG_ACCDENY 45 +#define MSG_ACCOK 46 +#define MSG_ENAPOOL 47 +#define MSG_DISPOOL 48 +#define MSG_ALRENAP 49 +#define MSG_ALRDISP 50 +#define MSG_MISPDP 52 +#define MSG_INVPDP 53 +#define MSG_TOOMANYP 54 +#define MSG_ADDPOOL 55 + +#define MSG_NOTIFY 60 + +#define MSG_REMLASTP 66 +#define MSG_ACTPOOL 67 +#define MSG_REMPOOL 68 +#define MSG_DEVDETAILS 69 +#define MSG_MINESTATS 70 +#define MSG_MISCHK 71 +#define MSG_CHECK 72 +#define MSG_POOLPRIO 73 +#define MSG_DUPPID 74 +#define MSG_MISBOOL 75 +#define MSG_INVBOOL 76 +#define MSG_FOO 77 +#define MSG_MINECOIN 78 +#define MSG_DEBUGSET 79 +#define MSG_SETCONFIG 82 +#define MSG_UNKCON 83 +#define MSG_INVNUM 84 +#define MSG_CONPAR 85 +#define MSG_CONVAL 86 + +#define MSG_NOUSTA 88 + +#define MSG_ZERMIS 94 +#define MSG_ZERINV 95 +#define MSG_ZERSUM 96 +#define MSG_ZERNOSUM 97 + +#define MSG_BYE 0x101 + +#define MSG_INVNEG 121 +#define MSG_SETQUOTA 122 +#define MSG_LOCKOK 123 +#define MSG_LOCKDIS 124 + +#define MSG_CHSTRAT 125 +#define MSG_MISSTRAT 126 +#define MSG_INVSTRAT 127 +#define MSG_MISSTRATINT 128 + +#define MSG_PROFILE 129 +#define MSG_NOPROFILE 130 + +#define MSG_PROFILEEXIST 131 +#define MSG_MISPRD 132 +#define MSG_ADDPROFILE 133 + +#define MSG_MISPRID 134 +#define MSG_PRNOEXIST 135 +#define MSG_PRISDEFAULT 136 +#define MSG_PRINUSE 137 +#define MSG_REMPROFILE 138 + +#define MSG_CHPOOLPR 139 + +enum code_severity { + SEVERITY_ERR, + SEVERITY_WARN, + SEVERITY_INFO, + SEVERITY_SUCC, + SEVERITY_FAIL +}; + +enum code_parameters { + PARAM_GPU, + PARAM_PID, + PARAM_GPUMAX, + PARAM_PMAX, + PARAM_PRMAX, + PARAM_POOLMAX, + +// Single generic case: have the code resolve it - see below + PARAM_DMAX, + + PARAM_CMD, + PARAM_POOL, + PARAM_STR, + PARAM_BOTH, + PARAM_BOOL, + PARAM_SET, + PARAM_INT, + PARAM_NONE +}; + +struct CODES { + const enum code_severity severity; + const int code; + const enum code_parameters params; + const char *description; +}; + +extern struct CODES codes[]; + +struct IP4ACCESS { + in_addr_t ip; + in_addr_t mask; + char group; +}; + +#define GROUP(g) (toupper(g)) +#define PRIVGROUP GROUP('W') +#define NOPRIVGROUP GROUP('R') +#define ISPRIVGROUP(g) (GROUP(g) == PRIVGROUP) +#define GROUPOFFSET(g) (GROUP(g) - GROUP('A')) +#define VALIDGROUP(g) (GROUP(g) >= GROUP('A') && GROUP(g) <= GROUP('Z')) +#define COMMANDS(g) (apigroups[GROUPOFFSET(g)].commands) +#define DEFINEDGROUP(g) (ISPRIVGROUP(g) || COMMANDS(g) != NULL) + +struct APIGROUPS { + // This becomes a string like: "|cmd1|cmd2|cmd3|" so it's quick to search + char *commands; +} apigroups['Z' - 'A' + 1]; // only A=0 to Z=25 (R: noprivs, W: allprivs) + +struct io_data { + size_t siz; + char *ptr; + char *cur; + bool sock; + bool close; +}; + +struct io_list { + struct io_data *io_data; + struct io_list *prev; + struct io_list *next; +}; + +extern void message(struct io_data *io_data, int messageid, int paramid, char *param2, bool isjson); +extern bool io_add(struct io_data *io_data, char *buf); +extern void io_close(struct io_data *io_data); +extern void io_free(); + +extern struct api_data *api_add_escape(struct api_data *root, char *name, char *data, bool copy_data); +extern struct api_data *api_add_string(struct api_data *root, char *name, char *data, bool copy_data); +extern struct api_data *api_add_const(struct api_data *root, char *name, const char *data, bool copy_data); +extern struct api_data *api_add_uint8(struct api_data *root, char *name, uint8_t *data, bool copy_data); +extern struct api_data *api_add_uint16(struct api_data *root, char *name, uint16_t *data, bool copy_data); +extern struct api_data *api_add_int(struct api_data *root, char *name, int *data, bool copy_data); +extern struct api_data *api_add_uint(struct api_data *root, char *name, unsigned int *data, bool copy_data); +extern struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *data, bool copy_data); +extern struct api_data *api_add_hex32(struct api_data *root, char *name, uint32_t *data, bool copy_data); +extern struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data); +extern struct api_data *api_add_double(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_elapsed(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_bool(struct api_data *root, char *name, bool *data, bool copy_data); +extern struct api_data *api_add_timeval(struct api_data *root, char *name, struct timeval *data, bool copy_data); +extern struct api_data *api_add_time(struct api_data *root, char *name, time_t *data, bool copy_data); +extern struct api_data *api_add_mhs(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_khs(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_mhtotal(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_temp(struct api_data *root, char *name, float *data, bool copy_data); +extern struct api_data *api_add_utility(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_freq(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_volts(struct api_data *root, char *name, float *data, bool copy_data); +extern struct api_data *api_add_hs(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_diff(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_percent(struct api_data *root, char *name, double *data, bool copy_data); +extern struct api_data *api_add_avg(struct api_data *root, char *name, float *data, bool copy_data); +extern struct api_data *print_data(struct api_data *root, char *buf, bool isjson, bool precom); + +#define SOCKBUFALLOCSIZ 65536 + +#define io_new(init) _io_new(init, false) +#define sock_io_new() _io_new(SOCKBUFALLOCSIZ, true) + +#if LOCK_TRACKING + + #define LOCK_FMT_FFL " - called from %s %s():%d" + #define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__) + #define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__) + #define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum) + #define LOCKMSGFLUSH() fflush(stderr) + + typedef struct lockstat { + uint64_t lock_id; + const char *file; + const char *func; + int linenum; + struct timeval tv; + } LOCKSTAT; + + typedef struct lockline { + struct lockline *prev; + struct lockstat *stat; + struct lockline *next; + } LOCKLINE; + + typedef struct lockinfo { + void *lock; + enum cglock_typ typ; + const char *file; + const char *func; + int linenum; + uint64_t gets; + uint64_t gots; + uint64_t tries; + uint64_t dids; + uint64_t didnts; // should be tries - dids + uint64_t unlocks; + LOCKSTAT lastgot; + LOCKLINE *lockgets; + LOCKLINE *locktries; + } LOCKINFO; + + typedef struct locklist { + LOCKINFO *info; + struct locklist *next; + } LOCKLIST; +#endif + +#endif /* API_H */ \ No newline at end of file diff --git a/config_parser.c b/config_parser.c new file mode 100644 index 00000000..371d7a7a --- /dev/null +++ b/config_parser.c @@ -0,0 +1,2029 @@ +/* + * 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" + +#ifdef HAVE_ADL +#include "adl.h" +#endif + +#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_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; +} + +static void remove_profile(struct profile *profile) +{ + int i; + int found = 0; + + for(i = 0; i < (total_profiles - 1); i++) + { + //look for the profile + if(profiles[i]->profile_no == profile->profile_no) + found = 1; + + //once we found the profile, change the current index profile to next + if(found) + { + profiles[i] = profiles[i+1]; + profiles[i]->profile_no = i; + } + } + + //give the profile an invalid number and remove + profile->profile_no = total_profiles; + profile->removed = true; + total_profiles--; +} + +//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_devices(const char *arg) +{ + default_profile.devices = arg; + return NULL; +} + +char *set_default_lookup_gap(const char *arg) +{ + default_profile.lookup_gap = arg; + return NULL; +} + +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; + } + + char *set_default_gpu_powertune(const char *arg) + { + default_profile.gpu_powertune = arg; + return NULL; + } + + char *set_default_gpu_vddc(const char *arg) + { + default_profile.gpu_vddc = arg; + return NULL; + } + +#endif + +char *set_default_profile(char *arg) +{ + default_profile.name = arg; + return NULL; +} + +char *set_default_shaders(const char *arg) +{ + default_profile.shaders = arg; + return NULL; +} + +char *set_default_worksize(const char *arg) +{ + default_profile.worksize = arg; + return NULL; +} + +/****** Profile functions used in during config parsing ********/ +char *set_profile_name(const 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_devices(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->devices = arg; + return NULL; +} + +char *set_profile_lookup_gap(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->lookup_gap = 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; + } + + char *set_profile_gpu_powertune(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_powertune = arg; + return NULL; + } + + char *set_profile_gpu_vddc(const char *arg) + { + struct profile *profile = get_current_profile(); + profile->gpu_vddc = 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; +} + +char *set_profile_shaders(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->shaders = arg; + return NULL; +} + +char *set_profile_worksize(const char *arg) +{ + struct profile *profile = get_current_profile(); + profile->worksize = arg; + return NULL; +} + +/*************************************** +* Helper Functions +****************************************/ +json_t *json_sprintf(const char *fmt, ...) +{ + va_list args; + char *buf; + size_t bufsize; + + //build args + va_start(args, fmt); + //get final string buffer size + bufsize = vsnprintf(NULL, 0, fmt, args); + va_end(args); + + if(!(buf = (char *)malloc(++bufsize))) + quit(1, "Malloc failure in config_parser::json_sprintf()."); + + //zero out buffer + memset(buf, '\0', bufsize); + + //get args again + va_start(args, fmt); + vsnprintf(buf, bufsize, fmt, args); + va_end(args); + + //return json string + return json_string(buf); +} + +//set last json error +char *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, fmt, args); + va_end(args); + + //if NULL allocate memory... otherwise reallocate + if(!last_json_error) + { + if(!(last_json_error = (char *)malloc(++bufsize))) + quit(1, "Malloc failure in config_parser::set_last_json_error()."); + } + else + { + if(!(last_json_error = (char *)realloc(last_json_error, ++bufsize))) + quit(1, "Realloc failure in config_parser::set_last_json_error()."); + } + + //zero out buffer + memset(last_json_error, '\0', bufsize); + + //get args again + va_start(args, fmt); + vsnprintf(last_json_error, bufsize, fmt, args); + va_end(args); + + return last_json_error; +} + +//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)) + return set_last_json_error("Error: JSON decode of file \"%s\" failed:\n %s", arg, err.text); + + 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.devices = profile->devices; + default_profile.lookup_gap = profile->lookup_gap; + 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; + default_profile.gpu_powertune = profile->gpu_powertune; + default_profile.gpu_vddc = profile->gpu_vddc; +#endif + default_profile.shaders = profile->shaders; + default_profile.worksize = profile->worksize; + } + } +} + +//apply default settings +void apply_defaults() +{ + set_algorithm(&opt_algorithm, default_profile.algorithm.name); + + if(!empty_string(default_profile.devices)) + set_devices((char *)default_profile.devices); + + 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.lookup_gap)) + set_lookup_gap((char *)default_profile.lookup_gap); + + 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); + + if(!empty_string(default_profile.gpu_powertune)) + set_gpu_powertune((char *)default_profile.gpu_powertune); + + if(!empty_string(default_profile.gpu_vddc)) + set_gpu_vddc((char *)default_profile.gpu_vddc); +#endif + + if(!empty_string(default_profile.shaders)) + set_shaders((char *)default_profile.shaders); + + if(!empty_string(default_profile.worksize)) + set_worksize((char *)default_profile.worksize); +} + +//apply profile settings to pools +void apply_pool_profiles() +{ + int i; + + for(i=total_pools;i--;) + { + apply_pool_profile(pools[i]); + } +} + +void apply_pool_profile(struct pool *pool) +{ + struct profile *profile; + + //if the pool has a profile set + if(!empty_string(pool->profile)) + { + applog(LOG_DEBUG, "Loading settings from profile \"%s\" for pool %i", pool->profile, pool->pool_no); + + //find profile and apply settings to the pool + if((profile = get_profile(pool->profile))) + { + pool->algorithm = profile->algorithm; + applog(LOG_DEBUG, "Pool %i Algorithm set to \"%s\"", pool->pool_no, pool->algorithm.name); + + pool->devices = profile->devices; + applog(LOG_DEBUG, "Pool %i devices set to \"%s\"", pool->pool_no, pool->devices); + + pool->lookup_gap = profile->lookup_gap; + applog(LOG_DEBUG, "Pool %i lookup gap set to \"%s\"", pool->pool_no, pool->lookup_gap); + + pool->intensity = profile->intensity; + applog(LOG_DEBUG, "Pool %i Intensity set to \"%s\"", pool->pool_no, pool->intensity); + + pool->xintensity = profile->xintensity; + applog(LOG_DEBUG, "Pool %i XIntensity set to \"%s\"", pool->pool_no, pool->xintensity); + + pool->rawintensity = profile->rawintensity; + applog(LOG_DEBUG, "Pool %i Raw Intensity set to \"%s\"", pool->pool_no, pool->rawintensity); + + pool->thread_concurrency = profile->thread_concurrency; + applog(LOG_DEBUG, "Pool %i Thread Concurrency set to \"%s\"", pool->pool_no, pool->thread_concurrency); + +#ifdef HAVE_ADL + pool->gpu_engine = profile->gpu_engine; + applog(LOG_DEBUG, "Pool %i GPU Clock set to \"%s\"", pool->pool_no, pool->gpu_engine); + + pool->gpu_memclock = profile->gpu_memclock; + applog(LOG_DEBUG, "Pool %i GPU Memory clock set to \"%s\"", pool->pool_no, pool->gpu_memclock); + + pool->gpu_threads = profile->gpu_threads; + applog(LOG_DEBUG, "Pool %i GPU Threads set to \"%s\"", pool->pool_no, pool->gpu_threads); + + pool->gpu_fan = profile->gpu_fan; + applog(LOG_DEBUG, "Pool %i GPU Fan set to \"%s\"", pool->pool_no, pool->gpu_fan); + + pool->gpu_powertune = profile->gpu_powertune; + applog(LOG_DEBUG, "Pool %i GPU Powertune set to \"%s\"", pool->pool_no, pool->gpu_powertune); + + pool->gpu_vddc = profile->gpu_vddc; + applog(LOG_DEBUG, "Pool %i GPU Vddc set to \"%s\"", pool->pool_no, pool->gpu_vddc); +#endif + + pool->shaders = profile->shaders; + applog(LOG_DEBUG, "Pool %i Shaders set to \"%s\"", pool->pool_no, pool->shaders); + + pool->worksize = profile->worksize; + applog(LOG_DEBUG, "Pool %i Worksize set to \"%s\"", pool->pool_no, pool->worksize); + } + else + { + applog(LOG_DEBUG, "Profile load failed for pool %i: profile %s not found.", pool->pool_no, pool->profile); + //remove profile name + pool->profile[0] = '\0'; + } + } +} + +//helper function to add json values to pool object +static bool build_pool_json_add(json_t *object, const char *key, const char *val, const char *str_compare, int id) +{ + if(!empty_string(val)) + { + if(safe_cmp(str_compare, val)) + { + if(json_object_set(object, key, json_string(val)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):%s", id, key); + return false; + } + } + } + + return true; +} + +//builds the "pools" json array for config file +json_t *build_pool_json() +{ + json_t *pool_array, *obj; + struct pool *pool; + struct profile *profile; + int i; + + //create the "pools" array + if(!(pool_array = json_array())) + { + set_last_json_error("json_array() failed on pools"); + return NULL; + } + + //process pool entries + for(i=0;ipool_no); + return NULL; + } + + //pool name + if(!empty_string(pool->name)) + { + if(json_object_set(obj, "name", json_string(pool->name)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):name", pool->pool_no); + return NULL; + } + } + + //add quota/url + if(pool->quota != 1) + { + if(json_object_set(obj, "quota", json_sprintf("%s%s%s%d;%s", + ((pool->rpc_proxy)?(char *)proxytype(pool->rpc_proxytype):""), + ((pool->rpc_proxy)?pool->rpc_proxy:""), + ((pool->rpc_proxy)?"|":""), + pool->quota, + pool->rpc_url)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):quota", pool->pool_no); + return NULL; + } + } + else + { + if(json_object_set(obj, "url", json_sprintf("%s%s%s%s", + ((pool->rpc_proxy)?(char *)proxytype(pool->rpc_proxytype):""), + ((pool->rpc_proxy)?pool->rpc_proxy:""), + ((pool->rpc_proxy)?"|":""), + pool->rpc_url)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):url", pool->pool_no); + return NULL; + } + } + + //user + if(json_object_set(obj, "user", json_string(pool->rpc_user)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):user", pool->pool_no); + return NULL; + } + + //pass + if(json_object_set(obj, "pass", json_string(pool->rpc_pass)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):pass", pool->pool_no); + return NULL; + } + + if(!pool->extranonce_subscribe) + { + if(json_object_set(obj, "no-extranonce", json_true()) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):no-extranonce", pool->pool_no); + return NULL; + } + } + + if(!empty_string(pool->description)) + { + if(json_object_set(obj, "description", json_string(pool->description)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):description", pool->pool_no); + return NULL; + } + } + + //if priority isnt the same as array index, specify it + if(pool->prio != i) + { + if(json_object_set(obj, "priority", json_sprintf("%d", pool->prio)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):description", pool->pool_no); + return NULL; + } + } + + //if a profile was specified, add it then compare pool/profile settings to see what we write + if(!empty_string(pool->profile)) + { + if((profile = get_profile(pool->profile))) + { + //save profile name + if(json_object_set(obj, "profile", json_string(pool->profile)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):profile", pool->pool_no); + return NULL; + } + } + //profile not found use default profile + else + profile = &default_profile; + } + //or select default profile + else + profile = &default_profile; + + //if algorithm is different than profile, add it + if(!cmp_algorithm(&pool->algorithm, &profile->algorithm)) + { + //save algorithm name + if(json_object_set(obj, "algorithm", json_string(pool->algorithm.name)) == -1) + { + set_last_json_error("json_object_set() failed on pool(%d):algorithm", pool->pool_no); + return NULL; + } + + //TODO: add other options like nfactor etc... + } + + //if pool and profile value doesn't match below, add it + //devices + if(!build_pool_json_add(obj, "device", pool->devices, profile->devices, pool->pool_no)) + return NULL; + + //lookup-gap + if(!build_pool_json_add(obj, "lookup-gap", pool->lookup_gap, profile->lookup_gap, pool->pool_no)) + return NULL; + + //intensity + if(!build_pool_json_add(obj, "intensity", pool->intensity, profile->intensity, pool->pool_no)) + return NULL; + + //xintensity + if(!build_pool_json_add(obj, "xintensity", pool->xintensity, profile->xintensity, pool->pool_no)) + return NULL; + + //rawintensity + if(!build_pool_json_add(obj, "rawintensity", pool->rawintensity, profile->rawintensity, pool->pool_no)) + return NULL; + + //shaders + if(!build_pool_json_add(obj, "shaders", pool->shaders, profile->shaders, pool->pool_no)) + return NULL; + + //thread_concurrency + if(!build_pool_json_add(obj, "thread-concurrency", pool->thread_concurrency, profile->thread_concurrency, pool->pool_no)) + return NULL; + + //worksize + if(!build_pool_json_add(obj, "worksize", pool->worksize, profile->worksize, pool->pool_no)) + return NULL; + +#ifdef HAVE_ADL + //gpu_engine + if(!build_pool_json_add(obj, "gpu-engine", pool->gpu_engine, profile->gpu_engine, pool->pool_no)) + return NULL; + + //gpu_memclock + if(!build_pool_json_add(obj, "gpu-memclock", pool->gpu_memclock, profile->gpu_memclock, pool->pool_no)) + return NULL; + + //gpu_threads + if(!build_pool_json_add(obj, "gpu-threads", pool->gpu_threads, profile->gpu_threads, pool->pool_no)) + return NULL; + + //gpu_fan + if(!build_pool_json_add(obj, "gpu-fan", pool->gpu_fan, profile->gpu_fan, pool->pool_no)) + return NULL; + + //gpu-powertune + if(!build_pool_json_add(obj, "gpu-powertune", pool->gpu_powertune, profile->gpu_powertune, pool->pool_no)) + return NULL; + + //gpu-vddc + if(!build_pool_json_add(obj, "gpu-vddc", pool->gpu_vddc, profile->gpu_vddc, pool->pool_no)) + return NULL; +#endif + + //all done, add pool to array... + if(json_array_append_new(pool_array, obj) == -1) + { + set_last_json_error("json_array_append() failed on pool %d", pool->pool_no); + return NULL; + } + } + + return pool_array; +} + + +//helper function to add json values to profile object +static bool build_profile_json_add(json_t *object, const char *key, const char *val, const char *str_compare, bool isdefault, int id) +{ + if(!empty_string(val)) + { + //always add if default profile is this profile + if(safe_cmp(str_compare, val) || isdefault) + { + if(json_object_set(object, key, json_string(val)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):%s", id, key); + return false; + } + } + } + + return true; +} + +//builds the "profiles" json array for config file +json_t *build_profile_json() +{ + json_t *profile_array, *obj; + struct profile *profile; + bool isdefault; + int i; + + //create the "pools" array + if(!(profile_array = json_array())) + { + set_last_json_error("json_array() failed on profiles"); + return NULL; + } + + //process pool entries + for(i=0;iname, default_profile.name)) + isdefault = true; + } + + //create a new object + if(!(obj = json_object())) + { + set_last_json_error("json_object() failed on profile %d", profile->profile_no); + return NULL; + } + + //profile name + if(!empty_string(profile->name)) + { + if(json_object_set(obj, "name", json_string(profile->name)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):name", profile->profile_no); + return NULL; + } + } + + //if algorithm is different than profile, add it - if default profile is the current profile, always add + if(!cmp_algorithm(&default_profile.algorithm, &profile->algorithm) || !strcasecmp(default_profile.name, profile->name)) + { + //save algorithm name + if(json_object_set(obj, "algorithm", json_string(profile->algorithm.name)) == -1) + { + set_last_json_error("json_object_set() failed on profile(%d):algorithm", profile->profile_no); + return NULL; + } + + //TODO: add other options like nfactor etc... + } + + //if pool and profile value doesn't match below, add it + //devices + if(!build_profile_json_add(obj, "device", profile->devices, default_profile.devices, isdefault, profile->profile_no)) + return NULL; + + //lookup-gap + if(!build_profile_json_add(obj, "lookup-gap", profile->lookup_gap, default_profile.lookup_gap, isdefault, profile->profile_no)) + return NULL; + + //intensity + if(!build_profile_json_add(obj, "intensity", profile->intensity, default_profile.intensity, isdefault, profile->profile_no)) + return NULL; + + //xintensity + if(!build_profile_json_add(obj, "xintensity", profile->xintensity, default_profile.xintensity, isdefault, profile->profile_no)) + return NULL; + + //rawintensity + if(!build_profile_json_add(obj, "rawintensity", profile->rawintensity, default_profile.rawintensity, isdefault, profile->profile_no)) + return NULL; + + //shaders + if(!build_profile_json_add(obj, "shaders", profile->shaders, default_profile.shaders, isdefault, profile->profile_no)) + return NULL; + + //thread_concurrency + if(!build_profile_json_add(obj, "thread-concurrency", profile->thread_concurrency, default_profile.thread_concurrency, isdefault, profile->profile_no)) + return NULL; + + //worksize + if(!build_profile_json_add(obj, "worksize", profile->worksize, default_profile.worksize, isdefault, profile->profile_no)) + return NULL; + +#ifdef HAVE_ADL + //gpu_engine + if(!build_profile_json_add(obj, "gpu-engine", profile->gpu_engine, default_profile.gpu_engine, isdefault, profile->profile_no)) + return NULL; + + //gpu_memclock + if(!build_profile_json_add(obj, "gpu-memclock", profile->gpu_memclock, default_profile.gpu_memclock, isdefault, profile->profile_no)) + return NULL; + + //gpu_threads + if(!build_profile_json_add(obj, "gpu-threads", profile->gpu_threads, default_profile.gpu_threads, isdefault, profile->profile_no)) + return NULL; + + //gpu_fan + if(!build_profile_json_add(obj, "gpu-fan", profile->gpu_fan, default_profile.gpu_fan, isdefault, profile->profile_no)) + return NULL; + + //gpu-powertune + if(!build_profile_json_add(obj, "gpu-powertune", profile->gpu_powertune, default_profile.gpu_powertune, isdefault, profile->profile_no)) + return NULL; + + //gpu-vddc + if(!build_profile_json_add(obj, "gpu-vddc", profile->gpu_vddc, default_profile.gpu_vddc, isdefault, profile->profile_no)) + return NULL; +#endif + + //all done, add pool to array... + if(json_array_append_new(profile_array, obj) == -1) + { + set_last_json_error("json_array_append() failed on profile %d", profile->profile_no); + return NULL; + } + } + + return profile_array; +} + +void write_config(const char *filename) +{ + json_t *config, *obj; + struct opt_table *opt; + char *p, *optname; + int i; + + if(!(config = json_object())) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object() failed on root."); + return; + } + + //build pools + if(!(obj = build_pool_json())) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n %s.", last_json_error); + return; + } + + //add pools to config + if(json_object_set(config, "pools", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set(pools) failed."); + return; + } + + //build profiles + if(!(obj = build_profile_json())) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n %s.", last_json_error); + return; + } + + //add profiles to config + if(json_object_set(config, "profiles", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set(profiles) failed."); + return; + } + + //pool strategy + switch(pool_strategy) + { + case POOL_BALANCE: + if(json_object_set(config, "balance", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on balance"); + return; + } + break; + case POOL_LOADBALANCE: + if(json_object_set(config, "load-balance", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on load-balance"); + return; + } + break; + case POOL_ROUNDROBIN: + if(json_object_set(config, "round-robin", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on round-robin"); + return; + } + break; + case POOL_ROTATE: + if(json_object_set(config, "rotate", json_sprintf("%d", opt_rotate_period)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on rotate"); + return; + } + break; + //default failover only + default: + if(json_object_set(config, "failover-only", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on failover-only"); + return; + } + break; + } + + //if using a specific profile as default, set it + if(!empty_string(default_profile.name)) + { + if(json_object_set(config, "default-profile", json_string(default_profile.name)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on default_profile"); + return; + } + } + //otherwise save default profile values + else + { + //save algorithm name + if(json_object_set(config, "algorithm", json_string(opt_algorithm.name)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on algorithm"); + return; + } + //TODO: add other options like nfactor etc... + + //devices + if(!empty_string(default_profile.devices)) + { + if(json_object_set(config, "devices", json_string(default_profile.devices)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on devices"); + return; + } + } + + //lookup-gap + if(!empty_string(default_profile.lookup_gap)) + { + if(json_object_set(config, "lookup-gap", json_string(default_profile.lookup_gap)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on lookup-gap"); + return; + } + } + + //intensity + if(!empty_string(default_profile.intensity)) + { + if(json_object_set(config, "intensity", json_string(default_profile.intensity)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on intensity"); + return; + } + } + + //xintensity + if(!empty_string(default_profile.xintensity)) + { + if(json_object_set(config, "xintensity", json_string(default_profile.xintensity)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on xintensity"); + return; + } + } + + //rawintensity + if(!empty_string(default_profile.rawintensity)) + { + if(json_object_set(config, "rawintensity", json_string(default_profile.rawintensity)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on rawintensity"); + return; + } + } + + //shaders + if(!empty_string(default_profile.shaders)) + { + if(json_object_set(config, "shaders", json_string(default_profile.shaders)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on shaders"); + return; + } + } + + //thread_concurrency + if(!empty_string(default_profile.thread_concurrency)) + { + if(json_object_set(config, "thread-concurrency", json_string(default_profile.thread_concurrency)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on thread_concurrency"); + return; + } + } + + //worksize + if(!empty_string(default_profile.worksize)) + { + if(json_object_set(config, "worksize", json_string(default_profile.worksize)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on worksize"); + return; + } + } + +#ifdef HAVE_ADL + //gpu_engine + if(!empty_string(default_profile.gpu_engine)) + { + if(json_object_set(config, "gpu-engine", json_string(default_profile.gpu_engine)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-engine"); + return; + } + } + + //gpu_memclock + if(!empty_string(default_profile.gpu_memclock)) + { + if(json_object_set(config, "gpu-memclock", json_string(default_profile.gpu_memclock)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-memclock"); + return; + } + } + + //gpu_threads + if(!empty_string(default_profile.gpu_threads)) + { + if(json_object_set(config, "gpu-threads", json_string(default_profile.gpu_threads)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-threads"); + return; + } + } + + //gpu_fan + if(!empty_string(default_profile.gpu_fan)) + { + if(json_object_set(config, "gpu-fan", json_string(default_profile.gpu_fan)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-fan"); + return; + } + } + + //gpu-powertune + if(!empty_string(default_profile.gpu_powertune)) + { + if(json_object_set(config, "gpu-powertune", json_string(default_profile.gpu_powertune)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-powertune"); + return; + } + } + + //gpu-vddc + if(!empty_string(default_profile.gpu_vddc)) + { + if(json_object_set(config, "gpu-vddc", json_string(default_profile.gpu_vddc)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-vddc"); + return; + } + } +#endif + } + + //devices + /*if(opt_devs_enabled) + { + bool extra_devs = false; + obj = json_string(""); + + for(i = 0; i < MAX_DEVICES; i++) + { + if(devices_enabled[i]) + { + int startd = i; + + if(extra_devs) + obj = json_sprintf("%s%s", json_string_value(obj), ","); + + while (i < MAX_DEVICES && devices_enabled[i + 1]) + ++i; + + obj = json_sprintf("%s%d", json_string_value(obj), startd); + if(i > startd) + obj = json_sprintf("%s-%d", json_string_value(obj), i); + } + } + + if(json_object_set(config, "devices", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on devices"); + return; + } + }*/ + + //remove-disabled + if(opt_removedisabled) + { + if(json_object_set(config, "remove-disabled", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on remove-disabled"); + return; + } + + } + + //write gpu settings that aren't part of profiles -- only write if gpus are available + if(nDevs) + { + +#ifdef HAVE_ADL + //temp-cutoff + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].cutofftemp); + + if(json_object_set(config, "temp-cutoff", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-cutoff"); + return; + } + + //temp-overheat + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].adl.overtemp); + + if(json_object_set(config, "temp-overheat", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-overheat"); + return; + } + + //temp-target + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), gpus[i].adl.targettemp); + + if(json_object_set(config, "temp-target", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on temp-target"); + return; + } + + //reorder gpus + if(opt_reorder) + { + if(json_object_set(config, "gpu-reorder", json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-reorder"); + return; + } + } + + //gpu-memdiff + for(i = 0;i < nDevs; i++) + obj = json_sprintf("%s%s%d", ((i > 0)?json_string_value(obj):""), ((i > 0)?",":""), (int)gpus[i].gpu_memdiff); + + if(json_object_set(config, "gpu-memdiff", obj) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on gpu-memdiff"); + return; + } +#endif + } + + //add other misc options + //shares + if(json_object_set(config, "shares", json_sprintf("%d", opt_shares)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on shares"); + return; + } + +#if defined(unix) || defined(__APPLE__) + //monitor + if(opt_stderr_cmd && *opt_stderr_cmd) + { + if(json_object_set(config, "monitor", json_string(opt_stderr_cmd)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on monitor"); + return; + } + } +#endif // defined(unix) + + //kernel path + if(opt_kernel_path && *opt_kernel_path) + { + //strip end / + char *kpath = strdup(opt_kernel_path); + if(kpath[strlen(kpath)-1] == '/') + kpath[strlen(kpath)-1] = 0; + + if(json_object_set(config, "kernel-path", json_string(kpath)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on kernel-path"); + return; + } + } + + //sched-time + if(schedstart.enable) + { + if(json_object_set(config, "sched-time", json_sprintf("%d:%d", schedstart.tm.tm_hour, schedstart.tm.tm_min)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on sched-time"); + return; + } + } + + //stop-time + if(schedstop.enable) + { + if(json_object_set(config, "stop-time", json_sprintf("%d:%d", schedstop.tm.tm_hour, schedstop.tm.tm_min)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on stop-time"); + return; + } + } + + //socks-proxy + if(opt_socks_proxy && *opt_socks_proxy) + { + if(json_object_set(config, "socks-proxy", json_string(opt_socks_proxy)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on socks-proxy"); + return; + } + } + + + //api stuff + //api-allow + if(opt_api_allow) + { + if(json_object_set(config, "api-allow", json_string(opt_api_allow)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-allow"); + return; + } + } + + //api-mcast-addr + if(strcmp(opt_api_mcast_addr, API_MCAST_ADDR) != 0) + { + if(json_object_set(config, "api-mcast-addr", json_string(opt_api_mcast_addr)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-mcast-addr"); + return; + } + } + + //api-mcast-code + if(strcmp(opt_api_mcast_code, API_MCAST_CODE) != 0) + { + if(json_object_set(config, "api-mcast-code", json_string(opt_api_mcast_code)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-mcast-code"); + return; + } + } + + //api-mcast-des + if(*opt_api_mcast_des) + { + if(json_object_set(config, "api-mcast-des", json_string(opt_api_mcast_des)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-mcast-des"); + return; + } + } + + //api-description + if(strcmp(opt_api_description, PACKAGE_STRING) != 0) + { + if(json_object_set(config, "api-description", json_string(opt_api_description)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-description"); + return; + } + } + + //api-groups + if(opt_api_groups) + { + if(json_object_set(config, "api-groups", json_string(opt_api_groups)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on api-groups"); + return; + } + } + + //add other misc bool/int options + for(opt = opt_config_table; opt->type != OPT_END; opt++) + { + optname = strdup(opt->names); + + //ignore --pool-* and --profile-* options + if(!strstr(optname, "--pool-") && !strstr(optname, "--profile-")) + { + //get first available long form option name + for(p = strtok(optname, "|"); p; p = strtok(NULL, "|")) + { + //skip short options + if(p[1] != '-') + continue; + + //type bool + if (opt->type & OPT_NOARG && + ((void *)opt->cb == (void *)opt_set_bool || (void *)opt->cb == (void *)opt_set_invbool) && + (*(bool *)opt->u.arg == ((void *)opt->cb == (void *)opt_set_bool))) + { + if(json_object_set(config, p+2, json_true()) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on %s.", p+2); + return; + } + break; //exit for loop... so we don't enter a duplicate value if an option has multiple names + } + //numeric types + else if (opt->type & OPT_HASARG && + ((void *)opt->cb_arg == (void *)set_int_0_to_9999 || + (void *)opt->cb_arg == (void *)set_int_1_to_65535 || + (void *)opt->cb_arg == (void *)set_int_0_to_10 || + (void *)opt->cb_arg == (void *)set_int_1_to_10) && opt->desc != opt_hidden) + { + if(json_object_set(config, p+2, json_sprintf("%d", *(int *)opt->u.arg)) == -1) + { + applog(LOG_ERR, "Error: config_parser::write_config():\n json_object_set() failed on %s.", p+2); + return; + } + break; //exit for loop... so we don't enter a duplicate value if an option has multiple names + } + } + } + } + + json_dump_file(config, filename, JSON_PRESERVE_ORDER|JSON_INDENT(2)); +} + +/********************************************* + * API functions + * *******************************************/ +//profile parameters +enum { + PR_ALGORITHM, + PR_NFACTOR, + PR_LOOKUPGAP, + PR_DEVICES, + PR_INTENSITY, + PR_XINTENSITY, + PR_RAWINTENSITY, + PR_GPUENGINE, + PR_GPUMEMCLOCK, + PR_GPUTHREADS, + PR_GPUFAN, + PR_GPUPOWERTUNE, + PR_GPUVDDC, + PR_SHADERS, + PR_TC, + PR_WORKSIZE +}; + +void api_profile_list(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) +{ + struct api_data *root = NULL; + struct profile *profile; + char buf[TMPBUFSIZ]; + bool io_open = false; + bool b; + int i; + + if (total_profiles == 0) + { + message(io_data, MSG_NOPROFILE, 0, NULL, isjson); + return; + } + + message(io_data, MSG_PROFILE, 0, NULL, isjson); + + if (isjson) + io_open = io_add(io_data, COMSTR JSON_PROFILES); + + for (i = 0; i <= total_profiles; i++) + { + //last profile is the default profile + if(i == total_profiles) + profile = &default_profile; + else + profile = profiles[i]; + + //if default profile name is profile name or loop index is beyond the last profile, then it is the default profile + b = (((i == total_profiles) || (!strcasecmp(default_profile.name, profile->name)))?true:false); + + root = api_add_int(root, "PROFILE", &i, false); + 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, "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); + root = api_add_escape(root, "XIntensity", isnull((char *)profile->xintensity, ""), true); + root = api_add_escape(root, "RawIntensity", isnull((char *)profile->rawintensity, ""), true); + root = api_add_escape(root, "Gpu Engine", isnull((char *)profile->gpu_engine, ""), true); + root = api_add_escape(root, "Gpu MemClock", isnull((char *)profile->gpu_memclock, ""), true); + root = api_add_escape(root, "Gpu Threads", isnull((char *)profile->gpu_threads, ""), true); + root = api_add_escape(root, "Gpu Fan%", isnull((char *)profile->gpu_fan, ""), true); + root = api_add_escape(root, "Gpu Powertune%", isnull((char *)profile->gpu_powertune, ""), true); + root = api_add_escape(root, "Gpu Vddc", isnull((char *)profile->gpu_vddc, ""), true); + root = api_add_escape(root, "Shaders", isnull((char *)profile->shaders, ""), true); + root = api_add_escape(root, "Thread Concurrency", isnull((char *)profile->thread_concurrency, ""), true); + root = api_add_escape(root, "Worksize", isnull((char *)profile->worksize, ""), true); + + root = print_data(root, buf, isjson, isjson && (i > 0)); + io_add(io_data, buf); + } + + if (isjson && io_open) + io_close(io_data); +} + +void api_profile_add(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + char *p; + char *split_str; + struct profile *profile; + int idx; + + split_str = strdup(param); + + //split all params by colon (:) because the comma (,) can be used in some of those parameters + if((p = strsep(&split_str, ":"))) + { + //get name first and see if the profile already exists + if((profile = get_profile(p))) + { + message(io_data, MSG_PROFILEEXIST, 0, p, isjson); + return; + } + + //doesnt exist, create new profile + profile = add_profile(); + + //assign name + profile->name = strdup(p); + + //get other parameters + idx = 0; + while((p = strsep(&split_str, ":")) != NULL) + { + switch(idx) + { + case PR_ALGORITHM: + set_algorithm(&profile->algorithm, p); + break; + case PR_NFACTOR: + if(!empty_string(p)) + set_algorithm_nfactor(&profile->algorithm, (const uint8_t)atoi(p)); + break; + case PR_LOOKUPGAP: + if(!empty_string(p)) + profile->lookup_gap = strdup(p); + break; + case PR_DEVICES: + if(!empty_string(p)) + profile->devices = strdup(p); + break; + case PR_INTENSITY: + if(!empty_string(p)) + profile->intensity = strdup(p); + break; + case PR_XINTENSITY: + if(!empty_string(p)) + profile->xintensity = strdup(p); + break; + case PR_RAWINTENSITY: + if(!empty_string(p)) + profile->rawintensity = strdup(p); + break; + case PR_GPUENGINE: + if(!empty_string(p)) + profile->gpu_engine = strdup(p); + break; + case PR_GPUMEMCLOCK: + if(!empty_string(p)) + profile->gpu_memclock = strdup(p); + break; + case PR_GPUTHREADS: + if(!empty_string(p)) + profile->gpu_threads = strdup(p); + break; + case PR_GPUFAN: + if(!empty_string(p)) + profile->gpu_fan = strdup(p); + break; + case PR_GPUPOWERTUNE: + if(!empty_string(p)) + profile->gpu_powertune = strdup(p); + break; + case PR_GPUVDDC: + if(!empty_string(p)) + profile->gpu_vddc = strdup(p); + break; + case PR_SHADERS: + if(!empty_string(p)) + profile->shaders = strdup(p); + break; + case PR_TC: + if(!empty_string(p)) + profile->thread_concurrency = strdup(p); + break; + case PR_WORKSIZE: + if(!empty_string(p)) + profile->worksize = strdup(p); + break; + default: + //invalid option ignore + break; + } + + idx++; + } + } + else + { + message(io_data, MSG_MISPRD, 0, NULL, isjson); + return; + } + + message(io_data, MSG_ADDPROFILE, 0, profile->name, isjson); +} + +void api_profile_remove(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct profile *profile; + struct pool *pool; + int i; + + //no profiles, nothing to remove + if (total_profiles == 0) + { + message(io_data, MSG_NOPROFILE, 0, NULL, isjson); + return; + } + + //make sure profile name is supplied + if(param == NULL || *param == '\0') + { + message(io_data, MSG_MISPRID, 0, NULL, isjson); + return; + } + + //see if the profile exists + if(!(profile = get_profile(param))) + { + message(io_data, MSG_PRNOEXIST, 0, param, isjson); + return; + } + + //next make sure it's not the default profile + if(!strcasecmp(default_profile.name, profile->name)) + { + message(io_data, MSG_PRISDEFAULT, 0, param, isjson); + return; + } + + //make sure no pools use it + for(i = 0;i < total_pools; i++) + { + pool = pools[i]; + + if(!strcasecmp(pool->profile, profile->name)) + { + message(io_data, MSG_PRINUSE, 0, param, isjson); + return; + } + } + + //all set, delete the profile + remove_profile(profile); + + message(io_data, MSG_REMPROFILE, profile->profile_no, profile->name, isjson); + + free(profile); +} + +//should move to pool.c with the other pool stuff... +void api_pool_profile(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) +{ + struct profile *profile; + struct pool *pool; + char *p; + int i; + + //no pool, nothing to change + if (total_pools == 0) + { + message(io_data, MSG_NOPOOL, 0, NULL, isjson); + return; + } + + //no profiles, nothing to change + if (total_profiles == 0) + { + message(io_data, MSG_NOPROFILE, 0, NULL, isjson); + return; + } + + //check if parameters were passed + if (param == NULL || *param == '\0') + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + //get pool number in parameter 1 + if(!(p = strtok(param, ","))) + { + message(io_data, MSG_MISPID, 0, NULL, isjson); + return; + } + + //check valid pool id + i = atoi(p); + + if(i < 0 || i >= total_pools) + { + message(io_data, MSG_INVPID, i, NULL, isjson); + return; + } + + //get pool + pool = pools[i]; + + //get profile name in parameter 2 + if(!(p = strtok(NULL, ","))) + { + message(io_data, MSG_MISPRID, 0, NULL, isjson); + return; + } + + //see if the profile exists + if(!(profile = get_profile(p))) + { + message(io_data, MSG_PRNOEXIST, 0, p, isjson); + return; + } + + //set profile + pool->profile = strdup(profile->name); + //apply settings + apply_pool_profile(pool); + + //if current pool restart it + if (pool == current_pool()) + switch_pools(NULL); + + message(io_data, MSG_CHPOOLPR, pool->pool_no, profile->name, isjson); +} diff --git a/config_parser.h b/config_parser.h new file mode 100644 index 00000000..31ea4273 --- /dev/null +++ b/config_parser.h @@ -0,0 +1,122 @@ +#ifndef CONFIG_PARSER_H +#define CONFIG_PARSER_H + +#include "config.h" + +#include "miner.h" +#include "api.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 +#ifndef safe_cmp + #define safe_cmp(val1, val2) (((val1 && strcmp(val1, val2) != 0) || empty_string(val1))?1:0) +#endif +#ifndef isnull + #define isnull(str, default_str) ((str == NULL)?default_str:str) +#endif + +//helper function to get a gpu option value +#ifndef gpu_opt + #define gpu_opt(i,optname) gpus[i].optname +#endif + +//profile structure +struct profile { + int profile_no; + char *name; + bool removed; + + algorithm_t algorithm; + const char *devices; + const char *intensity; + const char *xintensity; + const char *rawintensity; + const char *lookup_gap; + const char *gpu_engine; + const char *gpu_memclock; + const char *gpu_threads; + const char *gpu_fan; + const char *gpu_powertune; + const char *gpu_vddc; + const char *shaders; + const char *thread_concurrency; + const char *worksize; +}; + +/* 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; +extern struct profile **profiles; +extern int total_profiles; + +/* option parser functions */ +extern char *set_default_devices(const char *arg); +extern char *set_default_lookup_gap(const char *arg); +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); + extern char *set_default_gpu_powertune(const char *arg); + extern char *set_default_gpu_vddc(const char *arg); +#endif +extern char *set_default_profile(char *arg); +extern char *set_default_shaders(const char *arg); +extern char *set_default_worksize(const char *arg); + +extern char *set_profile_name(const char *arg); +extern char *set_profile_algorithm(const char *arg); +extern char *set_profile_devices(const char *arg); +extern char *set_profile_lookup_gap(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); + extern char *set_profile_gpu_powertune(const char *arg); + extern char *set_profile_gpu_vddc(const char *arg); +#endif +extern char *set_profile_nfactor(const char *arg); +extern char *set_profile_shaders(const char *arg); +extern char *set_profile_worksize(const char *arg); + +/* config parser functions */ +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); + +/* startup functions */ +extern void load_default_profile(); +extern void apply_defaults(); +extern void apply_pool_profiles(); +extern void apply_pool_profile(struct pool *pool); + +/* config writer */ +extern void write_config(const char *filename); + +/* API functions */ +extern void api_profile_list(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group); +extern void api_profile_add(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group); +extern void api_profile_remove(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group); +extern void api_pool_profile(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group); + +#endif // CONFIG_PARSER_H diff --git a/doc/API b/doc/API.md similarity index 83% rename from doc/API rename to doc/API.md index ecab03c7..b8f9ca05 100644 --- a/doc/API +++ b/doc/API.md @@ -1,202 +1,299 @@ -This README contains details about the sgminer RPC API - -It also includes some detailed information at the end, -about using miner.php - - -If you start sgminer with the "--api-listen" option, it will listen on a -simple TCP/IP socket for single string API requests from the same machine -running sgminer and reply with a string and then close the socket each time -If you add the "--api-network" option, it will accept API requests from any -network attached computer. - -You can only access the comands that reply with data in this mode. -By default, you cannot access any privileged command that affects the miner - -you will receive an access denied status message see --api-allow below. - -You can specify IP addresses/prefixes that are only allowed to access the API -with the "--api-allow" option e.g. --api-allow W:192.168.0.1,10.0.0/24 -will allow 192.168.0.1 or any address matching 10.0.0.*, but nothing else -IP addresses are automatically padded with extra '.0's as needed -Without a /prefix is the same as specifying /32 -0/0 means all IP addresses. -The 'W:' on the front gives that address/subnet privileged access to commands -that modify sgminer (thus all API commands) -Without it those commands return an access denied status. -See --api-groups below to define other groups like W: -Privileged access is checked in the order the IP addresses were supplied to -"--api-allow" -The first match determines the privilege level. -Using the "--api-allow" option overides the "--api-network" option if they -are both specified -With "--api-allow", 127.0.0.1 is not by default given access unless specified - -If you start sgminer also with the "--api-mcast" option, it will listen for -a multicast message and reply to it with a message containing it's API port -number, but only if the IP address of the sender is allowed API access - -More groups (like the privileged group W:) can be defined using the ---api-groups command -Valid groups are only the letters A-Z (except R & W are predefined) and are -not case sensitive -The R: group is the same as not privileged access -The W: group is (as stated) privileged access (thus all API commands) -To give an IP address/subnet access to a group you use the group letter -in front of the IP address instead of W: e.g. P:192.168.0/32 -An IP address/subnet can only be a member of one group -A sample API group would be: - --api-groups - P:switchpool:enablepool:addpool:disablepool:removepool:poolpriority:* -This would create a group 'P' that can do all current pool commands and all -non-priviliged commands - the '*' means all non-priviledged commands -Without the '*' the group would only have access to the pool commands -Defining multiple groups example: - --api-groups Q:quit:restart:*,S:save -This would define 2 groups: - Q: that can 'quit' and 'restart' as well as all non-priviledged commands - S: that can only 'save' and no other commands +# sgminer RPC API Documentation + +*Work in Progress!* + +This README contains details about the sgminer RPC API and also includes some detailed information +at the end, about using [miner.php](#miner-php). + +--- + +## API Configuration + +If you start sgminer with the `--api-listen` option, it will listen on a simple TCP/IP socket for single string API requests from the same machine running sgminer and reply with a string and then close the socket each time If you add the `--api-network` option, it will accept API requests from any network attached computer. + +You can only access the comands that reply with data in this mode. By default, you cannot access any privileged command that affects the miner - you will receive an access denied status message see `--api-allow` below. + +You can specify IP addresses/prefixes that are only allowed to access the API with the `--api-allow` option. + +``` +--api-allow W:192.168.0.1,10.0.0/24 +``` + +The example above will allow 192.168.0.1 or any address matching 10.0.0.*, but nothing else. IP addresses are automatically padded with extra '.0's as needed Without a /prefix is the same as specifying /32 0/0 means all IP addresses. The `W:` on the front gives that address/subnet privileged access to commands that modify sgminer (thus all API commands). Without it those commands return an access denied status. See `--api-groups` below to define other groups like `W:`. Privileged access is checked in the order the IP addresses were supplied to `--api-allow`. The first match determines the privilege level. Using the `--api-allow` option overides the `--api-network` option if they are both specified. With `--api-allow`, 127.0.0.1 is not by default given access unless specified. + +If you start sgminer also with the `--api-mcast` option, it will listen for a multicast message and reply to it with a message containing it's API port number, but only if the IP address of the sender is allowed API access. + +More groups (like the privileged group `W:`) can be defined using the `--api-groups` command. Valid groups are only the letters A-Z (except R & W are predefined) and are not case sensitive. The `R:` group is the same as not privileged access. The `W:` group is (as stated) privileged access (thus all API commands). To give an IP address/subnet access to a group you use the group letter in front of the IP address instead of `W:` e.g. `P:192.168.0/32`. An IP address/subnet can only be a member of one group + +A sample API group would be: + +``` +--api-groups P:switchpool:enablepool:addpool:disablepool:removepool:poolpriority:* +``` + +This would create a group `P` that can do all current pool commands and all non-priviliged commands - the asterisk (\*) means all non-priviledged commands. Without the asterisk (\*), the group would only have access to the pool commands. + +Defining multiple groups example: + +``` +--api-groups Q:quit:restart:*,S:save +``` + +This would define 2 groups: `Q:`, that can `quit` and `restart` as well as all non-priviledged commands, and `S:`, that can only `save` and no other commands. + +For API configuration options, see `doc/configuration.md`. + +--- + +## API Requests The RPC API request can be either simple text or JSON. -If the request is JSON (starts with '{'), it will reply with a JSON formatted +If the request is JSON (starts with `{`), it will reply with a JSON formatted response, otherwise it replies with text formatted as described further below. -The JSON request format required is '{"command":"CMD","parameter":"PARAM"}' +The JSON request format required is `{"command":"CMD","parameter":"PARAM"}` (though of course parameter is not required for all requests) where "CMD" is from the "Request" column below and "PARAM" would be e.g. the ASC/GPU number if required. An example request in both formats to set GPU 0 fan to 80%: +``` gpufan|0,80 {"command":"gpufan","parameter":"0,80"} +``` The format of each reply (unless stated otherwise) is a STATUS section followed by an optional detail section From API version 1.7 onwards, reply strings in JSON and Text have the necessary escaping as required to avoid ambiguity - they didn't before 1.7 -For JSON the 2 characters '"' and '\' are escaped with a '\' before them -For Text the 4 characters '|' ',' '=' and '\' are escaped the same way +For JSON the 2 characters `"` and `\` are escaped with a `\` before them +For Text the 4 characters `|` `,` `=` and `\` are escaped the same way Only user entered information will contain characters that require being escaped, such as Pool URL, User and Password or the Config save filename, when they are returned in messages or as their values by the API -For API version 1.4 and later: +For API version 1.4 and later the STATUS section is: -The STATUS section is: +`STATUS=X,When=NNN,Code=N,Msg=string,Description=string|` - STATUS=X,When=NNN,Code=N,Msg=string,Description=string| +* `STATUS=X` Where X is one of: + `W` Warning + `I` Informational + `S` Success + `E` Error + `F` Fatal (code bug) - STATUS=X Where X is one of: - W - Warning - I - Informational - S - Success - E - Error - F - Fatal (code bug) - - When=NNN +* `When=NNN` Standard long time of request in seconds - Code=N - Each unique reply has a unigue Code (See api.c - #define MSG_NNNNNN) +* `Code=N` + Each unique reply has a unigue Code (See `api.c` and `api.h` - #define MSG_NNNNNN) - Msg=string +* `Msg=string` Message matching the Code value N - Description=string - This defaults to the sgminer version but is the value of --api-description +* `Description=string` + This defaults to the sgminer version but is the value of `--api-description` if it was specified at runtime. With API V3.1 you can also request multiple report replies in a single command -request -e.g. to request both summary and devs, the command would be summary+devs +request: e.g. to request both `summary` and `devs`, the command would be `summary+devs` -This is only available for report commands that don't need parameters, -and is not available for commands that change anything -Any parameters supplied will be ignored +**Note:** This is only available for report commands that don't need parameters, +and is not available for commands that change anything. Any parameters supplied will be ignored. -The extra formatting of the result is to have a section for each command -e.g. CMD=summary|STATUS=....|CMD=devs|STATUS=... -With JSON, each result is within a section of the command name -e.g. {"summary":{"STATUS":[{"STATUS":"S"...}],"SUMMARY":[...],"id":1}, - "devs":{"STATUS":[{"STATUS:"S"...}],"DEVS":[...],"id":1},"id":1} +The extra formatting of the result is to have a section for each command: +`CMD=summary|STATUS=....|CMD=devs|STATUS=...` -As before, if you supply bad JSON you'll just get a single 'E' STATUS section +With JSON, each result is within a section of the command name +``` +{ + "summary":{ + "STATUS":[ + {"STATUS":"S"...} + ], + "SUMMARY":[...], + "id":1 + }, + "devs":{ + "STATUS":[ + {"STATUS:"S"...} + ], + "DEVS":[...], + "id":1 + }, + "id":1 +} +```` + +As before, if you supply bad JSON you'll just get a single `E` STATUS section in the old format, since it doesn't switch to using the new format until it -correctly processes the JSON and can match a '+' in the command +correctly processes the JSON and can match a `+` in the command. -If you request a command multiple times, e.g. devs+devs -you'll just get it once +If you request a command multiple times, e.g. `devs+devs`, you'll just get it once. If this results in only one command, it will still use the new layout with just the one command If you request a command that can't be used due to requiring parameters, -a command that isn't a report, or an invalid command, you'll get an 'E' STATUS +a command that isn't a report, or an invalid command, you'll get an `E` STATUS for that one but it will still attempt to process all other commands supplied -Blank/missing commands are ignore e.g. +devs++ -will just show 'devs' using the new layout - -For API version 1.10 and later: - -The list of requests - a (*) means it requires privileged access - and replies: - - Request Reply Section Details - ------- ------------- ------- - version VERSION Miner="sgminer " sgminer version - CGMiner=sgminer version - API=API version - - config CONFIG Some miner configuration information: - GPU Count=N, <- the number of GPUs - ASC Count=N, <- the number of ASCs - PGA Count=N, <- the number of PGAs - Pool Count=N, <- the number of Pools - ADL=X, <- Y or N if ADL is compiled in the code - ADL in use=X, <- Y or N if any GPU has ADL - Strategy=Name, <- the current pool strategy - Log Interval=N, <- log interval (--log N) - Device Code=GPU ICA , <- spaced list of compiled - device drivers - OS=Linux/Apple/..., <- operating System - Failover-Only=true/false, <- failover-only setting - ScanTime=N, <- --scan-time setting - Queue=N, <- --queue setting - Expiry=N| <- --expiry setting - - summary SUMMARY The status summary of the miner - e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...| - - pools POOLS The status of each pool e.g. - Pool=0,URL=http://pool.com:6311,Status=Alive,...| - - devs DEVS Each available GPU, PGA and ASC with their details - e.g. GPU=0,Accepted=NN,MHS av=NNN,...,Intensity=D| - Last Share Time=NNN, <- standand long time in sec - (or 0 if none) of last accepted share - Last Share Pool=N, <- pool number (or -1 if none) - Last Valid Work=NNN, <- standand long time in sec - of last work returned that wasn't an HW: - Will not report PGAs if PGA mining is disabled - Will not report ASCs if ASC mining is disabled - - gpu|N GPU The details of a single GPU number N in the same - format and details as for DEVS +Blank/missing commands are ignored. `+devs++` will just show `devs` using the new +layout. - pga|N PGA The details of a single PGA number N in the same - format and details as for DEVS - This is only available if PGA mining is enabled - Use 'pgacount' or 'config' first to see if there - are any +--- + +## API Commands + +### version + +Returns the version information of sgminer. + +*Syntax:* `version` + +*Arguments:* None + +*Access*: `Non-priviledged` + +*Returns:* +``` + Miner="sgminer " + CGMiner= + API= +``` + +### config + +Returns some miner configuration information + +*Syntax:* `config` + +*Arguments:* None + +*Access*: `Non-priviledged` + +*Returns:* +``` + GPU Count=N, <- the number of GPUs + ASC Count=N, <- the number of ASCs + PGA Count=N, <- the number of PGAs + Pool Count=N, <- the number of Pools + ADL=X, <- Y or N if ADL is compiled in the code + ADL in use=X, <- Y or N if any GPU has ADL + Strategy=Name, <- the current pool strategy + Log Interval=N, <- log interval (--log N) + Device Code=GPU ICA, <- spaced list of compiled device drivers + OS=Linux/Apple/..., <- operating System + Failover-Only=true/false, <- failover-only setting + ScanTime=N, <- --scan-time setting + Queue=N, <- --queue setting + Expiry=N| <- --expiry setting +``` + +### summary + +Returns the status summary of the miner - gpucount GPUS Count=N| <- the number of GPUs +*Syntax:* `summary` - pgacount PGAS Count=N| <- the number of PGAs - Always returns 0 if PGA mining is disabled +*Arguments:* None - switchpool|N (*) +*Access*: `Non-priviledged` + +*Returns:* `Elapsed=NNN,Found Blocks=N,Getworks=N,...|` + +### devs + +Returns each available GPU, PGA and ASC with their details. **Note** that this will not return PGAs or ASCs if PGA or ASC mining is not enabled. + +*Syntax:* `devs` + +*Arguments:* None + +*Access*: `Non-priviledged` + +*Returns:* +``` +GPU=0,Accepted=NN,MHS av=NNN,...,Intensity=D| +Last Share Time=NNN, <- standand long time in sec (or 0 if none) of last accepted share +Last Share Pool=N, <- pool number (or -1 if none) +Last Valid Work=NNN, <- standand long time in sec of last work returned that wasn't an HW +``` + +### gpu + +Returns the details of a single GPU in the same format and details as [devs](#devs). + +*Syntax:* `gpu|` + +*Arguments:* `number` GPU Number + +*Access*: `Non-priviledged` + +*Returns:* +``` +GPU=0,Accepted=NN,MHS av=NNN,...,Intensity=D| +Last Share Time=NNN, <- standand long time in sec (or 0 if none) of last accepted share +Last Share Pool=N, <- pool number (or -1 if none) +Last Valid Work=NNN, <- standand long time in sec of last work returned that wasn't an HW +``` + +### pga + +Returns the details of a single PGA in the same format and details as [devs](#devs). **Note** that this is only available if PGA mining is enabled. Use [pgacount](#pgacount) or [config](#config) first to see if there are any PGA devices. + +*Syntax:* `pga|` + +*Arguments:* `number` PGA Number + +*Access*: `Non-priviledged` + +*Returns:* +``` +PGA=0,Accepted=NN,MHS av=NNN,...,Intensity=D| +Last Share Time=NNN, <- standand long time in sec (or 0 if none) of last accepted share +Last Share Pool=N, <- pool number (or -1 if none) +Last Valid Work=NNN, <- standand long time in sec of last work returned that wasn't an HW +``` + +### gpucount + +Returns the number of GPU devices. + +*Syntax:* `gpucount` + +*Arguments:* None + +*Access*: `Non-priviledged` + +*Returns:* +``` +Count=N| <- number of GPUs +``` + +### pgacount + +Returns the number of PGA devices. + +*Syntax:* `pgacount` + +*Arguments:* None + +*Access*: `Non-priviledged` + +*Returns:* +``` +Count=N| <- number of PGAs +``` + +--- + +``` +switchpool|N (*) none There is no reply section just the STATUS section stating the results of switching pool N to the highest priority (the pool is also enabled) @@ -207,13 +304,13 @@ The list of requests - a (*) means it requires privileged access - and replies: stating the results of enabling pool N The Msg includes the pool URL - addpool|URL,USR,PASS[,NAME,DESC,ALGO] (*) + addpool|URL,USR,PASS[,NAME,DESC,PROFILE,ALGO] (*) none There is no reply section just the STATUS section stating the results of attempting to add pool N The Msg includes the pool URL Use '\\' to get a '\' and '\,' to include a comma inside URL, USR or PASS - Name, description and algorithm are optional + Name, description, profile and algorithm are optional poolpriority|N,... (*) none There is no reply section just the STATUS section @@ -234,8 +331,37 @@ The list of requests - a (*) means it requires privileged access - and replies: stating the results of removing pool N The Msg includes the pool URL N.B. all details for the pool will be lost + + changestrategy|STRAT,INT (*) + none There is no reply section just the STATUS section + stating the results of changing multipool strategy + to STRAT. If the strategy requested is "rotate", + the interval INT must be specified as a number + between 0 and 9999 seconds. INT is not required + otherwise. - gpuenable|N (*) + changepoolprofile|N,NAME (*) + none There is no reply section just the STATUS section + stating the results of changing the profile of + pool N to profile NAME. + +addprofile|NAME:ALGORITHM:NFACTOR:LOOKUPGAP:DEVICE:INTENSITY:XINTENSITY:RAWINTENSITY:GPUENGINE:GPUMEMCLOCK + :GPUTHREADS:GPUFAN:GPUPOWERTUNE:GPUVDDC:SHADERS:THREADCONCURRENCY:WORKSIZE (*) + none There is no reply section just the STATUS section + stating the results of attempting to add profile NAME + The Msg includes the profile NAME. Parameters NAME and + ALGORITHM are required. Everything else is optional. + Note that these parameters are colon (:) delimited. + +removeprofile|NAME (*) + none There is no reply section just the STATUS section + stating the results of removing profile NAME. + The Msg includes the profile NAME. The profile NAME + must exist and not be in use by any of the pools or + as default profile. + N.B. all details for the profile will be lost + +gpuenable|N (*) none There is no reply section just the STATUS section stating the results of the enable request @@ -474,6 +600,7 @@ The list of requests - a (*) means it requires privileged access - and replies: A warning reply means lock stats are not compiled into sgminer The API writes all the lock stats to stderr +``` When you enable, disable or restart a GPU, PGA or ASC, you will also get Thread messages in the sgminer status window @@ -524,15 +651,18 @@ miner.php - an example web page to access the API See the end of this API readme for details of how to tune the display and also to use the option to display a multi-rig summary ----------- - -Feature Changelog for external applications using the API: +## API Version History +API V4.0 (sgminer v5.0) -API V - -Modified API commands: - 'version' - add 'Miner' +Modified API command: + 'addpool' - supports profile and algorithm is correctly set to default if none is selected +Added API commands: + 'changestrategy' - change multi pool strategy on the fly from API + 'changepoolprofile' - change pool profile + 'addprofile' - add a new profile + 'removeprofile' - removes a profile + 'profiles' - list profiles ---------- @@ -957,8 +1087,8 @@ Commands: ---------------------------------------- -miner.php -========= +## miner.php + miner.php is a PHP based interface to the sgminer RPC API (referred to simply as the API below) diff --git a/doc/GPU b/doc/GPU.md similarity index 100% rename from doc/GPU rename to doc/GPU.md diff --git a/doc/configuration.md b/doc/configuration.md index 66d79663..c2c1fec6 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -2,71 +2,2174 @@ *Work in progress!* +### Table of contents + +* [CLI Only options](#cli-only-options) +* [Config-file and CLI options](#config-file-and-cli-options) +* [Working with Profiles and Pool Specific Settings](#working-with-profiles-and-pool-specific-settings) +* [Includes](#includes) + +### Configuration Settings Order + +The configuration settings in sgminer are applied in this order: + +``` +Command Line > Config File Globals/Default Profile > Pool Profile > Pool Specific +``` + +--- + +## CLI Only options + +* [config](#config) `--config` or `-c` +* [default-config](#default-config) `--default-config` +* [help](#help) `--help` or `-h` +* [ndevs](#ndevs) `-ndevs` or `-n` +* [version](#version) `--version` or `-V` + +--- + +### config + +Load a JSON-formatted configuration file. See `example.conf` for an example configuration file. + +Note that the configuration file's settings will override any settings passed via command line. For more information, see [Configuration Settings Order](#configuration-settings-order). + +*Syntax:* `--config ` or `-c ` + +*Argument:* string + +*Example:* + +``` +# ./sgminer -c example.conf +``` + +[Top](#configuration-and-command-line-options) :: [CLI Only options](#cli-only-options) + +### default-config + +Specifies the name of the default configuration file to be loaded at start up and also used to save any settings changes during operation. + +*Syntax:* `--default-config ` + +*Argument:* string + +*Example:* + +``` +# ./sgminer --default_config defaultconfig.conf +``` + +[Top](#configuration-and-command-line-options) :: [CLI Only options](#cli-only-options) + +### help + +Displays the current sgminer version string, followed by the command line syntax help and then exits. + +*Syntax:* `--help` or `-h` + +*Example:* + +``` +# ./sgminer -h +sgminer 4.2.1-116-g2e8b-dirty +Usage: ./sgminer [-DdEgXKlLmpPQqUsTouvwOchnV] +Options for both config file and command line: +--algorithm Set mining algorithm and most common defaults, default: scrypt +--api-allow Allow API access only to the given list of [G:]IP[/Prefix] addresses[/subnets] +--api-description Description placed in the API status header, default: sgminer version +--api-groups API one letter groups G:cmd:cmd[,P:cmd:*...] defining the cmds a groups can use +--api-listen Enable API, default: disabled + +... + +``` + +[Top](#configuration-and-command-line-options) :: [CLI Only options](#cli-only-options) + +### ndevs + +Displays the number of GPUs detected, Open CL/ADL platform information and then exits. + +*Syntax:* `--ndevs` or `-n` + +*Example:* + +``` +# ./sgminer -n +[10:16:04] CL Platform vendor: Advanced Micro Devices, Inc. +[10:16:04] CL Platform name: AMD Accelerated Parallel Processing +[10:16:04] CL Platform version: OpenCL 1.2 AMD-APP (1348.5) +[10:16:04] Platform devices: 2 +[10:16:04] 0 Tahiti +[10:16:04] 1 Tahiti +[10:16:04] Number of ADL devices: 2 +[10:16:04] ATI ADL Overdrive5 API found. +[10:16:04] ATI ADL Overdrive6 API found. +[10:16:04] Found 12 logical ADL adapters + +... + +``` + +[Top](#configuration-and-command-line-options) :: [CLI Only options](#cli-only-options) + +### version + +Displays the current sgminer version string and exits. + +*Syntax:* `--version` or `-V` + +*Example:* + +``` +# ./sgminer -V +sgminer 4.2.1-116-g2e8b-dirty +``` + +[Top](#configuration-and-command-line-options) :: [CLI Only options](#cli-only-options) + +--- ## Config-file and CLI options +* [API Options](#api-options) + * [api-allow](#api-allow) + * [api-description](#api-description) + * [api-groups](#api-groups) + * [api-listen](#api-listen) + * [api-mcast](#api-mcast) + * [api-mcast-addr](#api-mcast-addr) + * [api-mcast-code](#api-mcast-code) + * [api-mcast-des](#api-mcast-des) + * [api-mcast-port](#api-mcast-port) + * [api-network](#api-network) + * [api-port](#api-port) +* [Algorithm Options](#algorithm-options) + * [algorithm](#algorithm) + * [lookup-gap](#lookup-gap) + * [nfactor](#nfactor) + * [hamsi-expand-big](#hamsi-expand-big) + * [shaders](#shaders) + * [thread-concurrency](#thread-concurrency) + * [worksize](#worksize) +* [GPU Options](#gpu-options) + * [auto-fan](#auto-fan) + * [auto-gpu](#auto-gpu) + * [gpu-dyninterval](#gpu-dyninterval) + * [gpu-engine](#gpu-engine) + * [gpu-platform](#gpu-platform) + * [gpu-threads](#gpu-threads) + * [gpu-fan](#gpu-fan) + * [gpu-map](#gpu-map) + * [gpu-memclock](#gpu-memclock) + * [gpu-memdiff](#gpu-memdiff) + * [gpu-powertune](#gpu-powertune) + * [gpu-reorder](#gpu-reorder) + * [gpu-threads](#gpu-threads) + * [gpu-vddc](#gpu-vddc) + * [intensity](#intensity) + * [no-adl](#no-adl) + * [no-restart](#no-restart) + * [rawintensity](#rawintensity) + * [temp-cutoff](#temp-cutoff) + * [temp-hysteresis](#temp-hysteresis) + * [temp-overheat](#temp-overheat) + * [temp-target](#temp-target) + * [xintensity](#xintensity) +* [Pool Options](#pool-options) + * [algorithm](#algorithm) + * [description](#description) + * [device](#device) + * [gpu-engine](#gpu-engine) + * [gpu-fan](#gpu-fan) + * [gpu-memclock](#gpu-memclock) + * [gpu-powertune](#gpu-powertune) + * [gpu-threads](#gpu-threads) + * [gpu-vddc](#gpu-vddc) + * [intensity](#intensity) + * [lookup-gap](#lookup-gap) + * [name](#pool-name) + * [nfactor](#nfactor) + * [no-extranonce](#no-extranonce) + * [pass](#pass) + * [priority](#priority) + * [profile](#profile) + * [quota](#quota) + * [rawintensity](#rawintensity) + * [shaders](#shaders) + * [state](#state) + * [thread-concurrency](#thread-concurrency) + * [url](#url) + * [user](#user) + * [userpass](#userpass) + * [worksize](#worksize) + * [xintensity](#xintensity) +* [Pool Strategy Options](#pool-strategy-options) + * [balance](#balance) + * [disable-rejecting](#disable-rejecting) + * [failover-only](#failover-only) + * [failover-switch-delay](#failover-switch-delay) + * [load-balance](#load-balance) + * [rotate](#rotate) + * [round-robin](#round-robin) +* [Profile Options](#profile-options) + * [algorithm](#algorithm) + * [device](#device) + * [gpu-engine](#gpu-engine) + * [gpu-fan](#gpu-fan) + * [gpu-memclock](#gpu-memclock) + * [gpu-powertune](#gpu-powertune) + * [gpu-threads](#gpu-threads) + * [gpu-vddc](#gpu-vddc) + * [intensity](#intensity) + * [lookup-gap](#lookup-gap) + * [name](#profile-name) + * [nfactor](#nfactor) + * [rawintensity](#rawintensity) + * [shaders](#shaders) + * [thread-concurrency](#thread-concurrency) + * [worksize](#worksize) + * [xintensity](#xintensity) +* [Miscellaneous Options](#miscellaneous-options) + * [benchmark](#benchmark) + * [compact](#compact) + * [debug](#debug) + * [default-profile](#default-profile) + * [device](#device) + * [difficulty-multiplier](#difficulty-multiplier) + * [expiry](#expiry) + * [fix-protocol](#fix-protocol) + * [incognito](#incognito) + * [kernel-path](#kernel-path) + * [log](#log) + * [log-show-date](#log-show-date) + * [lowmem](#lowmem) + * [monitor](#monitor) + * [more-notices](#more-notices) + * [net-delay](#net-delay) + * [no-client-reconnect](#no-client-reconnect) + * [per-device-stats](#per-device-stats) + * [protocol-dump](#protocol-dump) + * [queue](#queue) + * [quiet](#quiet) + * [real-quiet](#real-quiet) + * [remove-disabled](#remove-disabled) + * [scan-time](#scan-time) + * [sched-start](#sched-start) + * [sched-stop](#sched-stop) + * [sharelog](#sharelog) + * [shares](#shares) + * [socks-proxy](#socks-proxy) + * [show-coindiff](#show-coindiff) + * [syslog](#syslog) + * [tcp-keepalive](#tcp-keepalive) + * [text-only](#text-only) + * [verbose](#verbose) + * [worktime](#worktime) + +--- + +## API Options + +### api-allow + +Specifies the API access list. + +*Available*: Global + +*Config File Syntax:* `"api-allow":""` + +*Command Line Syntax:* `--api-allow ""` + +*Argument:* `comma (,) delimited list` Format: `[:][/Prefix] [/subnets][,...]` + +*Default:* None + +*Example:* + +``` +"api-allow":"W:127.0.0.1,W:192.168.0.10" +``` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-description + +Description placed in the API status header. + +*Available*: Global + +*Config File Syntax:* `"api-description":""` + +*Command Line Syntax:* `--api-description ""` + +*Argument:* `string` + +*Default:* `sgminer version` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-groups + +Sets API groups which restrict group members to only a certain set of commands. The list of groups is comma(,) delimited and each entry has its parameters colon(:) delimited. The first parameter of an entry is always the Group Identifier, which consists of one letter. When defining a group, you can use the asterisk (*) to refer to all non-priviledged functions. + +Two groups are pre-defined and may not be used with this option: +* `R` Access to all non-priviledged functions +* `W` Access to all priviledged and non-priviledged functions + +Group Members are specified in [api-allow](#api-allow) where they are associated with a group by their IP address. + +*Available*: Global + +*Config File Syntax:* `"api-groups":""` + +*Command Line Syntax:* `--api-groups ""` + +*Argument:* `comma (,) delimited list` Format: `::[:*][:...][,...]` + +*Default:* `R` Access to all non-priviledged functions `W` Access to all functions + +*Example:* + +``` +"api-groups":"A:addpool:*,B:addpool:removepool:switchpool:gpurestart:gpuenable:gpudisable:save:quit", +"api-allow":"A:192.168.0.10,B:127.0.0.1" +``` + +The above example grants users of group A access to the addpool function as well as all non-priviledged functions. +Group B users only have access to the following functions: addpool, removepool, switchpool, gpurestart, gpuenable, gpudisable, save, quit. + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-listen + +Enables the API. + +*Available*: Global + +*Config File Syntax:* `"api-listen":true` + +*Command Line Syntax:* `--api-listen` + +*Argument:* None + +*Default:* `false` (disabled) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-mcast + +Enables the API over multicast. + +*Available*: Global + +*Config File Syntax:* `"api-mcast":true` + +*Command Line Syntax:* `--api-mcast` + +*Argument:* None + +*Default:* `false` (disabled) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-mcast-addr + +Set the API multicast address. + +*Available*: Global + +*Config File Syntax:* `"api-mcast-addr":""` + +*Command Line Syntax:* `--api-mcast-addr ` + +*Argument:* `string` IP Address + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-mcast-code + +Code to use in API multicast messages. **Do not use the dash (-)** + +*Available*: Global + +*Config File Syntax:* `"api-mcast-code":""` + +*Command Line Syntax:* `--api-mcast-code ""` + +*Argument:* `string` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-mcast-des + +Description appended to API multicast replies. + +*Available*: Global + +*Config File Syntax:* `"api-mcast-des":""` + +*Command Line Syntax:* `--api-mcast-des ""` + +*Argument:* `string` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-mcast-port + +Port to use for API multicast. + +*Available*: Global + +*Config File Syntax:* `"api-mcast-port":""` + +*Command Line Syntax:* `--api-mcast-port ` + +*Argument:* `number` Port Number between 1 and 65535 + +*Default:* `4028` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-network + +**Needs clarification** Allows API (if enabled) to listen on/for any address. + +*Available*: Global + +*Config File Syntax:* `"api-network":true` + +*Command Line Syntax:* `--api-network` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +### api-port + +Port to use for API. + +*Available*: Global + +*Config File Syntax:* `"api-port":""` + +*Command Line Syntax:* `--api-port ` + +*Argument:* `number` Port Number between 1 and 65535 + +*Default:* `4028` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [API Options](#api-options) + +--- + +## Algorithm Options + ### algorithm -Allows choosing between the few mining algorithms for incompatible -cryptocurrencies. +**Formerly the kernel option.** Sets the algorithm to use for mining. -If specified in a pool section in the configuration file, sets the -option for that pool only. Otherwise sets the default. +*Available*: Global, Pool, Profile -*Argument:* string +*Config File Syntax:* `"algorithm":""` + +*Command Line Syntax:* `--algorithm ` `--pool-algorithm ` `--profile-algorithm ` + +*Argument:* `string` + +*Default:* `ckolivas` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) -*Default:* `scrypt` +### lookup-gap -*Supported:* +Set GPU lookup gap for scrypt mining. -* `adaptive-n-factor` - Vertcoin-style adaptive N-factor scrypt. - N-factor defaults to 11. Aliases: `adaptive-nfactor` (to be removed - in future versions) and `nscrypt`. -* `scrypt` - Litecoin-style static N-factor scrypt. -* everything else - currently defaults to `scrypt`, subject to change - without warning. +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"lookup-gap":""` + +*Command Line Syntax:* `--lookup-gap ""` `--pool-lookup-gap ""` `--profile-lookup-gap ""` + +*Argument:* `One value or a comma (,) delimited list` GPU lookup gap + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) ### nfactor -Overrides the default scrypt parameter N, specified as the factor of 2 -(`N = 2^nfactor`). +Overrides the default scrypt parameter N, specified as the factor of 2 (`N = 2^nfactor`). + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"nfactor":""` + +*Command Line Syntax:* `--nfactor ` `--pool-nfactor ` `--profile-nfactor ` -If specified in a pool section in the configuration file, sets the -option for that pool only. Otherwise sets the default. +*Argument:* `number` Nfactor 1 or greater -*Argument:* whole number (>1). +*Default:* `10` -*Default:* depends on `algorithm`; otherwise `10`. +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) ### hamsi-expand-big -Sets SPH_HAMSI_EXPAND_BIG for X13 algorithms. Values `"4"` and `"1"` are -commonly used. Changing this may improve hashrate. Which value is better -depends on GPU type and even manufacturer (i.e. exact GPU model). +Sets SPH_HAMSI_EXPAND_BIG for X13 algorithms. Values `"4"` and `"1"` are commonly used. Changing this may improve hashrate. Which value is better depends on GPU type and even manufacturer (i.e. exact GPU model). + +*Available*: Global + +*Config File Syntax:* `"hamsi-expand-big":""` + +*Command Line Syntax:* `--hamsi-expand-big ` + +*Argument:* `4` or `1` + +*Default:* `4` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) + +### shaders + +Number of shaders per GPU for algorithm tuning. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"shaders":""` + +*Command Line Syntax:* `--shaders ""` `--pool-shaders ""` `--profile-shaders ""` + +*Argument:* `One value or a comma (,) delimited list` GPU shaders + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) + +### thread-concurrency + +Number of concurrent threads per GPU for mining. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"thread-concurrency":""` + +*Command Line Syntax:* `--thread-concurrency ""` `--pool-thread-concurrency ""` `--profile-thread-concurrency ""` + +*Argument:* `One value or a comma (,) delimited list` GPU thread concurrency + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) + +### worksize + +Amount of work handled by GPUs per work request. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"worksize":""` + +*Command Line Syntax:* `--worksize ""` `-w ""` `--pool-worksize ""` `--profile-worksize ""` + +*Argument:* `One value or a comma (,) delimited list` GPU worksize + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Algorithm Options](#algorithm-options) + +--- + +## GPU Options + +### auto-fan + +Automatically adjust all GPU fan speeds to maintain a target temperature. + +Used with [temp-target](#temp-target), [temp-cutoff](#temp-cutoff), [temp-overheat](#temp-overheat) and [temp-hysteresis](#temp-hysteresis). + +*Available*: Global + +*Config File Syntax:* `"auto-fan":true` + +*Command Line Syntax:* `--auto-fan` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### auto-gpu + +Automatically adjust all GPU engine clock speeds to maintain a target temperature. + +Used with [temp-target](#temp-target), [temp-cutoff](#temp-cutoff), [temp-overheat](#temp-overheat) and [temp-hysteresis](#temp-hysteresis). + +*Available*: Global + +*Config File Syntax:* `"auto-gpu":true` + +*Command Line Syntax:* `--auto-gpu` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-dyninterval + +**Need clarification** Refresh interval in milliseconds (ms) for GPUs using dynamic intensity. + +*Available*: Global + +*Config File Syntax:* `"gpu-dyninterval":""` + +*Command Line Syntax:* `--gpu-dyninterval ` + +*Argument:* `number` Number of milliseconds from 1 to 65535. + +*Default:* `7` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-engine + +Set the GPU core clock range in Mhz. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"gpu-engine":""` + +*Command Line Syntax:* `--gpu-engine ""` `--pool-gpu-engine ""` `--profile-gpu-engine ""` + +*Argument:* `One value, range and/or comma (,) separated list` GPU engine clocks in Mhz + +*Default:* None + +*Example:* + +``` +"gpu-engine":"1000,950-1100,1050-1050" +``` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-fan + +Set the GPU fan percentage range. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"gpu-fan":""` + +*Command Line Syntax:* `--gpu-fan ""` `--pool-gpu-fan ""` `--profile-gpu-fan ""` + +*Argument:* `One value, range and/or comma (,) separated list` GPU fan speed percentage + +*Default:* None + +*Example:* + +``` +"gpu-fan":"75-85,100,50-50" +``` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-map + +Manually map OpenCL to ADL devices. + +*Available*: Global + +*Config File Syntax:* `"gpu-map":""` + +*Command Line Syntax:* `--gpu-map ""` + +*Argument:* `comma (,) delimited list` Format: `:,:[,...]` + +*Default:* None + +*Example:* + +``` +"gpu-map":"1:0,2:1,3:2" +``` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-memclock + +Set the GPU memory clock in Mhz. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"gpu-memclock":""` + +*Command Line Syntax:* `--gpu-memclock ""` `--pool-gpu-memclock ""` `--profile-gpu-memclock ""` + +*Argument:* `one value and/or comma (,) delimited list` GPU memory clocks in Mhz + +*Default:* None + +*Example:* + +``` +"gpu-memclock":"1500,1250,1000" +``` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-memdiff + +Set a fixed difference between the GPU core clock and memory clock while in auto-gpu mode. + +*Available*: Global + +*Config File Syntax:* `"gpu-memdiff":""` + +*Command Line Syntax:* `--gpu-memdiff ""` + +*Argument:* `number` Clock difference in Mhz + +*Default:* None + +*Example:* + +``` +"auto-gpu":true, +"gpu-engine":"900-1100", +"gpu-memclock":"400" +``` +With the above, memory clock would range between 1300Mhz and 1500Mhz. + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-platform + +**Need clarification** Select the OpenCL platform ID to use for GPU mining. + +*Available*: Global + +*Config File Syntax:* `"gpu-platform":""` + +*Command Line Syntax:* `--gpu-platform ` + +*Argument:* `number` OpenCL Platform ID number between 0 and 9999. + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-powertune + +Set the GPU Powertune percentage. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"gpu-powertune":""` + +*Command Line Syntax:* `--gpu-powertune ""` `-g ""` `--pool-gpu-powertune ""` `--profile-gpu-powertune ""` + +*Argument:* `one value or a comma (,) delimited list` GPU Powertune percentages + +*Default:* `0` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-reorder + +Attempts to reorder the GPUs according to their PCI Bus ID. + +*Available*: Global + +*Config File Syntax:* `"gpu-reorder":true` + +*Command Line Syntax:* `--gpu-reorder` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-threads + +Number of mining threads per GPU. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"gpu-threads":""` + +*Command Line Syntax:* `--gpu-threads ""` `-g ""` `--pool-gpu-threads ""` `--profile-gpu-threads ""` + +*Argument:* `one value or (,) delimited list` GPU threads + +*Default:* `1` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### gpu-vddc + +Set the GPU voltage in Volts. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"gpu-vddc":""` + +*Command Line Syntax:* `--gpu-vddc ""` `--pool-gpu-vddc ""` `--profile-gpu-vddc ""` + +*Argument:* `one value or comma (,) delimited list` GPU voltage in Volts + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### intensity + +Intensity of GPU scanning. + +Overridden by [xintensity](#xintensity) and [rawintensity](#rawintensity). + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"intensity":""` + +*Command Line Syntax:* `--intensity ""` `-I ""` `--pool-intensity ""` `--profile-intensity ""` + +*Argument:* `one value or a comma (,) delimited list` GPU Intensity between 8 and 31. Use `d` instead of a number to maintain desktop interactivity. + +*Default:* `d` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### no-adl + +Disable the AMD ADL library. **Note that without ADL, all GPU monitoring is disabled and all GPU parameter functions will not work.** + +*Available*: Global + +*Config File Syntax:* `"no-adl":true` + +*Command Line Syntax:* `--no-adl` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### no-restart + +Do not attempt to restart GPUs that hang. + +*Available*: Global + +*Config File Syntax:* `"no-restart":true` + +*Command Line Syntax:* `--no-restart` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### rawintensity + +Raw intensity of GPU scanning. + +Overriddes by [intensity](#intensity) and [xintensity](#xintensity). + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"rawintensity":""` + +*Command Line Syntax:* `--rawintensity ""` `--pool-rawintensity ""` `--profile-rawintensity ""` + +*Argument:* `one value or a comma (,) delimited list` GPU Raw intensity between 1 and 2147483647. + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### temp-cutoff + +Temperature at which a GPU will be disabled at. + +Used with [auto-fan](#auto-fan) and [auto-gpu](#auto-gpu). + +*Available*: Global + +*Config File Syntax:* `"temp-cutoff":""` + +*Command Line Syntax:* `--temp-cutoff ""` + +*Argument:* `one value or a comma (,) delimited list` Temperature in Celcius + +*Default:* `95` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### temp-cutoff + +Set the allowable temperature fluctuation a GPU can operate outside of limits. + +Used with [auto-fan](#auto-fan) and [auto-gpu](#auto-gpu). + +*Available*: Global + +*Config File Syntax:* `"temp-hysteresis":""` + +*Command Line Syntax:* `--temp-hysteresis ` + +*Argument:* `number` Temperature in Celcius between 0 and 10 + +*Default:* `3` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### temp-overheat + +Temperature at which a GPU will be throttled. + +Used with [auto-fan](#auto-fan) and [auto-gpu](#auto-gpu). + +*Available*: Global + +*Config File Syntax:* `"temp-overheat":""` + +*Command Line Syntax:* `--temp-overheat ""` + +*Argument:* `one value or a comma (,) delimited list` Temperature in Celcius + +*Default:* `85` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### temp-target + +Temperature at which a GPU should stay at. + +Used with [auto-fan](#auto-fan) and [auto-gpu](#auto-gpu). + +*Available*: Global + +*Config File Syntax:* `"temp-target":""` + +*Command Line Syntax:* `--temp-target ""` + +*Argument:* `one value or a comma (,) delimited list` Temperature in Celcius + +*Default:* `75` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +### xintensity + +Shader based intensity of GPU scanning. + +Overridden by [rawintensity](#rawintensity) and overrides [intensity](#intensity). + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"xintensity":""` + +*Command Line Syntax:* `--xintensity ""` `-X ""` `--pool-xintensity ""` `--profile-xintensity ""` + +*Argument:* `one value or a comma (,) delimited list` GPU Xintensity between 1 and 9999. + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [GPU Options](#gpu-options) + +--- + +## Pool Options + +### [pool-]algorithm + +See [algorithm](#algorithm) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### description + +Set the pool's description + +*Available*: Pool + +*Config File Syntax:* `"description":""` + +*Command Line Syntax:* `--pool-description ""` + +*Argument:* `string` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]device + +See [device](#device). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]gpu-engine + +See [gpu-engine](#gpu-engine) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]gpu-fan + +See [gpu-fan](#gpu-fan) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]gpu-memclock + +See [gpu-memclock](#gpu-memclock) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]gpu-powertune + +See [gpu-powertune](#gpu-powertune) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]gpu-threads + +See [gpu-threads](#gpu-threads) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]gpu-vddc + +See [gpu-vddc](#gpu-vddc) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]intensity + +See [intensity](#intensity) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]lookup-gap + +See [lookup-gap](#lookup-gap) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]name + +Set a name for a pool. + +*Available*: Pool + +*Config File Syntax:* `"name":""` + +*Command Line Syntax:* `--name ""` `--pool-name ""` + +*Argument:* `string` Name of the pool + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]nfactor + +See [nfactor](#nfactor) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### no-extranonce + +Disable 'extranonce' stratum subscribe for pool. + +*Available*: Pool + +*Config File Syntax:* `"no-extranonce:true` + +*Command Line Syntax:* `--no-extranonce` `--pool-no-extranonce` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### pass + +Set pool password. + +*Available*: Pool + +*Config File Syntax:* `"pass":""` + +*Command Line Syntax:* `--pass ""` `-p ""` `--pool-pass ""` + +*Argument:* `string` Pool password + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### priority + +Set the priority of the pool other than the order it is entered in the pool list. + +*Available*: Pool + +*Config File Syntax:* `"priority":""` + +*Command Line Syntax:* `--priority ` `--pool-priority ` + +*Argument:* `number` Pool priority + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### profile + +Set the profile to use for this pool's settings. + +*Available*: Pool + +*Config File Syntax:* `"profile":""` + +*Command Line Syntax:* `--pool-profile ""` + +*Argument:* `string` Pool profile name + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### quota + +Replaces the pool [url](#url) when using the load-balance multipool strategy and enables setting a quota percentage for the pool. + +*Available*: Pool + +*Config File Syntax:* `"quota":""` + +*Command Line Syntax:* `--quota ""` `--pool-quota ""` `-U ""` + +*Argument:* `string` Pool quota and url in the form `;` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]rawintensity + +See [rawintensity](#rawintensity) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]shaders + +See [shaders](#shaders) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### state + +Set the pool state at startup. + +*Available*: Pool + +*Config File Syntax:* `"state":""` + +*Command Line Syntax:* `--state ""` `--pool-state ""` + +*Argument:* `string` Pool state. Possible values: `enabled` `disabled` `hidden` `rejecting` + +*Default:* `enabled` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]thread-concurrency + +See [thread-concurrency](#thread-concurrency) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### url + +Set the Pool URL. + +*Available*: Pool + +*Config File Syntax:* `"url":""` + +*Command Line Syntax:* `--url ""` `--pool-url ""` `-o ""` + +*Argument:* `string` Pool URL + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### user + +Set the Pool username. + +*Available*: Pool + +*Config File Syntax:* `"user":""` + +*Command Line Syntax:* `--user ""` `--pool-user ""` `-u ""` + +*Argument:* `string` Pool username + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### userpass + +Set the Pool username and password. + +*Available*: Pool + +*Config File Syntax:* `"userpass":""` + +*Command Line Syntax:* `--userpass ""` `--pool-userpass ""` `-O ""` + +*Argument:* `string` Pool username and password `:` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]worksize + +See [worksize](#worksize) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +### [pool-]xintensity + +See [intensity](#xintensity) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Options](#pool-options) + +--- + +## Pool Strategy Options + +### balance + +Changes the multipool strategy to even share balance. + +*Available*: Global + +*Config File Syntax:* `"balance":true` + +*Command Line Syntax:* `--balance` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +### disable-rejecting + +Automatically disable a pool that continually reject shares. + +*Available*: Global + +*Config File Syntax:* `"disable-rejecting":true` + +*Command Line Syntax:* `--disable-rejecting` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +### failover-only + +Use the first pool alive based on pool priority. + +*Available*: Global + +*Config File Syntax:* `"failover-only":true` + +*Command Line Syntax:* `--failover-only` + +*Argument:* None + +*Default:* `true` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +### failover-switch-delay + +Number of seconds to wait before switching back to a previously failed pool. + +*Available*: Global + +*Config File Syntax:* `"failover-switch-delay":""` + +*Command Line Syntax:* `--failover-switch-delay ` + +*Argument:* `number` Number of seconds between 1 and 65535. + +*Default:* `60` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +### load-balance + +Changes the multipool strategy to quota based balance. + +**Note:** Use [quota](#quota) instead of [url](#url) in pool settings when using this multipool strategy. + +*Available*: Global + +*Config File Syntax:* `"load-balance":true` + +*Command Line Syntax:* `--load-balance` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +### rotate + +Changes the multipool strategy to rotate between pools after a certain amount of time in seconds. + +*Available*: Global + +*Config File Syntax:* `"rotate":""` + +*Command Line Syntax:* `--rotate ` + +*Argument:* `number` Number of seconds between 0 and 9999 before switching to the next pool + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +### round-robin + +Changes the multipool strategy to round-robin. + +*Available*: Global + +*Config File Syntax:* `"round-robin":true` + +*Command Line Syntax:* `--round-robin` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Pool Strategy Options](#pool-strategy-options) + +--- + +## Profile Options + +### [profile-]algorithm + +See [algorithm](#algorithm) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]device + +See [device](#device). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]gpu-engine + +See [gpu-engine](#gpu-engine). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]gpu-fan + +See [gpu-fan](#gpu-fan). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]gpu-memclock + +See [gpu-memclock](#gpu-memclock). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]gpu-powertune + +See [gpu-powertune](#gpu-powertune). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]gpu-threads + +See [gpu-threads](#gpu-threads). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]gpu-vddc + +See [gpu-vddc](#gpu-vddc). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]intensity + +See [intensity](#intensity). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]lookup-gap + +See [lookup-gap](#lookup-gap). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]name + +Set a name for a profile. + +**Note** if no profile name is set, the profile name defaults to the profile number in the order that +it was entered starting with `0`. + +*Available*: Profile + +*Config File Syntax:* `"name":""` + +*Command Line Syntax:* `--profile-name ""` + +*Argument:* `string` Name of the profile + +*Default:* `Profile number` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]nfactor + +See [nfactor](#nfactor). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]rawintensity + +See [rawintensity](#rawintensity). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]shaders + +See [shaders](#shaders) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]thread-concurrency + +See [thread-concurrency](#thread-concurrency) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]worksize + +See [worksize](#worksize) + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +### [profile-]xintensity + +See [xintensity](#xintensity). + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Profile Options](#profile-options) + +--- + +## Miscellaneous Options + +### benchmark + +Runs sgminer in benchmark mode. **This does not produce any shares.** + +*Available*: Global + +*Config File Syntax:* `"benchmark":true` + +*Command Line Syntax:* `--benchmark` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### compact + +Use a compact display, without per device statistics. + +*Available*: Global + +*Config File Syntax:* `"compact":true` + +*Command Line Syntax:* `--compact` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### debug + +Enable debug output. + +*Available*: Global + +*Config File Syntax:* `"debug":true` + +*Command Line Syntax:* `--debug` or `-D` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### default-profile + +Use this profile for sgminer's default settings. + +*Available*: Global + +*Config File Syntax:* `"default-profile":""` + +*Command Line Syntax:* `--default-profile ` + +*Argument:* `string` Profile name + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### device + +Select devices to use. + +**Note:** if you assign per-profile or per-pool devices to be turned on or off, it is recommended to specify `"device":"*"` on the other pools or profiles that should use all devices. + +*Available*: Global, Pool, Profile + +*Config File Syntax:* `"device":""` + +*Command Line Syntax:* `--device ""` `-d ""` `--pool-device ""` `--profile-device ""` + +*Argument:* `one value, range and/or a comma (,) separated list with a combination of both` To enable all devices use the asterisk (*) or the word "all". + +*Default:* None (all devices enabled) + +*Example:* + +``` +{ +"pools":[ + { + "url":"stratum+tcp://pool.ip:8334", + "user":"user", + "pass":"x" + }, + { + "url":"stratum+tcp://pool2.ip:3333", + "user":"user", + "pass":"x", + "profile":"x11" + } +], +"profiles":[ + { + "name":"x11", + "algorithm":"darkcoin-mod", + "devices":"*" + } +], +... +"algorithm":"ckolivas", +"device":"0,2-5" +... +} +``` + +The above would start mining `scrypt` on `pool.ip` with devices `0, 2, 3, 4, 5`. Upon switching to `pool2.ip`, all devices would be enabled to mine `x11`. + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### difficulty-multiplier + +**Need clarification** Set the difficulty multiplier for jobs received from stratum pools. + +*Available*: Global + +*Config File Syntax:* `"difficulty-multiplier":""` + +*Command Line Syntax:* `--difficulty-multiplier ` + +*Argument:* `number` Decimal multiplier + +*Default:* `0.0` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### expiry + +Set how many seconds to wait after getting work before sgminer considers it a stale share. + +*Available*: Global + +*Config File Syntax:* `"expiry":""` + +*Command Line Syntax:* `--expiry ` or `-E ` + +*Argument:* `number` Number of seconds between 0 and 9999. + +*Default:* `28` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### fix-protocol + +**Need clarification** Do not redirect to a different getwork protocol (e.g. stratum). + +*Available*: Global + +*Config File Syntax:* `"fix-protocol":true` + +*Command Line Syntax:* `--fix-protocol` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### incognito + +Do not display user name in status window. + +*Available*: Global + +*Config File Syntax:* `"incognito":true` + +*Command Line Syntax:* `--incognito` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### kernel-path + +Path to where the kernel files are. + +*Available*: Global + +*Config File Syntax:* `"kernel-path":""` + +*Command Line Syntax:* `--kernel-path ""` `-K ""` + +*Argument:* `string` Path to kernel files + +*Default:* `/path/to/sgminer` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### log + +Set the interval in seconds between log outputs. + +*Available*: Global + +*Config File Syntax:* `"log":""` + +*Command Line Syntax:* `--log ` `-l ` + +*Argument:* `number` Number of seconds between 0 and 9999. + +*Default:* `5` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### log-show-date + +Show a timestamp on every log line. + +*Available*: Global + +*Config File Syntax:* `"log-show-date":true` + +*Command Line Syntax:* `--log-show-date` `-L` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### lowmem + +Minimize caching of shares for low memory systems. + +*Available*: Global + +*Config File Syntax:* `"lowmem":true` + +*Command Line Syntax:* `--lowmem` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### monitor + +Use custom pipe command for output messages. **Only available on unix based operating systems.** + +*Available*: Global + +*Config File Syntax:* `"monitor":""` + +*Command Line Syntax:* `--monitor ""` `-m ""` + +*Argument:* `string` Command to pipe messages through. + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### more-notices + +Display work restart and new block notices. + +*Available*: Global + +*Config File Syntax:* `"more-notices":true` + +*Command Line Syntax:* `--more-notices` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### net-delay + +Set small delays in networking not to overload slower routers. + +*Available*: Global + +*Config File Syntax:* `"net-delay":true` + +*Command Line Syntax:* `--net-delay` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### no-client-reconnect + +Disabled the 'client.reconnect' stratum functionality. + +*Available*: Global + +*Config File Syntax:* `"no-client-reconnect":true` + +*Command Line Syntax:* `--no-client-reconnect` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### no-submit-stale + +Do not submit shares that are detected as stale. + +*Available*: Global + +*Config File Syntax:* `"no-submit-stale":true` + +*Command Line Syntax:* `--no-submit-stale` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### per-device-stats + +Force output of per-device statistics. + +*Available*: Global + +*Config File Syntax:* `"per-device-stats":true` + +*Command Line Syntax:* `--per-device-stats` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### protocol-dump + +Force output of protocol-level activities. + +*Available*: Global + +*Config File Syntax:* `"protocol-dump":true` + +*Command Line Syntax:* `--protocol-dump` `-P` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### queue + +Minimum number of work items to have queued. + +*Available*: Global + +*Config File Syntax:* `"queue":""` + +*Command Line Syntax:* `--queue ` `-Q ` + +*Argument:* `number` Work items to have queued 0 to 9999 + +*Default:* `1` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### quiet + +Disables logging output, display status and errors. + +*Available*: Global + +*Config File Syntax:* `"quiet":true` + +*Command Line Syntax:* `--quiet` `-q` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### real-quiet + +Disables all output. + +*Available*: Global + +*Config File Syntax:* `"real-quiet":true` + +*Command Line Syntax:* `--real-quiet` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### remove-disabled + +Remove disabled devices completely as if they never existed. + +*Available*: Global + +*Config File Syntax:* `"remove-disabled":true` + +*Command Line Syntax:* `--remove-disabled` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### scan-time + +Set how many seconds to spend scanning for current work. + +*Available*: Global + +*Config File Syntax:* `"scan-time":""` + +*Command Line Syntax:* `--scan-time ` or `-s ` + +*Argument:* `number` Number of seconds between 0 and 9999. + +*Default:* `7` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### sched-start + +Set a time of day to start mining at. Used with [sched-stop](#sched-stop). + +*Available*: Global + +*Config File Syntax:* `"sched-start":""` + +*Command Line Syntax:* `--sched-start ""` + +*Argument:* `string` Time of day `HH:MM` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### sched-stop + +Set a time of day to stop mining at. Used with [sched-start](#sched-start). + +*Available*: Global + +*Config File Syntax:* `"sched-stop":""` + +*Command Line Syntax:* `--sched-stop ""` + +*Argument:* `string` Time of day `HH:MM` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### sharelog + +Appends share log to file. + +*Available*: Global + +*Config File Syntax:* `"sharelog":""` + +*Command Line Syntax:* `--sharelog ""` + +*Argument:* `string` Filename of log + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### shares + +Quit after mining a certain amount of shares. + +*Available*: Global + +*Config File Syntax:* `"shares":""` + +*Command Line Syntax:* `--shares ` + +*Argument:* `number` Number of shares + +*Default:* `Unlimited` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### socks-proxy + +Use a socks4 proxy. + +*Available*: Global + +*Config File Syntax:* `"socks-proxy":""` + +*Command Line Syntax:* `--socks-proxy ""` + +*Argument:* `string` Socks proxy settings `:` + +*Default:* None + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### show-coindiff + +Display the coin difficulty rather than the hash value of a share. + +*Available*: Global + +*Config File Syntax:* `"show-coindiff":true` + +*Command Line Syntax:* `--show-coindiff` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### syslog + +Output messages to syslog. **Note:** only available on operating systems with `syslogd`. + +*Available*: Global + +*Config File Syntax:* `"syslog":true` + +*Command Line Syntax:* `--syslog` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### tcp-keepalive + +Set the TCP keepalive packet idle timeout in seconds. **Note:** only available with libcurl and keepalive enabled. + +*Available*: Global + +*Config File Syntax:* `"tcp-keepalive":""` + +*Command Line Syntax:* `--tcp-keepalive ` + +*Argument:* `number` Number of seconds between 0 and 9999. + +*Default:* `30` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### text-only + +Disables the ncurses formatted screen output and user interface. + +*Available*: Global + +*Config File Syntax:* `"text-only":true` + +*Command Line Syntax:* `--text-only` `-T` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### verbose + +Outputs log and status to stderr. **Note:** only available on unix based operating systems. + +*Available*: Global + +*Config File Syntax:* `"verbose":true` + +*Command Line Syntax:* `--verbose` `-v` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +### worktime + +Displays extra work time debug information. + +*Available*: Global + +*Config File Syntax:* `"worktime":true` + +*Command Line Syntax:* `--worktime` + +*Argument:* None + +*Default:* `false` + +[Top](#configuration-and-command-line-options) :: [Config-file and CLI options](#config-file-and-cli-options) :: [Miscellaneous Options](#miscellaneous-options) + +--- + +## Working with Profiles and Pool Specific Settings + +Profiles are there to assist you in specifying different GPU or algorithm settings that could be (re-)used by one or more pools. + +[Top](#configuration-and-command-line-options) + +--- + +## Includes -*Argument:* `"4"` or `"1"` -*Default:* `"4"` +`Include` is a special keyword only available in the configuration file. You can include json-formatted files at any level of the configuration parsing. The values read in the included +files are applied to the current object being parsed. -## Pool-specific configuration +``` +/etc/pool.ip.credentials: +{ + "user":"user", + "pass":"x" +} -If you use any of these options for a pool, then **you must** set that option -for every pool. This is necessary due to current poor implementation of -sgminer config parser. +sgminer.conf: +... +"pools":[ + { + "url":"stratum+tcp://pool.ip:8334", + "include":"/etc/pool.ip.credentials" + } +], +... +``` -Options that can be configured have a `pool-` prefix and work the same as the -global settings: +In the example above, the parser will include the contents of the file `/etc/pool.ip.credentials` directly where it was called from. This will produce the following result: -* pool-algorithm -* pool-nfactor -* pool-intensity -* pool-xintensity -* pool-rawintensity -* pool-gpu-engine -* pool-gpu-memclock -* pool-gpu-threads -* pool-thread-concurrency -* pool-gpu-fan +``` +sgminer.conf: +... +"pools":[ + { + "url":"stratum+tcp://pool.ip:8334", + "user":"user", + "pass":"x" + } +], +... +``` -## CLI-only options +There is no limit as to how includes can be used as long as they follow proper json syntax. -*TODO* +[Top](#configuration-and-command-line-options) diff --git a/example.conf b/example.conf index 8c9f9a60..2fb65999 100644 --- a/example.conf +++ b/example.conf @@ -1,71 +1,94 @@ { -"pools" : [ - { - "name" : "Preferred Pool", - "url" : "http://url1:8332", - "user" : "user1", - "pass" : "pass1" - }, - { - "name" : "Failover Pool", - "url" : "http://url2:8344", - "user" : "user2", - "pass" : "pass2", - "state" : "enabled" - }, - { - "name" : "Failover Pool", - "url" : "http://url3:8344", - "user" : "user3", - "pass" : "pass3", - "algorithm" : "adaptive-n-factor", - "state" : "disabled" - }, - { - "name" : "Testing Pool", - "url" : "http://url4:8332", - "user" : "user4", - "pass" : "pass4", - "state" : "hidden" - } -], - -"failover-only" : true, -"failover-switch-delay" : "60", -"no-pool-disable" : true, - -"kernel-path" : "/usr/local/bin", -"kernel" : "alexkarold,ckolivas,zuikkis", - -"algorithm" : "scrypt", - -"intensity" : "d,9,9,9", -"xintensity" : "0,0,0", -"rawintensity" : "0,0,0", -"lookup-gap" : "2,2,2", - -"thread-concurrency" : "15508,15508,15508", -"shaders" : "0,0,0", - -"gpu-threads" : "2", -"gpu-engine" : "0-985,0-950,0-1000", -"gpu-memclock" : "860,825,875", -"gpu-powertune" : "20,20,20", - -"gpu-vddc" : "0.000,0.000,0.000", -"gpu-fan" : "0-85,0-85,0-85", - -"auto-gpu" : true, -"auto-fan" : true, - -"temp-target" : "75,75,75", -"temp-overheat" : "80,85,90", -"temp-cutoff" : "95", -"temp-hysteresis" : "3", - -"queue" : "1", -"scan-time" : "7", -"expiry" : "28", - -"log" : "5" -} + "pools": [ + { + "name":"Testpool X11", + "url": "stratum+tcp://url1:4440", + "user": "user", + "pass": "x", + "priority": "1", + "profile": "x11" + }, + { + "name":"Testpool Scrypt", + "url": "stratum+tcp://url2:3339", + "user": "user", + "pass": "x", + "priority": "2", + "profile": "scrypt" + }, + { + "name":"Testpool X11 with other profile", + "url": "stratum+tcp://url3:4440", + "user": "user", + "pass": "x", + "priority": "0", + "profile": "x11test" + }, + { + "name":"Testpool Using default profile", + "url": "stratum+tcp://url4:3333", + "user": "user", + "pass": "x" + } + ], + "profiles": [ + { + "name": "x11", + "algorithm": "darkcoin-mod", + "intensity": "19", + "thread-concurrency": "10696,8192", + "worksize": "128", + "gpu-engine": "1100", + "gpu-threads": "2", + "gpu-fan": "75" + }, + { + "name": "scrypt", + "algorithm": "ckolivas", + "lookup-gap": "2", + "intensity": "19,13", + "thread-concurrency": "19656,8192", + "worksize": "256", + "gpu-engine": "1000,1065", + "gpu-memclock": "1500", + "gpu-threads": "1,2", + "gpu-fan": "85", + "gpu-powertune": "20" + }, + { + "name": "x11test", + "algorithm": "darkcoin-mod", + "device": "1", + "intensity": "19", + "thread-concurrency": "10696,8192", + "worksize": "512", + "gpu-engine": "1100", + "gpu-threads": "2", + "gpu-fan": "75" + } + ], + "failover-only": true, + "default-profile": "scrypt", + "temp-cutoff": "95,95", + "temp-overheat": "90,90", + "temp-target": "80,80", + "gpu-memdiff": "0,0", + "shares": "0", + "kernel-path": "/usr/local/bin", + "api-allow": "W:127.0.0.1", + "api-listen": true, + "api-mcast-port": "4028", + "api-port": "4028", + "expiry": "1", + "failover-switch-delay": "60", + "gpu-dyninterval": "7", + "gpu-platform": "-1", + "hamsi-expand-big": "4", + "log": "5", + "no-pool-disable": true, + "no-client-reconnect": true, + "queue": "0", + "scan-time": "1", + "tcp-keepalive": "30", + "temp-hysteresis": "3" +} \ No newline at end of file diff --git a/miner.h b/miner.h index fcf419ef..07aa1021 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 @@ -251,7 +253,6 @@ enum alive { LIFE_INIT, }; - enum pool_strategy { POOL_FAILOVER, POOL_ROUNDROBIN, @@ -266,6 +267,9 @@ struct strategies { const char *s; }; +extern enum pool_strategy pool_strategy; +extern struct strategies strategies[]; + struct cgpu_info; #ifdef HAVE_ADL @@ -932,7 +936,21 @@ extern bool opt_protocol; extern bool have_longpoll; extern char *opt_kernel_path; extern char *opt_socks_proxy; + +#if defined(unix) || defined(__APPLE__) + extern char *opt_stderr_cmd; +#endif // defined(unix) + +struct schedtime { + bool enable; + struct tm tm; +}; + +extern struct schedtime schedstart; +extern struct schedtime schedstop; + extern char *sgminer_path; +extern int opt_shares; extern bool opt_fail_only; extern bool opt_autofan; extern bool opt_autoengine; @@ -1023,11 +1041,12 @@ extern void api(int thr_id); extern struct pool *current_pool(void); extern int enabled_pools; extern void get_intrange(char *arg, int *val1, int *val2); +extern char *set_devices(char *arg); extern bool detect_stratum(struct pool *pool, char *url); extern void print_summary(void); extern void adjust_quota_gcd(void); extern struct pool *add_pool(void); -extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *algo); +extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *profile, char *algo); #define MAX_GPUDEVICES 16 #define MAX_DEVICES 4096 @@ -1056,6 +1075,9 @@ extern struct cgpu_info gpus[MAX_GPUDEVICES]; extern double total_secs; extern int mining_threads; extern int total_devices; +extern bool devices_enabled[MAX_DEVICES]; +extern int opt_devs_enabled; +extern bool opt_removedisabled; extern struct cgpu_info **devices; extern int total_pools; extern struct pool **pools; @@ -1081,6 +1103,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,15 +1217,22 @@ struct pool { proxytypes_t rpc_proxytype; char *rpc_proxy; + char *profile; 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; + const char *devices; + const char *intensity; + const char *xintensity; + const char *rawintensity; + const char *lookup_gap; + const char *gpu_engine; + const char *gpu_memclock; + const char *gpu_threads; + const char *gpu_fan; + const char *gpu_powertune; + const char *gpu_vddc; + const char *shaders; + const char *thread_concurrency; + const char *worksize; pthread_mutex_t pool_lock; cglock_t data_lock; @@ -1374,7 +1406,7 @@ extern void kill_work(void); extern void switch_pools(struct pool *selected); extern void discard_work(struct work *work); extern void remove_pool(struct pool *pool); -extern void write_config(FILE *fcfg); +//extern void write_config(FILE *fcfg); extern void zero_bestshare(void); extern void zero_stats(void); extern void default_save_file(char *filename); @@ -1398,6 +1430,11 @@ extern struct work *copy_work_noffset(struct work *base_work, int noffset); #define copy_work(work_in) copy_work_noffset(work_in, 0) extern struct cgpu_info *get_devices(int id); +extern char *set_int_0_to_9999(const char *arg, int *i); +extern char *set_int_1_to_65535(const char *arg, int *i); +extern char *set_int_0_to_10(const char *arg, int *i); +extern char *set_int_1_to_10(const char *arg, int *i); + enum api_data_type { API_ESCAPE, API_STRING, diff --git a/sgminer.c b/sgminer.c index 009d6110..0551824f 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 @@ -70,14 +71,6 @@ char *curly = ":D"; #define VERSION GIT_VERSION #endif -struct strategies strategies[] = { - { "Failover" }, - { "Round Robin" }, - { "Rotate" }, - { "Load Balance" }, - { "Balance" }, -}; - static char packagename[256]; bool opt_work_update; @@ -112,14 +105,15 @@ int opt_hamsi_expand_big = 4; bool opt_restart = true; struct list_head scan_devices; -static bool devices_enabled[MAX_DEVICES]; -static int opt_devs_enabled; +bool devices_enabled[MAX_DEVICES]; +int opt_devs_enabled; static bool opt_display_devs; -static bool opt_removedisabled; +bool opt_removedisabled; int total_devices; static int most_devices; struct cgpu_info **devices; int mining_threads; +static int sgminer_id_count = 0; #ifdef HAVE_CURSES bool use_curses = true; @@ -128,7 +122,7 @@ bool use_curses; #endif static bool opt_submit_stale = true; -static int opt_shares; +int opt_shares; bool opt_fail_only; int opt_fail_switch_delay = 60; static bool opt_fix_protocol; @@ -228,14 +222,19 @@ unsigned int total_go, total_ro; struct pool **pools; static struct pool *currentpool = NULL; +struct strategies strategies[] = { + { "Failover" }, + { "Round Robin" }, + { "Rotate" }, + { "Load Balance" }, + { "Balance" }, +}; + int total_pools, enabled_pools; 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,18 +279,8 @@ 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; + char *opt_stderr_cmd = NULL; static int forkpid; #endif // defined(unix) @@ -304,11 +293,6 @@ struct thread_q *getq; static int total_work; struct work *staged_work = NULL; -struct schedtime { - bool enable; - struct tm tm; -}; - struct schedtime schedstart; struct schedtime schedstop; bool sched_paused; @@ -425,6 +409,8 @@ struct cgpu_info *get_devices(int id) return cgpu; } +void enable_device(struct cgpu_info *cgpu); + static void sharelog(const char*disposition, const struct work*work) { char *target, *hash, *data; @@ -526,6 +512,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; @@ -619,22 +606,22 @@ char *set_int_range(const char *arg, int *i, int min, int max) return NULL; } -static char *set_int_0_to_9999(const char *arg, int *i) +char *set_int_0_to_9999(const char *arg, int *i) { return set_int_range(arg, i, 0, 9999); } -static char *set_int_1_to_65535(const char *arg, int *i) +char *set_int_1_to_65535(const char *arg, int *i) { return set_int_range(arg, i, 1, 65535); } -static char *set_int_0_to_10(const char *arg, int *i) +char *set_int_0_to_10(const char *arg, int *i) { return set_int_range(arg, i, 0, 10); } -static char *set_int_1_to_10(const char *arg, int *i) +char *set_int_1_to_10(const char *arg, int *i) { return set_int_range(arg, i, 1, 10); } @@ -645,18 +632,30 @@ void get_intrange(char *arg, int *val1, int *val2) *val2 = *val1; } -static char *set_devices(char *arg) +char *set_devices(char *arg) { int i, val1 = 0, val2 = 0; char *nextptr; - if (*arg) { - if (*arg == '?') { - opt_display_devs = true; - return NULL; - } - } else - return "Invalid device parameters"; + if (*arg) + { + if (*arg == '?') + { + opt_display_devs = true; + return NULL; + } + //all devices enabled + else if(*arg == '*') + { + applog(LOG_DEBUG, "set_devices(%s)", arg); + opt_devs_enabled = 0; + return NULL; + } + } + else + return "Invalid device parameters"; + + applog(LOG_DEBUG, "set_devices(%s)", arg); nextptr = strtok(arg, ","); if (nextptr == NULL) @@ -776,6 +775,20 @@ static char *set_pool_algorithm(const char *arg) return NULL; } +static char *set_pool_devices(const char *arg) +{ + struct pool *pool = get_current_pool(); + pool->devices = arg; + return NULL; +} + +static char *set_pool_lookup_gap(const char *arg) +{ + struct pool *pool = get_current_pool(); + pool->lookup_gap = arg; + return NULL; +} + static char *set_pool_intensity(const char *arg) { struct pool *pool = get_current_pool(); @@ -832,6 +845,20 @@ static char *set_pool_gpu_fan(const char *arg) pool->gpu_fan = arg; return NULL; } + +static char *set_pool_gpu_powertune(const char *arg) +{ + struct pool *pool = get_current_pool(); + pool->gpu_powertune = arg; + return NULL; +} + +static char *set_pool_gpu_vddc(const char *arg) +{ + struct pool *pool = get_current_pool(); + pool->gpu_vddc = arg; + return NULL; +} #endif static char *set_pool_nfactor(const char *arg) @@ -854,6 +881,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."); @@ -862,6 +899,20 @@ static char *set_poolname_deprecated(char *arg) return NULL; } +static char *set_pool_shaders(const char *arg) +{ + struct pool *pool = get_current_pool(); + pool->shaders = arg; + return NULL; +} + +static char *set_pool_worksize(const char *arg) +{ + struct pool *pool = get_current_pool(); + pool->worksize = arg; + return NULL; +} + static void enable_pool(struct pool *pool) { if (pool->state != POOL_ENABLED) @@ -1198,7 +1249,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,11 +1308,14 @@ 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"), OPT_WITH_ARG("--device|-d", - set_devices, NULL, NULL, + set_default_devices, NULL, NULL, "Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all"), OPT_WITHOUT_ARG("--disable-rejecting", opt_set_bool, &opt_disable_pool, @@ -1291,47 +1345,39 @@ 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, "Set a fixed difference in clock speed between the GPU and memory in auto-gpu mode"), OPT_WITH_ARG("--gpu-powertune", - set_gpu_powertune, NULL, NULL, + set_default_gpu_powertune, NULL, NULL, "Set the GPU powertune percentage - one value for all or separate by commas for per card"), OPT_WITHOUT_ARG("--gpu-reorder", opt_set_bool, &opt_reorder, "Attempt to reorder GPU devices according to PCI Bus ID"), OPT_WITH_ARG("--gpu-vddc", - set_gpu_vddc, NULL, NULL, + set_default_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, + set_default_lookup_gap, NULL, NULL, "Set GPU lookup gap for scrypt mining, comma separated"), OPT_WITH_ARG("--hamsi-expand-big", set_int_1_to_10, opt_show_intval, &opt_hamsi_expand_big, @@ -1345,27 +1391,25 @@ static struct opt_table opt_config_table[] = { opt_set_bool, &opt_morenotices, "Shows work restart and new block notices, hidden by default"), OPT_WITH_ARG("--intensity|-I", - set_intensity, NULL, NULL, + set_default_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 "), overridden --xintensity|-X and --rawintensity."), + OPT_WITH_ARG("--xintensity|-X", +// 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 +1430,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", @@ -1415,21 +1459,131 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--no-submit-stale", opt_set_invbool, &opt_submit_stale, "Don't submit shares if they are detected as stale"), - OPT_WITHOUT_ARG("--no-extranonce-subscribe", + OPT_WITHOUT_ARG("--no-extranonce|--pool-no-extranonce", 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"), + OPT_WITH_ARG("--pool-device", + set_pool_devices, NULL, NULL, + "Select devices to use with pool, one value, range and/or comma separated (e.g. 0-2,4) default: all"), + OPT_WITH_ARG("--pool-lookup-gap", + set_pool_lookup_gap, NULL, NULL, + "Set Pool GPU lookup gap for scrypt mining, comma separated"), +#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-powertune", + set_pool_gpu_powertune, NULL, NULL, + "Set the Pool GPU powertune percentage - 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-vddc", + set_pool_gpu_vddc, NULL, NULL, + "Set the Pool GPU voltage in Volts - one value for all or separate by commas for per card"), +#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-shaders", + set_pool_shaders, NULL, NULL, + "Pool GPU shaders per card for tuning scrypt, comma separated"), + OPT_WITH_ARG("--pool-thread-concurrency", + set_pool_thread_concurrency, NULL, NULL, + "Set thread concurrency for pool"), + OPT_WITH_ARG("--pool-worksize", + set_pool_worksize, NULL, NULL, + "Override detected optimal worksize for pool - one value or comma separated list"), + 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"), + OPT_WITH_ARG("--profile-device", + set_profile_devices, NULL, NULL, + "Select devices to use with profile, one value, range and/or comma separated (e.g. 0-2,4) default: all"), + OPT_WITH_ARG("--profile-lookup-gap", + set_profile_lookup_gap, NULL, NULL, + "Set Profile GPU lookup gap for scrypt mining, comma separated"), +#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-powertune", + set_profile_gpu_powertune, NULL, NULL, + "Set the Profile GPU powertune percentage - 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"), + OPT_WITH_ARG("--profile-gpu-vddc", + set_profile_gpu_vddc, NULL, NULL, + "Set the Profile GPU voltage in Volts - one value for all or separate by commas for per card"), +#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-shaders", + set_profile_shaders, NULL, NULL, + "Profile GPU shaders per card for tuning scrypt, comma separated"), + OPT_WITH_ARG("--profile-thread-concurrency", + set_profile_thread_concurrency, NULL, NULL, + "Set thread concurrency for profile"), + OPT_WITH_ARG("--profile-worksize", + set_profile_worksize, NULL, NULL, + "Override detected optimal worksize for profile - one value or comma separated list"), + 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 +1593,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", @@ -1470,7 +1624,7 @@ static struct opt_table opt_config_table[] = { set_schedtime, NULL, &schedstop, "Set a time of day in HH:MM to stop mining (will quit without a start time)"), OPT_WITH_ARG("--shaders", - set_shaders, NULL, NULL, + set_default_shaders, NULL, NULL, "GPU shaders per card for tuning scrypt, comma separated"), OPT_WITH_ARG("--sharelog", set_sharelog, NULL, NULL, @@ -1484,7 +1638,7 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--show-coindiff", opt_set_bool, &opt_show_coindiff, "Show coin difficulty rather than hash value of a share"), - OPT_WITH_ARG("--state", + OPT_WITH_ARG("--state|--pool-state", set_pool_state, NULL, NULL, "Specify pool state at startup (default: enabled)"), #ifdef HAVE_SYSLOG_H @@ -1525,21 +1679,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", @@ -1551,9 +1697,9 @@ static struct opt_table opt_config_table[] = { opt_set_bool, &opt_log_output, "Log verbose output to stderr as well as status output"), OPT_WITH_ARG("--worksize|-w", - set_worksize, NULL, NULL, + set_default_worksize, NULL, NULL, "Override detected optimal worksize - one value or comma separated list"), - OPT_WITH_ARG("--userpass|-O", + OPT_WITH_ARG("--userpass|--pool-userpass|-O", set_userpass, NULL, NULL, "Username:Password pair for bitcoin JSON-RPC server"), OPT_WITHOUT_ARG("--worktime", @@ -1561,153 +1707,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) @@ -4332,285 +4341,6 @@ static void display_pool_summary(struct pool *pool) } #endif -/* add a mutex if this needs to be thread safe in the future */ -static struct JE { - char *buf; - struct JE *next; -} *jedata = NULL; - -static void json_escape_free() -{ - struct JE *jeptr = jedata; - struct JE *jenext; - - jedata = NULL; - - while (jeptr) { - jenext = jeptr->next; - free(jeptr->buf); - free(jeptr); - jeptr = jenext; - } -} - -static char *json_escape(char *str) -{ - struct JE *jeptr; - char *buf, *ptr; - - /* 2x is the max, may as well just allocate that */ - ptr = buf = (char *)malloc(strlen(str) * 2 + 1); - - jeptr = (struct JE *)malloc(sizeof(*jeptr)); - - jeptr->buf = buf; - jeptr->next = jedata; - jedata = jeptr; - - while (*str) { - if (*str == '\\' || *str == '"') - *(ptr++) = '\\'; - - *(ptr++) = *(str++); - } - - *ptr = '\0'; - - return buf; -} - -void write_config(FILE *fcfg) -{ - int i; - - /* Write pool values */ - fputs("{\n\"pools\" : [", fcfg); - for(i = 0; i < total_pools; i++) { - struct pool *pool = pools[i]; - - fprintf(fcfg, "%s", i > 0 ? "," : ""); - if (pool->quota != 1) { - fprintf(fcfg, "\n\t{\n\t\t\"quota\" : \"%s%s%s%d;%s\"", - pool->rpc_proxy ? json_escape((char *)proxytype(pool->rpc_proxytype)) : "", - pool->rpc_proxy ? json_escape(pool->rpc_proxy) : "", - pool->rpc_proxy ? "|" : "", - pool->quota, - json_escape(pool->rpc_url)); - } else { - fprintf(fcfg, "\n\t{\n\t\t\"url\" : \"%s%s%s%s\"", - pool->rpc_proxy ? json_escape((char *)proxytype(pool->rpc_proxytype)) : "", - pool->rpc_proxy ? json_escape(pool->rpc_proxy) : "", - pool->rpc_proxy ? "|" : "", - json_escape(pool->rpc_url)); - } - if (!pool->extranonce_subscribe) - fprintf(fcfg, ",\n\t\t\"no-extranonce-subscribe\" : true"); - fprintf(fcfg, ",\n\t\t\"user\" : \"%s\"", json_escape(pool->rpc_user)); - fprintf(fcfg, ",\n\t\t\"pass\" : \"%s\"", json_escape(pool->rpc_pass)); - /* Using get_pool_name() here is unsafe if opt_incognito is true. */ - if (strcmp(pool->name, "") != 0) { - fprintf(fcfg, ",\n\t\t\"name\" : \"%s\"", json_escape(pool->name)); - } - if (strcmp(pool->description, "") != 0) { - fprintf(fcfg, ",\n\t\t\"description\" : \"%s\"", json_escape(pool->description)); - } - if (!cmp_algorithm(&pool->algorithm, &opt_algorithm)) { - fprintf(fcfg, ",\n\t\t\"algorithm\" : \"%s\"", json_escape(pool->algorithm.name)); - } - if (pool->prio != i) { - fprintf(fcfg, ",\n\t\t\"priority\" : \"%d\"", pool->prio); - } - fprintf(fcfg, "\n\t}"); - } - fputs("\n]\n", fcfg); - - /* Write only if there are usable GPUs */ - if (nDevs) { - fputs(",\n\"intensity\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - if (gpus[i].dynamic) - fprintf(fcfg, "%sd", i > 0 ? "," : ""); - else - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].intensity); - - fputs("\",\n\"xintensity\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].xintensity); - - fputs("\",\n\"rawintensity\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].rawintensity); - - /* All current kernels only support vector=1 */ - /* fputs("\",\n\"vectors\" : \"", fcfg); */ - /* for(i = 0; i < nDevs; i++) */ - /* fprintf(fcfg, "%s%d", i > 0 ? "," : "", */ - /* gpus[i].vwidth); */ - - fputs("\",\n\"worksize\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].work_size); - - fputs("\",\n\"algorithm\" : \"", fcfg); - for(i = 0; i < nDevs; i++) { - fprintf(fcfg, "%s", i > 0 ? "," : ""); - fprintf(fcfg, "%s", gpus[i].algorithm.name); - } - - fputs("\",\n\"lookup-gap\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].opt_lg); - - fputs("\",\n\"thread-concurrency\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].opt_tc); - - fputs("\",\n\"shaders\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].shaders); - - fputs("\",\n\"gpu-threads\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", - (int)gpus[i].threads); - -#ifdef HAVE_ADL - fputs("\",\n\"gpu-engine\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d-%d", i > 0 ? "," : "", gpus[i].min_engine, gpus[i].gpu_engine); - - fputs("\",\n\"gpu-fan\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d-%d", i > 0 ? "," : "", gpus[i].min_fan, gpus[i].gpu_fan); - - fputs("\",\n\"gpu-memclock\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].gpu_memclock); - - fputs("\",\n\"gpu-memdiff\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].gpu_memdiff); - - fputs("\",\n\"gpu-powertune\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].gpu_powertune); - - fputs("\",\n\"gpu-vddc\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%1.3f", i > 0 ? "," : "", gpus[i].gpu_vddc); - - fputs("\",\n\"temp-cutoff\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].cutofftemp); - - fputs("\",\n\"temp-overheat\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].adl.overtemp); - - fputs("\",\n\"temp-target\" : \"", fcfg); - for(i = 0; i < nDevs; i++) - fprintf(fcfg, "%s%d", i > 0 ? "," : "", gpus[i].adl.targettemp); -#endif - - fputs("\"", fcfg); - } -#ifdef HAVE_ADL - if (opt_reorder) - fprintf(fcfg, ",\n\"gpu-reorder\" : true"); -#endif - - /* Simple bool and int options */ - struct opt_table *opt; - for (opt = opt_config_table; opt->type != OPT_END; opt++) { - char *p, *name = strdup(opt->names); - for (p = strtok(name, "|"); p; p = strtok(NULL, "|")) { - if (p[1] != '-') - continue; - if (opt->type & OPT_NOARG && - ((void *)opt->cb == (void *)opt_set_bool || (void *)opt->cb == (void *)opt_set_invbool) && - (*(bool *)opt->u.arg == ((void *)opt->cb == (void *)opt_set_bool))) - fprintf(fcfg, ",\n\"%s\" : true", p+2); - - if (opt->type & OPT_HASARG && - ((void *)opt->cb_arg == (void *)set_int_0_to_9999 || - (void *)opt->cb_arg == (void *)set_int_1_to_65535 || - (void *)opt->cb_arg == (void *)set_int_0_to_10 || - (void *)opt->cb_arg == (void *)set_int_1_to_10) && opt->desc != opt_hidden) - fprintf(fcfg, ",\n\"%s\" : \"%d\"", p+2, *(int *)opt->u.arg); - } - } - - /* Special case options */ - fprintf(fcfg, ",\n\"shares\" : \"%d\"", opt_shares); - if (pool_strategy == POOL_BALANCE) - fputs(",\n\"balance\" : true", fcfg); - if (pool_strategy == POOL_LOADBALANCE) - fputs(",\n\"load-balance\" : true", fcfg); - if (pool_strategy == POOL_ROUNDROBIN) - fputs(",\n\"round-robin\" : true", fcfg); - if (pool_strategy == POOL_ROTATE) - fprintf(fcfg, ",\n\"rotate\" : \"%d\"", opt_rotate_period); -#if defined(unix) || defined(__APPLE__) - if (opt_stderr_cmd && *opt_stderr_cmd) - fprintf(fcfg, ",\n\"monitor\" : \"%s\"", json_escape(opt_stderr_cmd)); -#endif // defined(unix) - if (opt_kernel_path && *opt_kernel_path) { - char *kpath = strdup(opt_kernel_path); - if (kpath[strlen(kpath)-1] == '/') - kpath[strlen(kpath)-1] = 0; - fprintf(fcfg, ",\n\"kernel-path\" : \"%s\"", json_escape(kpath)); - } - if (schedstart.enable) - fprintf(fcfg, ",\n\"sched-time\" : \"%d:%d\"", schedstart.tm.tm_hour, schedstart.tm.tm_min); - if (schedstop.enable) - fprintf(fcfg, ",\n\"stop-time\" : \"%d:%d\"", schedstop.tm.tm_hour, schedstop.tm.tm_min); - if (opt_socks_proxy && *opt_socks_proxy) - fprintf(fcfg, ",\n\"socks-proxy\" : \"%s\"", json_escape(opt_socks_proxy)); - if (opt_devs_enabled) { - fprintf(fcfg, ",\n\"device\" : \""); - bool extra_devs = false; - - for (i = 0; i < MAX_DEVICES; i++) { - if (devices_enabled[i]) { - int startd = i; - - if (extra_devs) - fprintf(fcfg, ","); - while (i < MAX_DEVICES && devices_enabled[i + 1]) - ++i; - fprintf(fcfg, "%d", startd); - if (i > startd) - fprintf(fcfg, "-%d", i); - } - } - fprintf(fcfg, "\""); - } - if (opt_removedisabled) - fprintf(fcfg, ",\n\"remove-disabled\" : true"); - if (strcmp(opt_algorithm.name, "scrypt") != 0) - fprintf(fcfg, ",\n\"algorithm\" : \"%s\"", json_escape(opt_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) - fprintf(fcfg, ",\n\"api-mcast-addr\" : \"%s\"", json_escape(opt_api_mcast_addr)); - if (strcmp(opt_api_mcast_code, API_MCAST_CODE) != 0) - fprintf(fcfg, ",\n\"api-mcast-code\" : \"%s\"", json_escape(opt_api_mcast_code)); - if (*opt_api_mcast_des) - fprintf(fcfg, ",\n\"api-mcast-des\" : \"%s\"", json_escape(opt_api_mcast_des)); - if (strcmp(opt_api_description, PACKAGE_STRING) != 0) - fprintf(fcfg, ",\n\"api-description\" : \"%s\"", json_escape(opt_api_description)); - if (opt_api_groups) - fprintf(fcfg, ",\n\"api-groups\" : \"%s\"", json_escape(opt_api_groups)); - - fputs("\n}\n", fcfg); - - json_escape_free(); -} - void zero_bestshare(void) { int i; @@ -5044,7 +4774,6 @@ retry: opt_expiry = selected; goto retry; } else if (!strncasecmp(&input, "w", 1)) { - FILE *fcfg; char *str, filename[PATH_MAX], prompt[PATH_MAX + 50]; default_save_file(filename); @@ -5064,13 +4793,9 @@ retry: } else free(str); - fcfg = fopen(filename, "w"); - if (!fcfg) { - wlogprint("Cannot open or create file\n"); - goto retry; - } - write_config(fcfg); - fclose(fcfg); + + write_config(filename); + goto retry; } else if (!strncasecmp(&input, "r", 1)) { @@ -6167,62 +5892,144 @@ static void *restart_mining_threads_thread(void *userdata); 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 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); mutex_lock(&algo_switch_lock); - if (cmp_algorithm(&work->pool->algorithm, &mythr->cgpu->algorithm) && (algo_switch_n == 0)) { + 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; } 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 + active_threads = 0; + for(i = 0; i < mining_threads; i++) + { + struct thr_info *thr = mining_thr[i]; + + if(thr->cgpu->deven != DEV_DISABLED) + active_threads ++; + } // If all threads are waiting now - if (algo_switch_n >= mining_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) { - for (i = 0; i < mining_threads; i++) { + 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(); - // Apply other pool-specific settings - // TODO: when config parser is improved, add else statements and set - // to default intensity - if (work->pool->intensity) + + // 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); + + //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); + + //xintensity + 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); + + //raw intensity + if (!empty_string(work->pool->rawintensity)) set_rawintensity(work->pool->rawintensity); - if (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.rawintensity)) + set_rawintensity(default_profile.rawintensity); + + //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); + + //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 + //GPU clock + 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) { + else if(!empty_string(default_profile.gpu_engine)) + set_gpu_engine(default_profile.gpu_engine); + + //GPU memory clock + 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) { + else if(!empty_string(default_profile.gpu_memclock)) + set_gpu_memclock(default_profile.gpu_memclock); + + //GPU fans + 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 + else if(!empty_string(default_profile.gpu_fan)) + set_gpu_fan(default_profile.gpu_fan); + + //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); + + //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); + + //apply gpu settings + for (i = 0; i < nDevs; i++) + { + set_engineclock(i, gpus[i].min_engine); + set_memoryclock(i, gpus[i].gpu_memclock); + set_fanspeed(i, gpus[i].gpu_fan); + set_powertune(i, gpus[i].gpu_powertune); + set_vddc(i, gpus[i].gpu_vddc); + } +#endif + // Change algorithm for each thread (thread_prepare calls initCl) - for (i = 0; i < mining_threads; i++) { + for (i = 0; i < start_threads; i++) + { struct thr_info *thr = mining_thr[i]; thr->cgpu->algorithm = work->pool->algorithm; if (soft_restart) { @@ -6234,22 +6041,66 @@ static void get_work_prepare_thread(struct thr_info *mythr, struct work *work) 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 (when gpu_threads is changed) - if (!soft_restart) { + 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) + { + for (i = 0; i < MAX_DEVICES; i++) + { + //device should be enabled + if(devices_enabled[i] && i < total_devices) + { + applog(LOG_DEBUG, "Enabling device %d", i); + enable_device(devices[i]); + } + else if(i < total_devices) + { + applog(LOG_DEBUG, "Disabling device %d", i); + //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]); + } + + //devices reset - assign gpu-threads as needed + unsigned int n_threads = 0; pthread_t restart_thr; #ifdef HAVE_ADL - set_gpu_threads(work->pool->gpu_threads); + 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; + 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); @@ -7354,7 +7205,7 @@ static void *test_pool_thread(void *arg) /* Always returns true that the pool details were added unless we are not * live, implying this is the only pool being added, so if no pools are * active it returns false. */ -bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *algo) +bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass, char *name, char *desc, char *profile, char *algo) { size_t siz; @@ -7365,7 +7216,20 @@ bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char pool->rpc_pass = pass; pool->name = name; pool->description = desc; - set_algorithm(&pool->algorithm, algo); + pool->profile = profile; + + //if a profile was supplied, apply pool properties from profile + if(!empty_string(profile)) + apply_pool_profile(pool); //remove profile if was invalid + + //if profile is empty, assign algorithm or default algorithm + if(empty_string(pool->profile)) + { + if(!empty_string(algo)) + set_algorithm(&pool->algorithm, algo); + else + set_algorithm(&pool->algorithm, default_profile.algorithm.name); + } siz = strlen(pool->rpc_user) + strlen(pool->rpc_pass) + 2; pool->rpc_userpass = (char *)malloc(siz); @@ -7390,7 +7254,7 @@ bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char static bool input_pool(bool live) { char *url = NULL, *user = NULL, *pass = NULL; - char *name = NULL, *desc = NULL, *algo = NULL; + char *name = NULL, *desc = NULL, *profile = NULL, *algo = NULL; struct pool *pool; bool ret = false; @@ -7408,8 +7272,10 @@ static bool input_pool(bool live) if (strcmp(name, "-1") == 0) strcpy(name, ""); desc = curses_input("Description (optional)"); if (strcmp(desc, "-1") == 0) strcpy(desc, ""); + algo = curses_input("Profile (optional)"); + if (strcmp(profile, "-1") == 0) profile[0] = '\0'; algo = curses_input("Algorithm (optional)"); - if (strcmp(algo, "-1") == 0) strcpy(algo, opt_algorithm.name); + if (strcmp(algo, "-1") == 0) algo[0] = '\0'; pool = add_pool(); @@ -7427,7 +7293,7 @@ static bool input_pool(bool live) } ret = add_pool_details(pool, live, url, user, pass, - name, desc, algo); + name, desc, profile, algo); out: immedok(logwin, false); @@ -7548,8 +7414,6 @@ void enable_curses(void) { } #endif -static int sgminer_id_count = 0; - /* Various noop functions for drivers that don't support or need their * variants. */ static void noop_reinit_device(struct cgpu_info __maybe_unused *cgpu) @@ -7729,16 +7593,18 @@ static void restart_mining_threads(unsigned int new_n_threads) if (mining_thr) { rd_lock(&mining_thr_lock); for (i = 0; i < mining_threads; i++) { - mining_thr[i]->cgpu->shutdown = true; + 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); - for (i = 0; i < mining_threads; i++) { - thr = mining_thr[i]; - thr->cgpu->drv->thread_shutdown(thr); - thr->cgpu->shutdown = false; + for (i = 0; i < mining_threads; i++) + { + thr = mining_thr[i]; + thr->cgpu->drv->thread_shutdown(thr); + thr->cgpu->shutdown = false; } rd_unlock(&mining_thr_lock); } @@ -7952,6 +7818,25 @@ 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(); + + /*FILE *fcfg = fopen("testconf_test.conf", "w"); + if (!fcfg) { + wlogprint("Cannot open or create file\n"); + quit(1,""); + }*/ + //write_config("./testconf_test.conf"); + //fclose(fcfg); + //quit(1,"file saved."); + + if (opt_benchmark) { struct pool *pool;