diff --git a/cpu-miner.c b/cpu-miner.c index adf3f4d..cb4d365 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -343,6 +343,9 @@ struct work { char job_id[128]; size_t xnonce2_len; unsigned char xnonce2[32]; + + uint32_t scanned_from; + uint32_t scanned_to; }; static struct work g_work; @@ -494,7 +497,8 @@ static bool submit_upstream_work(CURL *curl, struct work *work) goto out; } - hashlog_remember_submit(work->job_id, nonce, 0); + hashlog_remember_submit(work->job_id, nonce); + hashlog_remember_scan_range(work->job_id, work->scanned_from, work->scanned_to); } else { @@ -834,8 +838,6 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) diff_to_target(work->target, sctx->job.diff / (65536.0 * opt_difficulty)); else if (opt_algo == ALGO_FUGUE256 || opt_algo == ALGO_GROESTL || opt_algo == ALGO_DMD_GR || opt_algo == ALGO_FRESH) diff_to_target(work->target, sctx->job.diff / (256.0 * opt_difficulty)); - else if (opt_algo == ALGO_BLAKE) - diff_to_target(work->target, sctx->job.diff / (2.0 * opt_difficulty)); else diff_to_target(work->target, sctx->job.diff / opt_difficulty); } @@ -848,6 +850,7 @@ static void *miner_thread(void *userdata) uint32_t max_nonce; uint32_t end_nonce = 0xffffffffU / opt_n_threads * (thr_id + 1) - (thr_id + 1); unsigned char *scratchbuf = NULL; + bool work_done = false; char s[16]; memset(&work, 0, sizeof(work)); // prevent work from being used uninitialized @@ -871,6 +874,7 @@ static void *miner_thread(void *userdata) while (1) { unsigned long hashes_done; + uint32_t start_nonce; struct timeval tv_start, tv_end, diff; int64_t max64; uint64_t umax64; @@ -880,41 +884,51 @@ static void *miner_thread(void *userdata) int wcmplen = 76; uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + wcmplen); + applog(LOG_WARNING, "job %s %08x", g_work.job_id, (*nonceptr)); + if (have_stratum) { - while (time(NULL) >= g_work_time + opt_scantime) + while (time(NULL) >= (g_work_time + opt_scantime) && !work_done) usleep(500*1000); + work_done = false; 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 : 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 && - (time(NULL) - g_work_time >= min_scantime || - (*nonceptr) >= end_nonce)) { + if (time(NULL) - g_work_time >= min_scantime || + (*nonceptr) >= end_nonce) { if (unlikely(!get_work(mythr, &g_work))) { applog(LOG_ERR, "work retrieval failed, exiting " "mining thread %d", mythr->id); pthread_mutex_unlock(&g_work_lock); goto out; } - g_work_time = have_stratum ? 0 : time(NULL); - } - if (have_stratum) { - pthread_mutex_unlock(&g_work_lock); - continue; + g_work_time = time(NULL); } } if (memcmp(work.data, g_work.data, wcmplen)) { + /* + applog(LOG_NOTICE, "job %s %08x work change", g_work.job_id, (*nonceptr)); + for (int n=0; n 0 && range.scanned[1] > 0) { + /* continue scan the end */ + start_nonce = range.scanned[1] + 1; + applog(LOG_WARNING, "scan the next part %x + 1", range.scanned[1]); + } else if (range.scanned[0] > 1) { + /* dont scan the beginning... make loops */ + //end_nonce = range.scanned[0] - 1; + //applog(LOG_WARNING, "scan the missing part 0 -> %x", end_nonce); + } + if (start_nonce == work.scanned_from) { + /* to prevent stales, if last was in the same range */ + applog(LOG_ERR, "detected a staled job!"); + //(*nonceptr) = end_nonce + 1; + //work_done = true; + //continue; + start_nonce = range.scanned[1] + 1; + } + } + } + umax64 = (uint64_t) max64; - if (end_nonce < (umax64 + (*nonceptr))) + if ((umax64 + start_nonce) >= end_nonce) max_nonce = end_nonce; else - max_nonce = (uint32_t) 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; - } - } + max_nonce = (uint32_t) umax64 + start_nonce; + + work.scanned_from = start_nonce; + (*nonceptr) = start_nonce; hashes_done = 0; gettimeofday(&tv_start, NULL); @@ -1058,6 +1097,10 @@ static void *miner_thread(void *userdata) /* record scanhash elapsed time */ gettimeofday(&tv_end, NULL); + + if (rc && opt_debug) + applog(LOG_NOTICE, CL_CYN "found => %08x" CL_GRN " %08x", *nonceptr, swab32(*nonceptr)); + timeval_subtract(&diff, &tv_end, &tv_start); if (diff.tv_usec || diff.tv_sec) { pthread_mutex_lock(&stats_lock); @@ -1068,7 +1111,7 @@ static void *miner_thread(void *userdata) if (!opt_quiet) { sprintf(s, thr_hashrates[thr_id] >= 1e6 ? "%.0f" : "%.2f", 1e-3 * thr_hashrates[thr_id]); - applog(LOG_INFO, "GPU #%d: %s, %s khash/s", + applog(LOG_INFO, "GPU #%d: %s, %s kH/s", device_map[thr_id], device_name[thr_id], s); } if (opt_benchmark && thr_id == opt_n_threads - 1) { @@ -1078,10 +1121,19 @@ static void *miner_thread(void *userdata) hashrate += thr_hashrates[i]; if (i == opt_n_threads) { sprintf(s, hashrate >= 1e6 ? "%.0f" : "%.2f", hashrate / 1000.); - applog(LOG_NOTICE, "Total: %s khash/s", s); + applog(LOG_NOTICE, "Total: %s kH/s", s); } } + if (rc) { + work.scanned_to = *nonceptr; + } else { + work.scanned_to = max_nonce; + } + + // could be used to store speeds too.. + hashlog_remember_scan_range(work.job_id, work.scanned_from, work.scanned_to); + /* if nonce found, submit work */ if (rc && !opt_benchmark && !submit_work(mythr, &work)) break; diff --git a/hashlog.cpp b/hashlog.cpp index 0b8b574..645fc88 100644 --- a/hashlog.cpp +++ b/hashlog.cpp @@ -1,21 +1,23 @@ -//#include #include +#include #include #include "miner.h" #define HI_DWORD(u64) ((uint32_t) (u64 >> 32)) #define LO_DWORD(u64) ((uint32_t) u64) +#define MK_HI64(u32) (0x100000000ULL * u32) struct hashlog_data { uint32_t ntime; uint32_t scanned_from; uint32_t scanned_to; + uint32_t last_from; }; static std::map tlastshares; -#define LOG_PURGE_TIMEOUT 15*60 +#define LOG_PURGE_TIMEOUT 5*60 /** * str hex to uint32 @@ -27,32 +29,79 @@ static uint64_t hextouint(char* jobid) } /** - * Store submitted nonces of a job + * @return time of a job/nonce submission (or last nonce if nonce is 0) */ -extern "C" void hashlog_remember_submit(char* jobid, uint32_t nonce, uint64_t range) +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()) { + hashlog_data data = tlastshares[key]; + ret = data.ntime; + } + return ret; +} +/** + * Store submitted nonces of a job + */ +extern "C" void hashlog_remember_submit(char* jobid, uint32_t nonce) +{ + uint64_t njobid = hextouint(jobid); + uint64_t keyall = (njobid << 32); + uint64_t key = keyall + nonce; struct hashlog_data data; + + data = tlastshares[keyall]; data.ntime = (uint32_t) time(NULL); - data.scanned_from = LO_DWORD(range); - data.scanned_to = HI_DWORD(range); tlastshares[key] = data; } /** - * Search last submitted nonce for a job - * @return max nonce + * Update job scanned range */ -extern "C" uint32_t hashlog_get_last_sent(char* jobid) +extern "C" void hashlog_remember_scan_range(char* jobid, uint32_t scanned_from, uint32_t scanned_to) { - uint32_t ret = 0; + uint64_t njobid = hextouint(jobid); + uint64_t keyall = (njobid << 32); + struct hashlog_data data; + + // global scan range of a job + data = tlastshares[keyall]; + if (hashlog_get_scan_range(jobid) == 0) { + memset(&data, 0, sizeof(data)); + } + + if (data.scanned_from == 0 || scanned_to == (data.scanned_from - 1)) + data.scanned_from = scanned_from ? scanned_from : 1; // min 1 + if (data.scanned_to == 0 || scanned_from == data.scanned_to + 1) + data.scanned_to = scanned_to; + + data.last_from = scanned_from; + + tlastshares[keyall] = data; + applog(LOG_BLUE, "job %s range : %x %x -> %x %x (%x)", jobid, + scanned_from, scanned_to, data.scanned_from, data.scanned_to, data.ntime);/* */ +} + +/** + * Returns the range of a job + * @return uint64_t to|from + */ +extern "C" uint64_t hashlog_get_scan_range(char* jobid) +{ + uint64_t ret = 0; 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); + if ((keypfx & i->first) == keypfx) { + hashlog_data data = i->second; + ret = data.scanned_from; + ret += MK_HI64(data.scanned_to); } i++; } @@ -60,21 +109,22 @@ extern "C" uint32_t hashlog_get_last_sent(char* jobid) } /** - * @return time of a job/nonce submission (or last nonce if nonce is 0) + * Search last submitted nonce for a job + * @return max nonce */ -extern "C" uint32_t hashlog_already_submittted(char* jobid, uint32_t nonce) +extern "C" uint32_t hashlog_get_last_sent(char* jobid) { - uint32_t ret = 0; + uint32_t nonce = 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()) { - hashlog_data data = tlastshares[key]; - ret = data.ntime; + uint64_t keypfx = (njobid << 32); + std::map::iterator i = tlastshares.begin(); + while (i != tlastshares.end()) { + if ((keypfx & i->first) == keypfx && i->second.ntime > 0) { + nonce = LO_DWORD(i->first); + } + i++; } - return ret; + return nonce; } /** diff --git a/miner.h b/miner.h index 79e3a15..5f9e8ac 100644 --- a/miner.h +++ b/miner.h @@ -391,9 +391,11 @@ bool stratum_subscribe(struct stratum_ctx *sctx); bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass); bool stratum_handle_method(struct stratum_ctx *sctx, const char *s); -void hashlog_remember_submit(char* jobid, uint32_t nounce, uint64_t range); +void hashlog_remember_submit(char* jobid, uint32_t nounce); +void hashlog_remember_scan_range(char* jobid, uint32_t scanned_from, uint32_t scanned_to); uint32_t hashlog_already_submittted(char* jobid, uint32_t nounce); uint32_t hashlog_get_last_sent(char* jobid); +uint64_t hashlog_get_scan_range(char* jobid); void hashlog_purge_old(void); void hashlog_purge_job(char* jobid); void hashlog_purge_all(void); diff --git a/util.c b/util.c index 73a1847..5567459 100644 --- a/util.c +++ b/util.c @@ -559,7 +559,7 @@ bool fulltest(const uint32_t *hash, const uint32_t *target) } } - if (!rc || opt_debug) { + if (!rc && opt_debug) { uint32_t hash_be[8], target_be[8]; char *hash_str, *target_str;