diff --git a/NEWS.md b/NEWS.md index c24343ba..576836f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,8 @@ * Multiple `--name` parsing should now work as expected (by _troky_). * `--coin` configuration parameter to specify a freeform pool description (by _troky_). +* Forward-port changes from `ckolivas/cgminer` slightly after 3.12.3 + (up to 133252175b90159d18151b004bf767d5a43812ea). ## Version 4.1.153 - 14th March 2014 diff --git a/README.md b/README.md index 4c68fa36..76ba656f 100644 --- a/README.md +++ b/README.md @@ -460,3 +460,30 @@ For example (this is wrapped, but it's all on one line for real): 000000004a4366808f81d44f26df3d69d7dc4b3473385930462d9ab707b50498 f681634a4f1f63d01a0cd43fb338000000000080000000000000000000000000 0000000000000000000000000000000000000000000000000000000080020000 + + +## Benchmark + +The --benchmark option hashes a single fixed work item over and over and does +not submit shares to any pools. + +The --benchfile option hashes the work given in the file supplied. +The format of the work file is: +version,merkleroot,prevhash,diffbits,noncetime +Any empty line or any line starting with '#' or '/' is ignored. +When it reaches the end of the file it continues back at the top. + +The format of the data items matches the byte ordering and format of the +the bitcoind getblock RPC output. + +An example file containing bitcoin block #1 would be: + +# Block 1 +1,0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098,00000000001 +9d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f,1d00ffff,1231469665 + +However, the work data should be one line without the linebreak in the middle + +If you use --benchfile , then --benchfile-display will output a log line, +for each nonce found, showing the nonce value in decimal and hex and the work +used to find it in hex. diff --git a/api.c b/api.c index 4caf65c4..356fa6b7 100644 --- a/api.c +++ b/api.c @@ -3738,7 +3738,7 @@ void api(int api_thr_id) json_t *json_config = NULL; json_t *json_val; bool isjson; - bool did, isjoin, firstjoin; + bool did, isjoin = false, firstjoin; int i; SOCKETTYPE *apisock; diff --git a/autogen.sh b/autogen.sh index 79bcea88..8b48add3 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,3 +4,8 @@ bs_dir="$(dirname $(readlink -f $0))" #Some versions of libtoolize don't like there being no ltmain.sh file already touch "${bs_dir}"/ltmain.sh autoreconf -fi "${bs_dir}" + +if test -n "$1" && test -z "$NOCONFIGURE" ; then + echo 'Configuring...' + "$bs_dir"/configure "$@" +fi diff --git a/doc/API b/doc/API index c39f6385..ae46ab1c 100644 --- a/doc/API +++ b/doc/API @@ -1270,20 +1270,49 @@ However, if $readonly is true, it will not display them --------- +Default: + $rigport = 4028; + +Default port to use if any $rigs entries don't specify the port number + +--------- + Default: $rigs = array('127.0.0.1:4028'); -Set $rigs to an array of your sgminer rigs that are running - format: 'IP:Port' or 'Host:Port' or 'Host:Port:Name' +Set $rigs to an array of your rigs that are running + format: 'IP' or 'Host' or 'IP:Port' or 'Host:Port' or 'Host:Port:Name' If you only have one rig, it will just show the detail of that rig If you have more than one rig it will show a summary of all the rigs with buttons to show the details of each rig - the button contents will be 'Name' rather than rig number, if you specify 'Name' +If Port is missing or blank, it will try $rigport e.g. $rigs = array('127.0.0.1:4028','myrig.com:4028:Sugoi'); --------- +Default: + $rignames = false; + +Set $rignames to false to not affect the display. +Set $rignames to one of 'ip' or 'ipx' to alter the name displayed +if the rig doesn't have a 'name' in $rigs +Currently: + 'ip' means use the 4th byte of the rig IP address as an integer + 'ipx' means use the 4th byte of the rig IP address as 2 hex bytes + +--------- + +Default: + $rigbuttons = true; + +Set $rigbuttons to false to display a link rather than a button on +the left of any summary table with rig buttons, in order to reduce +the height of the table cells + +--------- + Default: $mcast = false; diff --git a/logging.c b/logging.c index a511786b..6f57f54b 100644 --- a/logging.c +++ b/logging.c @@ -124,3 +124,23 @@ void _applog(int prio, const char *str, bool force) my_log_curses(prio, datetime, str, force); } } + +void _simplelog(int prio, const char *str, bool force) +{ +#ifdef HAVE_SYSLOG_H + if (use_syslog) { + syslog(prio, "%s", str); + } +#else + if (0) {} +#endif + else { + /* Only output to stderr if it's not going to the screen as well */ + if (!isatty(fileno((FILE *)stderr))) { + fprintf(stderr, "%s\n", str); /* atomic write to stderr */ + fflush(stderr); + } + + my_log_curses(prio, "", str, force); + } +} diff --git a/logging.h b/logging.h index 95a8fa47..431fa9a1 100644 --- a/logging.h +++ b/logging.h @@ -32,6 +32,7 @@ extern int opt_log_show_date; void applog(int prio, const char* fmt, ...); extern void _applog(int prio, const char *str, bool force); +extern void _simplelog(int prio, const char *str, bool force); #define IN_FMT_FFL " in %s %s():%d" diff --git a/miner.h b/miner.h index 9761ff23..86e70772 100644 --- a/miner.h +++ b/miner.h @@ -161,6 +161,7 @@ static inline int fsync (int fd) #ifndef htobe32 # if __BYTE_ORDER == __LITTLE_ENDIAN # define htole16(x) (x) +# define le16toh(x) (x) # define htole32(x) (x) # define htole64(x) (x) # define le32toh(x) (x) @@ -171,6 +172,7 @@ static inline int fsync (int fd) # define htobe64(x) bswap_64(x) # elif __BYTE_ORDER == __BIG_ENDIAN # define htole16(x) bswap_16(x) +# define le16toh(x) bswap_16(x) # define htole32(x) bswap_32(x) # define le32toh(x) bswap_32(x) # define le64toh(x) bswap_64(x) diff --git a/miner.php b/miner.php index 0bc21ec1..12db6464 100644 --- a/miner.php +++ b/miner.php @@ -1,7 +1,8 @@ "; + if ($usebuttons === true) + return ""; + else + return "$rigname"; } # -function rigbutton($rig, $rigname, $when, $row) +function rigbutton($rig, $rigname, $when, $row, $usebuttons) { list($value, $class) = fmt('BUTTON', 'Rig', '', $when, $row); if ($rig === '') $ri = ' '; else - $ri = riginput($rig, $rigname); + $ri = riginput($rig, $rigname, $usebuttons); return "$ri"; } # function showrigs($anss, $headname, $rigname) { + global $rigbuttons; + $dthead = array($headname => 1, 'STATUS' => 1, 'Description' => 1, 'When' => 1, 'API' => 1, 'sgminer' => 1); showhead('', $dthead); @@ -1591,7 +1647,7 @@ function showrigs($anss, $headname, $rigname) foreach ($dthead as $name => $x) { if ($item == 'STATUS' && $name == $headname) - echo rigbutton($rig, $rigname.$rig, $when, null); + echo rigbutton($rig, $rigname.$rig, $when, null, $rigbuttons); else { if (isset($row[$name])) @@ -1610,7 +1666,7 @@ function showrigs($anss, $headname, $rigname) function doforeach($cmd, $des, $sum, $head, $datetime) { global $miner, $port; - global $error, $readonly, $notify, $rigs; + global $error, $readonly, $notify, $rigs, $rigbuttons; global $warnfont, $warnoff, $dfmt; global $rigerror; @@ -1629,10 +1685,13 @@ function doforeach($cmd, $des, $sum, $head, $datetime) continue; $parts = explode(':', $rig, 3); - if (count($parts) >= 2) + if (count($parts) >= 1) { $miner = $parts[0]; - $port = $parts[1]; + if (count($parts) >= 2) + $port = $parts[1]; + else + $port = ''; if (count($parts) > 2) $name = $parts[2]; @@ -1747,7 +1806,7 @@ function doforeach($cmd, $des, $sum, $head, $datetime) echo "Total:"; } else - echo rigbutton($rig, "Rig $rig", $when, $row); + echo rigbutton($rig, "Rig $rig", $when, $row, $rigbuttons); } else { @@ -1780,7 +1839,7 @@ function refreshbuttons() # function pagebuttons($rig, $pg) { - global $readonly, $rigs, $userlist, $ses; + global $readonly, $rigs, $rigbuttons, $userlist, $ses; global $allowcustompages, $customsummarypages; if ($rig === null) @@ -1819,10 +1878,12 @@ function pagebuttons($rig, $pg) if ($userlist === null || isset($_SESSION[$ses])) { if ($prev !== null) - echo riginput($prev, 'Prev').' '; + echo riginput($prev, 'Prev', true).' '; + echo " "; + if ($next !== null) - echo riginput($next, 'Next').' '; + echo riginput($next, 'Next', true).' '; echo ' '; if (count($rigs) > 1) echo " "; @@ -2184,6 +2245,8 @@ function secmatch($section, $field) # function customset($showfields, $sum, $section, $rig, $isbutton, $result, $total) { + global $rigbuttons; + foreach ($result as $sec => $row) { $secname = preg_replace('/\d/', '', $sec); @@ -2200,7 +2263,7 @@ function customset($showfields, $sum, $section, $rig, $isbutton, $result, $total if ($isbutton) - echo rigbutton($rig, $rig, $when, $row); + echo rigbutton($rig, $rig, $when, $row, $rigbuttons); else { list($ignore, $class) = fmt('total', '', '', $when, $row); @@ -2535,10 +2598,13 @@ function processcustompage($pagename, $sections, $sum, $ext, $namemap) foreach ($rigs as $num => $rig) { $parts = explode(':', $rig, 3); - if (count($parts) >= 2) + if (count($parts) >= 1) { $miner = $parts[0]; - $port = $parts[1]; + if (count($parts) >= 2) + $port = $parts[1]; + else + $port = ''; if (count($parts) > 2) $name = $parts[2]; @@ -2896,10 +2962,13 @@ function display() if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs)) { $parts = explode(':', $rigs[$rig], 3); - if (count($parts) >= 2) + if (count($parts) >= 1) { $miner = $parts[0]; - $port = $parts[1]; + if (count($parts) >= 2) + $port = $parts[1]; + else + $port = ''; if ($readonly !== true) $preprocess = $arg; @@ -2948,10 +3017,13 @@ function display() if (count($rigs) == 1) { $parts = explode(':', $rigs[0], 3); - if (count($parts) >= 2) + if (count($parts) >= 1) { $miner = $parts[0]; - $port = $parts[1]; + if (count($parts) >= 2) + $port = $parts[1]; + else + $port = ''; htmlhead($mcerr, true, 0); doOne(0, $preprocess); @@ -2968,10 +3040,13 @@ function display() if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs)) { $parts = explode(':', $rigs[$rig], 3); - if (count($parts) >= 2) + if (count($parts) >= 1) { $miner = $parts[0]; - $port = $parts[1]; + if (count($parts) >= 2) + $port = $parts[1]; + else + $port = ''; htmlhead($mcerr, true, 0); doOne($rig, $preprocess); diff --git a/sgminer.c b/sgminer.c index 3b053e93..83fcea0a 100644 --- a/sgminer.c +++ b/sgminer.c @@ -82,6 +82,29 @@ static char packagename[256]; bool opt_work_update; bool opt_protocol; +static struct benchfile_layout { + int length; + char *name; +} benchfile_data[] = { + { 1, "Version" }, + { 64, "MerkleRoot" }, + { 64, "PrevHash" }, + { 8, "DifficultyBits" }, + { 10, "NonceTime" } // 10 digits +}; +enum benchwork { + BENCHWORK_VERSION = 0, + BENCHWORK_MERKLEROOT, + BENCHWORK_PREVHASH, + BENCHWORK_DIFFBITS, + BENCHWORK_NONCETIME, + BENCHWORK_COUNT +}; +static char *opt_benchfile; +static bool opt_benchfile_display; +static FILE *benchfile_in; +static int benchfile_line; +static int benchfile_work; static bool opt_benchmark; bool have_longpoll; bool want_per_device_stats; @@ -1141,6 +1164,12 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--balance", set_balance, &pool_strategy, "Change multipool strategy from failover to even share balance"), + OPT_WITH_ARG("--benchfile", + opt_set_charp, NULL, &opt_benchfile, + "Run cgminer in benchmark mode using a work file - produces no shares"), + OPT_WITHOUT_ARG("--benchfile-display", + opt_set_bool, &opt_benchfile_display, + "Display each benchfile nonce found"), OPT_WITHOUT_ARG("--benchmark", opt_set_bool, &opt_benchmark, "Run sgminer in benchmark mode - produces no shares"), @@ -3069,6 +3098,154 @@ static void get_benchmark_work(struct work *work) calc_diff(work, 0); } +static void benchfile_dspwork(struct work *work, uint32_t nonce) +{ + char buf[1024]; + uint32_t dn; + int i; + + dn = 0; + for (i = 0; i < 4; i++) { + dn *= 0x100; + dn += nonce & 0xff; + nonce /= 0x100; + } + + if ((sizeof(work->data) * 2 + 1) > sizeof(buf)) + quithere(1, "BENCHFILE Invalid buf size"); + + __bin2hex(buf, work->data, sizeof(work->data)); + + applog(LOG_ERR, "BENCHFILE nonce %u=0x%08x for work=%s", + (unsigned int)dn, (unsigned int)dn, buf); + +} + +static bool benchfile_get_work(struct work *work) +{ + char buf[1024]; + char item[1024]; + bool got = false; + + if (!benchfile_in) { + if (opt_benchfile) + benchfile_in = fopen(opt_benchfile, "r"); + else + quit(1, "BENCHFILE Invalid benchfile NULL"); + + if (!benchfile_in) + quit(1, "BENCHFILE Failed to open benchfile '%s'", opt_benchfile); + + benchfile_line = 0; + + if (!fgets(buf, 1024, benchfile_in)) + quit(1, "BENCHFILE Failed to read benchfile '%s'", opt_benchfile); + + got = true; + benchfile_work = 0; + } + + if (!got) { + if (!fgets(buf, 1024, benchfile_in)) { + if (benchfile_work == 0) + quit(1, "BENCHFILE No work in benchfile '%s'", opt_benchfile); + fclose(benchfile_in); + benchfile_in = NULL; + return benchfile_get_work(work); + } + } + + do { + benchfile_line++; + + // Empty lines and lines starting with '#' or '/' are ignored + if (*buf != '\0' && *buf != '#' && *buf != '/') { + char *commas[BENCHWORK_COUNT]; + int i, j, len; + long nonce_time; + + commas[0] = buf; + for (i = 1; i < BENCHWORK_COUNT; i++) { + commas[i] = strchr(commas[i-1], ','); + if (!commas[i]) { + quit(1, "BENCHFILE Invalid input file line %d" + " - field count is %d but should be %d", + benchfile_line, i, BENCHWORK_COUNT); + } + len = commas[i] - commas[i-1]; + if (benchfile_data[i-1].length && + (len != benchfile_data[i-1].length)) { + quit(1, "BENCHFILE Invalid input file line %d " + "field %d (%s) length is %d but should be %d", + benchfile_line, i, + benchfile_data[i-1].name, + len, benchfile_data[i-1].length); + } + + *(commas[i]++) = '\0'; + } + + // NonceTime may have LF's etc + len = strlen(commas[BENCHWORK_NONCETIME]); + if (len < benchfile_data[BENCHWORK_NONCETIME].length) { + quit(1, "BENCHFILE Invalid input file line %d field %d" + " (%s) length is %d but should be least %d", + benchfile_line, BENCHWORK_NONCETIME+1, + benchfile_data[BENCHWORK_NONCETIME].name, len, + benchfile_data[BENCHWORK_NONCETIME].length); + } + + sprintf(item, "0000000%c", commas[BENCHWORK_VERSION][0]); + + j = strlen(item); + for (i = benchfile_data[BENCHWORK_PREVHASH].length-8; i >= 0; i -= 8) { + sprintf(&(item[j]), "%.8s", &commas[BENCHWORK_PREVHASH][i]); + j += 8; + } + + for (i = benchfile_data[BENCHWORK_MERKLEROOT].length-8; i >= 0; i -= 8) { + sprintf(&(item[j]), "%.8s", &commas[BENCHWORK_MERKLEROOT][i]); + j += 8; + } + + nonce_time = atol(commas[BENCHWORK_NONCETIME]); + + sprintf(&(item[j]), "%08lx", nonce_time); + j += 8; + + strcpy(&(item[j]), commas[BENCHWORK_DIFFBITS]); + j += benchfile_data[BENCHWORK_DIFFBITS].length; + + memset(work, 0, sizeof(*work)); + + hex2bin(work->data, item, j >> 1); + + calc_midstate(work); + + benchfile_work++; + + return true; + } + } while (fgets(buf, 1024, benchfile_in)); + + if (benchfile_work == 0) + quit(1, "BENCHFILE No work in benchfile '%s'", opt_benchfile); + fclose(benchfile_in); + benchfile_in = NULL; + return benchfile_get_work(work); +} + +static void get_benchfile_work(struct work *work) +{ + benchfile_get_work(work); + work->mandatory = true; + work->pool = pools[0]; + cgtime(&work->tv_getwork); + copy_time(&work->tv_getwork_reply, &work->tv_getwork); + work->getwork_mode = GETWORK_MODE_BENCHMARK; + calc_diff(work, 0); +} + #ifdef HAVE_CURSES static void disable_curses_windows(void) { @@ -3577,7 +3754,7 @@ static bool stale_work(struct work *work, bool share) struct pool *pool; int getwork_delay; - if (opt_benchmark) + if (opt_benchmark || opt_benchfile) return false; if (work->work_block != work_block) { @@ -6159,6 +6336,9 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce) return false; } + if (opt_benchfile && opt_benchfile_display) + benchfile_dspwork(work, nonce); + return true; } @@ -6179,6 +6359,10 @@ bool submit_noffset_nonce(struct thr_info *thr, struct work *work_in, uint32_t n } ret = true; update_work_stats(thr, work); + + if (opt_benchfile && opt_benchfile_display) + benchfile_dspwork(work, nonce); + if (!fulltest(work->hash, work->target)) { applog(LOG_INFO, "%s %d: Share above target", thr->cgpu->drv->name, thr->cgpu->device_id); @@ -7000,11 +7184,12 @@ static void *watchpool_thread(void __maybe_unused *userdata) for (i = 0; i < total_pools; i++) { struct pool *pool = pools[i]; - if (!opt_benchmark) + if (!opt_benchmark && !opt_benchfile) reap_curl(pool); /* Get a rolling utility per pool over 10 mins */ if (intervals > 19) { + applog(LOG_DEBUG, "Getting rolling utility for %s", pool->poolname); int shares = pool->diff1 - pool->last_shares; pool->last_shares = pool->diff1; @@ -7012,18 +7197,22 @@ static void *watchpool_thread(void __maybe_unused *userdata) pool->shares = pool->utility; } - if (pool->state == POOL_DISABLED) + if (pool->state == POOL_DISABLED) { + applog(LOG_DEBUG, "Skipping disabled %s", pool->poolname); continue; + } /* Don't start testing any pools if the test threads * from startup are still doing their first attempt. */ if (unlikely(pool->testing)) { + applog(LOG_DEBUG, "Testing %s", pool->poolname); pthread_join(pool->test_thread, NULL); pool->testing = false; } /* Test pool is idle once every minute */ if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 30) { + applog(LOG_DEBUG, "Testing idle %s", pool->poolname); cgtime(&pool->tv_idle); if (pool_active(pool, true) && pool_tclear(pool, &pool->idle)) pool_resus(pool); @@ -7040,8 +7229,10 @@ static void *watchpool_thread(void __maybe_unused *userdata) } } - if (current_pool()->idle) + if (current_pool()->idle) { + applog(LOG_DEBUG, "%s is idle, switching pools", current_pool()->poolname); switch_pools(NULL); + } if (pool_strategy == POOL_ROTATE && now.tv_sec - rotate_tv.tv_sec > 60 * opt_rotate_period) { cgtime(&rotate_tv); @@ -7917,14 +8108,19 @@ int main(int argc, char *argv[]) if (!config_loaded) load_default_config(); - if (opt_benchmark) { + if (opt_benchmark || opt_benchfile) { struct pool *pool; // FIXME: executes always (leftover from SHA256d days) quit(1, "Cannot use benchmark mode with scrypt"); pool = add_pool(); + pool->rpc_url = (char *)malloc(255); - strcpy(pool->rpc_url, "Benchmark"); + if (opt_benchfile) + strcpy(pool->rpc_url, "Benchfile"); + else + strcpy(pool->rpc_url, "Benchmark"); + pool->rpc_user = pool->rpc_url; pool->rpc_pass = pool->rpc_url; enable_pool(pool); @@ -8109,7 +8305,7 @@ int main(int argc, char *argv[]) } } - if (opt_benchmark) + if (opt_benchmark || opt_benchfile) goto begin_bench; /* Set pool state */ @@ -8302,7 +8498,12 @@ retry: continue; } - if (opt_benchmark) { + if (opt_benchfile) { + get_benchfile_work(work); + applog(LOG_DEBUG, "Generated benchfile work"); + stage_work(work); + continue; + } else if (opt_benchmark) { get_benchmark_work(work); applog(LOG_DEBUG, "Generated benchmark work"); stage_work(work);