Browse Source

hashlog: prevent double computing on jobs already done

master
Tanguy Pruvot 10 years ago
parent
commit
1a4391d7ff
  1. 2
      blake32.cu
  2. 41
      cpu-miner.c
  3. 71
      hashlog.cpp
  4. 4
      miner.h
  5. 26
      util.c

2
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 vhashcpu[8];
uint32_t Htarg = ptarget[7]; 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++) for (int k=0; k < 20; k++)
be32enc(&endiandata[k], pdata[k]); be32enc(&endiandata[k], pdata[k]);

41
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); pthread_mutex_unlock(&sctx->work_lock);
if (opt_debug) { if (opt_debug) {
char *tm = atime2str(swab32(work->data[17]));
char *xnonce2str = bin2hex(work->xnonce2, sctx->xnonce2_size); char *xnonce2str = bin2hex(work->xnonce2, sctx->xnonce2_size);
applog(LOG_DEBUG, "DEBUG: job_id='%s' extranonce2=%s ntime=%08x", applog(LOG_DEBUG, "DEBUG: job_id=%s xnonce2=%s time=%s",
work->job_id, xnonce2str, swab32(work->data[17])); work->job_id, xnonce2str, tm);
free(tm);
free(xnonce2str); free(xnonce2str);
} }
@ -842,10 +844,9 @@ static void *miner_thread(void *userdata)
int thr_id = mythr->id; int thr_id = mythr->id;
struct work work; struct work work;
uint32_t max_nonce; 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; unsigned char *scratchbuf = NULL;
char s[16]; char s[16];
int i;
memset(&work, 0, sizeof(work)); // prevent work from being used uninitialized 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; unsigned long hashes_done;
struct timeval tv_start, tv_end, diff; struct timeval tv_start, tv_end, diff;
int64_t max64; int64_t max64;
uint64_t umax64;
int rc; int rc;
// &work.data[19] // &work.data[19]
@ -877,13 +879,17 @@ static void *miner_thread(void *userdata)
uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + wcmplen); uint32_t *nonceptr = (uint32_t*) (((char*)work.data) + wcmplen);
if (have_stratum) { if (have_stratum) {
while (time(NULL) >= g_work_time + 120) while (time(NULL) >= g_work_time + opt_scantime)
sleep(1); usleep(500*1000);
pthread_mutex_lock(&g_work_lock); pthread_mutex_lock(&g_work_lock);
nonceptr = (uint32_t*) (((char*)work.data) + wcmplen);
if ((*nonceptr) >= end_nonce) if ((*nonceptr) >= end_nonce)
stratum_gen_work(&stratum, &g_work); stratum_gen_work(&stratum, &g_work);
} else { } 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 */ /* obtain new work from internal workio thread */
pthread_mutex_lock(&g_work_lock); pthread_mutex_lock(&g_work_lock);
if (!have_stratum && if (!have_stratum &&
@ -904,7 +910,7 @@ static void *miner_thread(void *userdata)
} }
if (memcmp(work.data, g_work.data, wcmplen)) { if (memcmp(work.data, g_work.data, wcmplen)) {
memcpy(&work, &g_work, sizeof(struct work)); 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 } else
(*nonceptr)++; (*nonceptr)++;
pthread_mutex_unlock(&g_work_lock); pthread_mutex_unlock(&g_work_lock);
@ -932,10 +938,24 @@ static void *miner_thread(void *userdata)
break; break;
} }
} }
if ((int64_t)(*nonceptr) + max64 > end_nonce)
umax64 = (uint64_t) max64;
if (end_nonce < (umax64 + (*nonceptr)))
max_nonce = end_nonce; max_nonce = end_nonce;
else 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; hashes_done = 0;
gettimeofday(&tv_start, NULL); gettimeofday(&tv_start, NULL);
@ -1051,6 +1071,7 @@ static void *miner_thread(void *userdata)
} }
if (opt_benchmark && thr_id == opt_n_threads - 1) { if (opt_benchmark && thr_id == opt_n_threads - 1) {
double hashrate = 0.; double hashrate = 0.;
int i;
for (i = 0; i < opt_n_threads && thr_hashrates[i]; i++) for (i = 0; i < opt_n_threads && thr_hashrates[i]; i++)
hashrate += thr_hashrates[i]; hashrate += thr_hashrates[i];
if (i == opt_n_threads) { if (i == opt_n_threads) {

71
hashlog.cpp

@ -1,39 +1,68 @@
#include <inttypes.h> //#include <inttypes.h>
#include <stdlib.h> #include <stdlib.h>
#include <map> #include <map>
#include "miner.h" #include "miner.h"
#define HI_DWORD(u64) ((uint32_t) (u64 >> 32))
#define LO_DWORD(u64) ((uint32_t) u64)
static std::map<uint64_t, uint32_t> tlastshares; static std::map<uint64_t, uint32_t> tlastshares;
/**
* Purge entries after 15 minutes
*/
#define LOG_PURGE_TIMEOUT 15*60 #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; char *ptr;
uint64_t njobid = (uint64_t) strtoul(jobid, &ptr, 16); return strtoull(jobid, &ptr, 16);
uint64_t key = (njobid << 32) + nounce; }
/**
* 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); 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; uint32_t ret = 0;
uint64_t njobid = (uint64_t) strtoul(jobid, &ptr, 16); uint64_t njobid = hextouint(jobid);
uint64_t key = (njobid << 32) + nounce; uint64_t keypfx = (njobid << 32);
std::map<uint64_t, uint32_t>::iterator i = tlastshares.find(key); std::map<uint64_t, uint32_t>::iterator i = tlastshares.begin();
if (i != tlastshares.end()) 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]; ret = (uint32_t) tlastshares[key];
}
return ret; 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) extern "C" void hashlog_purge_job(char* jobid)
{ {
char *ptr; uint64_t njobid = hextouint(jobid);
uint64_t njobid = strtoul(jobid, &ptr, 16);
uint64_t keypfx = (njobid << 32); uint64_t keypfx = (njobid << 32);
std::map<uint64_t, uint32_t>::iterator i = tlastshares.begin(); std::map<uint64_t, uint32_t>::iterator i = tlastshares.begin();
while (i != tlastshares.end()) { while (i != tlastshares.end()) {
if ((keypfx & i->first) != 0) if ((keypfx & i->first) == keypfx)
tlastshares.erase(i); tlastshares.erase(i);
i++; i++;
} }
@ -60,6 +88,7 @@ extern "C" void hashlog_purge_old(void)
{ {
int deleted = 0; int deleted = 0;
uint32_t now = (uint32_t) time(NULL); uint32_t now = (uint32_t) time(NULL);
uint32_t sz = tlastshares.size();
std::map<uint64_t, uint32_t>::iterator i = tlastshares.begin(); std::map<uint64_t, uint32_t>::iterator i = tlastshares.begin();
while (i != tlastshares.end()) { while (i != tlastshares.end()) {
if ((now - i->second) > LOG_PURGE_TIMEOUT) { if ((now - i->second) > LOG_PURGE_TIMEOUT) {
@ -69,16 +98,14 @@ extern "C" void hashlog_purge_old(void)
i++; i++;
} }
if (opt_debug && deleted) { if (opt_debug && deleted) {
applog(LOG_DEBUG, "hashlog: %d/%d purged", applog(LOG_DEBUG, "hashlog: %d/%d purged", deleted, sz);
deleted, tlastshares.size());
} }
} }
/** /**
* Reset the submitted nounce cache * Reset the submitted nonces cache
*/ */
extern "C" void hashlog_purge_all(void) extern "C" void hashlog_purge_all(void)
{ {
tlastshares.clear(); tlastshares.clear();
} }

4
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); void hashlog_remember_submit(char* jobid, uint32_t nounce);
uint32_t hashlog_already_submittted(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_old(void);
void hashlog_purge_job(char* jobid); void hashlog_purge_job(char* jobid);
void hashlog_purge_all(void); void hashlog_purge_all(void);
@ -405,6 +406,9 @@ extern void tq_thaw(struct thread_q *tq);
void proper_exit(int reason); 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 applog_hash(unsigned char *hash);
void print_hash_tests(void); void print_hash_tests(void);

26
util.c

@ -21,6 +21,7 @@
#include <unistd.h> #include <unistd.h>
#include <jansson.h> #include <jansson.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <sys/time.h>
#include <time.h> #include <time.h>
#ifdef WIN32 #ifdef WIN32
#include "compat/winansi.h" #include "compat/winansi.h"
@ -1350,6 +1351,31 @@ out:
return rval; 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 */ /* sprintf can be used in applog */
static char* format_hash(char* buf, unsigned char *hash) static char* format_hash(char* buf, unsigned char *hash)
{ {

Loading…
Cancel
Save