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 @@ -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]);

41
cpu-miner.c

@ -822,9 +822,11 @@ static void stratum_gen_work(struct stratum_ctx *sctx, struct work *work) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) @@ -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) {

71
hashlog.cpp

@ -1,39 +1,68 @@ @@ -1,39 +1,68 @@
#include <inttypes.h>
//#include <inttypes.h>
#include <stdlib.h>
#include <map>
#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;
/**
* 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<uint64_t, uint32_t>::iterator i = tlastshares.find(key);
if (i != tlastshares.end())
uint64_t njobid = hextouint(jobid);
uint64_t keypfx = (njobid << 32);
std::map<uint64_t, uint32_t>::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) @@ -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<uint64_t, uint32_t>::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) @@ -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<uint64_t, uint32_t>::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) @@ -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();
}

4
miner.h

@ -390,6 +390,7 @@ bool stratum_handle_method(struct stratum_ctx *sctx, const char *s); @@ -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); @@ -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);

26
util.c

@ -21,6 +21,7 @@ @@ -21,6 +21,7 @@
#include <unistd.h>
#include <jansson.h>
#include <curl/curl.h>
#include <sys/time.h>
#include <time.h>
#ifdef WIN32
#include "compat/winansi.h"
@ -1350,6 +1351,31 @@ out: @@ -1350,6 +1351,31 @@ out:
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)
{

Loading…
Cancel
Save