From 1a4391d7ff21397a128abf031f92733a8ac47437 Mon Sep 17 00:00:00 2001 From: Tanguy Pruvot Date: Tue, 2 Sep 2014 12:40:52 +0200 Subject: [PATCH] hashlog: prevent double computing on jobs already done --- blake32.cu | 2 +- cpu-miner.c | 41 +++++++++++++++++++++++-------- hashlog.cpp | 71 ++++++++++++++++++++++++++++++++++++----------------- miner.h | 4 +++ util.c | 26 ++++++++++++++++++++ 5 files changed, 111 insertions(+), 33 deletions(-) diff --git a/blake32.cu b/blake32.cu index a86287e8bd..b50a3cac54 100644 --- a/blake32.cu +++ b/blake32.cu @@ -304,7 +304,7 @@ extern "C" int scanhash_blake32(int thr_id, uint32_t *pdata, const uint32_t *pta uint32_t vhashcpu[8]; uint32_t Htarg = ptarget[7]; - applog(LOG_WARNING, "throughput=%u, start=%x, max=%x", throughput, first_nonce, max_nonce); + applog(LOG_WARNING, "throughput=%u, start=%x, max=%x, pdata=%x", throughput, first_nonce, max_nonce, pdata[0]); for (int k=0; k < 20; k++) be32enc(&endiandata[k], pdata[k]); diff --git a/cpu-miner.c b/cpu-miner.c index a16c3b782c..6da146596a 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -822,9 +822,11 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) pthread_mutex_unlock(&sctx->work_lock); if (opt_debug) { + char *tm = atime2str(swab32(work->data[17])); char *xnonce2str = bin2hex(work->xnonce2, sctx->xnonce2_size); - applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x", - work->job_id, xnonce2str, swab32(work->data[17])); + applog(LOG_DEBUG, "DEBUG: job_id=%s xnonce2=%s time=%s", + work->job_id, xnonce2str, tm); + free(tm); free(xnonce2str); } @@ -842,10 +844,9 @@ static void *miner_thread(void *userdata) int thr_id = mythr->id; struct work work; uint32_t max_nonce; - uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - 2; + uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - (thr_id + 1); unsigned char *scratchbuf = NULL; char s[16]; - int i; memset(&work, 0, sizeof(work)); // prevent work from being used uninitialized @@ -870,6 +871,7 @@ static void *miner_thread(void *userdata) unsigned long hashes_done; struct timeval tv_start, tv_end, diff; int64_t max64; + uint64_t umax64; int rc; // &work.data[19] @@ -877,13 +879,17 @@ static void *miner_thread(void *userdata) uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + wcmplen); if (have_stratum) { - while (time(NULL) >= g_work_time + 120) - sleep(1); + while (time(NULL) >= g_work_time + opt_scantime) + usleep(500*1000); pthread_mutex_lock(&g_work_lock); + nonceptr = (uint32_t*) (((char*)work.data) + wcmplen); if ((*nonceptr) >= end_nonce) stratum_gen_work(&stratum, &g_work); } else { - int min_scantime = have_longpoll ? (LP_SCANTIME*3)/4 : opt_scantime; + int min_scantime = have_longpoll ? LP_SCANTIME : opt_scantime; + if (!opt_quiet) + applog(LOG_DEBUG, "have_longpoll=%d, have_stratum=%d, min_scantime=%d, g_work_time=%d", + have_longpoll, have_stratum, min_scantime, g_work_time); /* obtain new work from internal workio thread */ pthread_mutex_lock(&g_work_lock); if (!have_stratum && @@ -904,7 +910,7 @@ static void *miner_thread(void *userdata) } if (memcmp(work.data, g_work.data, wcmplen)) { memcpy(&work, &g_work, sizeof(struct work)); - (*nonceptr) = 0xffffffffU / opt_n_threads * thr_id; + (*nonceptr) = 0xffffffffU / opt_n_threads * thr_id; // 0 if single thr } else (*nonceptr)++; pthread_mutex_unlock(&g_work_lock); @@ -932,10 +938,24 @@ static void *miner_thread(void *userdata) break; } } - if ((int64_t)(*nonceptr) + max64 > end_nonce) + + umax64 = (uint64_t) max64; + if (end_nonce < (umax64 + (*nonceptr))) max_nonce = end_nonce; else - max_nonce = (uint32_t)((*nonceptr) + max64); + max_nonce = umax64 + (*nonceptr); + + /* do not recompute something already scanned (and sent) ! */ + if (hashlog_already_submittted(work.job_id, 0)) { + uint32_t lastnonce = hashlog_get_last_sent(work.job_id); + if ((*nonceptr) < lastnonce && lastnonce <= max_nonce) { + applog(LOG_WARNING, "rescan of sent job? nonce=%x, last was %x", (*nonceptr), lastnonce); + max_nonce = lastnonce - 1; + } else if ((*nonceptr) == lastnonce) { + applog(LOG_WARNING, "rescan of sent job? start nonce = lastnonce"); + (*nonceptr) = lastnonce + 1; + } + } hashes_done = 0; gettimeofday(&tv_start, NULL); @@ -1051,6 +1071,7 @@ static void *miner_thread(void *userdata) } if (opt_benchmark && thr_id == opt_n_threads - 1) { double hashrate = 0.; + int i; for (i = 0; i < opt_n_threads && thr_hashrates[i]; i++) hashrate += thr_hashrates[i]; if (i == opt_n_threads) { diff --git a/hashlog.cpp b/hashlog.cpp index ded566e6da..3948751db0 100644 --- a/hashlog.cpp +++ b/hashlog.cpp @@ -1,39 +1,68 @@ -#include +//#include #include #include #include "miner.h" +#define HI_DWORD(u64) ((uint32_t) (u64 >> 32)) +#define LO_DWORD(u64) ((uint32_t) u64) + static std::map tlastshares; -/** - * Purge entries after 15 minutes - */ #define LOG_PURGE_TIMEOUT 15*60 /** - * Store submitted nounces of a job + * str hex to uint32 */ -extern "C" void hashlog_remember_submit(char* jobid, uint32_t nounce) +static uint64_t hextouint(char* jobid) { char *ptr; - uint64_t njobid = (uint64_t) strtoul(jobid, &ptr, 16); - uint64_t key = (njobid << 32) + nounce; + return strtoull(jobid, &ptr, 16); +} + +/** + * Store submitted nonces of a job + */ +extern "C" void hashlog_remember_submit(char* jobid, uint32_t nonce) +{ + uint64_t njobid = hextouint(jobid); + uint64_t key = (njobid << 32) + nonce; tlastshares[key] = (uint32_t) time(NULL); } /** - * @return time of submission + * Search last submitted nonce for a job + * @return max nonce */ -extern "C" uint32_t hashlog_already_submittted(char* jobid, uint32_t nounce) +extern "C" uint32_t hashlog_get_last_sent(char* jobid) { - char *ptr; uint32_t ret = 0; - uint64_t njobid = (uint64_t) strtoul(jobid, &ptr, 16); - uint64_t key = (njobid << 32) + nounce; - std::map::iterator i = tlastshares.find(key); - if (i != tlastshares.end()) + uint64_t njobid = hextouint(jobid); + uint64_t keypfx = (njobid << 32); + std::map::iterator i = tlastshares.begin(); + while (i != tlastshares.end()) { + if ((keypfx & i->first) == keypfx && LO_DWORD(i->first) > ret) { + ret = LO_DWORD(i->first); + } + i++; + } + return ret; +} + +/** + * @return time of a job/nonce submission (or last nonce if nonce is 0) + */ +extern "C" uint32_t hashlog_already_submittted(char* jobid, uint32_t nonce) +{ + uint32_t ret = 0; + uint64_t njobid = hextouint(jobid); + uint64_t key = (njobid << 32) + nonce; + if (nonce == 0) { + // search last submitted nonce for job + ret = hashlog_get_last_sent(jobid); + } else if (tlastshares.find(key) != tlastshares.end()) { ret = (uint32_t) tlastshares[key]; + } return ret; } @@ -42,12 +71,11 @@ extern "C" uint32_t hashlog_already_submittted(char* jobid, uint32_t nounce) */ extern "C" void hashlog_purge_job(char* jobid) { - char *ptr; - uint64_t njobid = strtoul(jobid, &ptr, 16); + uint64_t njobid = hextouint(jobid); uint64_t keypfx = (njobid << 32); std::map::iterator i = tlastshares.begin(); while (i != tlastshares.end()) { - if ((keypfx & i->first) != 0) + if ((keypfx & i->first) == keypfx) tlastshares.erase(i); i++; } @@ -60,6 +88,7 @@ extern "C" void hashlog_purge_old(void) { int deleted = 0; uint32_t now = (uint32_t) time(NULL); + uint32_t sz = tlastshares.size(); std::map::iterator i = tlastshares.begin(); while (i != tlastshares.end()) { if ((now - i->second) > LOG_PURGE_TIMEOUT) { @@ -69,16 +98,14 @@ extern "C" void hashlog_purge_old(void) i++; } if (opt_debug && deleted) { - applog(LOG_DEBUG, "hashlog: %d/%d purged", - deleted, tlastshares.size()); + applog(LOG_DEBUG, "hashlog: %d/%d purged", deleted, sz); } } /** - * Reset the submitted nounce cache + * Reset the submitted nonces cache */ extern "C" void hashlog_purge_all(void) { tlastshares.clear(); } - diff --git a/miner.h b/miner.h index b986197372..310037132e 100644 --- a/miner.h +++ b/miner.h @@ -390,6 +390,7 @@ bool stratum_handle_method(struct stratum_ctx *sctx, const char *s); void hashlog_remember_submit(char* jobid, uint32_t nounce); uint32_t hashlog_already_submittted(char* jobid, uint32_t nounce); +uint32_t hashlog_get_last_sent(char* jobid); void hashlog_purge_old(void); void hashlog_purge_job(char* jobid); void hashlog_purge_all(void); @@ -405,6 +406,9 @@ extern void tq_thaw(struct thread_q *tq); void proper_exit(int reason); +size_t time2str(char* buf, time_t timer); +char* atime2str(time_t timer); + void applog_hash(unsigned char *hash); void print_hash_tests(void); diff --git a/util.c b/util.c index a9e0ae2ea7..275abf74df 100644 --- a/util.c +++ b/util.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #ifdef WIN32 #include "compat/winansi.h" @@ -1350,6 +1351,31 @@ void *tq_pop(struct thread_q *tq, const struct timespec *abstime) return rval; } +/** + * @param buf char[9] mini + * @param time_t timer to convert + */ +size_t time2str(char* buf, time_t timer) +{ + struct tm* tm_info; + tm_info = localtime(&timer); + return strftime(buf, 19, "%H:%M:%S", tm_info); +} + +/** + * Alloc and returns time string (to be freed) + * @param time_t timer to convert + */ +char* atime2str(time_t timer) +{ + struct tm* tm_info; + char* buf = malloc(16); + memset(buf, 0, 16); + tm_info = localtime(&timer); + strftime(buf, 19, "%H:%M:%S", tm_info); + return buf; +} + /* sprintf can be used in applog */ static char* format_hash(char* buf, unsigned char *hash) {