diff --git a/README.md b/README.md index a64a7b80..f7f2c583 100644 --- a/README.md +++ b/README.md @@ -448,3 +448,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/sgminer.c b/sgminer.c index d287e182..c3549231 100644 --- a/sgminer.c +++ b/sgminer.c @@ -79,6 +79,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; @@ -1095,6 +1118,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, opt_show_charp, &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"), @@ -2989,6 +3018,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; + + 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; + } + + long time = atol(commas[BENCHWORK_NONCETIME]); + + sprintf(&(item[j]), "%08lx", 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) { @@ -3494,7 +3671,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) { @@ -6091,6 +6268,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; } @@ -6111,6 +6291,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); @@ -6932,7 +7116,7 @@ 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 */ @@ -7833,14 +8017,17 @@ 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 = 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); @@ -8025,7 +8212,7 @@ int main(int argc, char *argv[]) } } - if (opt_benchmark) + if (opt_benchmark || opt_benchfile) goto begin_bench; /* Set pool state */ @@ -8218,7 +8405,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);