From 0426d3ace0b7d99f55bab140ee4e3ca365ba4ccc Mon Sep 17 00:00:00 2001 From: pooler Date: Thu, 19 Jan 2012 16:25:01 +0100 Subject: [PATCH] Drastically increase getwork efficiency --- NEWS | 6 ++++++ README | 3 +++ configure.ac | 2 +- cpu-miner.c | 53 +++++++++++++++++++++++++++++++++++++--------------- miner.h | 3 ++- scrypt.c | 38 ++++++++++++++++++++++--------------- 6 files changed, 73 insertions(+), 32 deletions(-) diff --git a/NEWS b/NEWS index 1cb04f9..11f3c1f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,9 @@ +Version 2.1 - Jan 19, 2012 + +- Share the same work among all threads +- Do not ask for new work if the current one is not expired +- Do not discard the work returned by long polling + Version 2.0 - Jan 16, 2012 - Change default port to 9332 for Litecoin and remove default credentials diff --git a/README b/README index 9ad2b67..e7b7649 100644 --- a/README +++ b/README @@ -23,3 +23,6 @@ Basic WIN32 build instructions (on Fedora 13; requires mingw32): Usage instructions: Run "minerd --help" to see options. +Also many issues and FAQs are covered in the forum thread +dedicated to this program, + https://bitcointalk.org/index.php?topic=55038.0 diff --git a/configure.ac b/configure.ac index c6886cb..f7cd425 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([cpuminer], [2.0]) +AC_INIT([cpuminer], [2.1]) AC_PREREQ(2.52) AC_CANONICAL_SYSTEM diff --git a/cpu-miner.c b/cpu-miner.c index 1ebab72..054f68b 100644 --- a/cpu-miner.c +++ b/cpu-miner.c @@ -101,7 +101,7 @@ int opt_scantime = 5; static json_t *opt_config; static const bool opt_time = true; static enum sha256_algos opt_algo = ALGO_SCRYPT; -static int opt_n_threads; +int opt_n_threads; static int num_processors; static char *rpc_url; static char *rpc_userpass; @@ -213,6 +213,10 @@ struct work { unsigned char hash[32]; }; +static struct work g_work; +static time_t g_work_time; +static pthread_mutex_t g_work_lock; + static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen) { @@ -287,9 +291,6 @@ static bool submit_upstream_work(CURL *curl, const struct work *work) "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", hexstr); - if (opt_debug) - applog(LOG_DEBUG, "DBG: sending RPC call: %s", s); - /* issue JSON-RPC request */ val = json_rpc_call(curl, rpc_url, rpc_userpass, s, false, false); if (unlikely(!val)) { @@ -535,6 +536,7 @@ static void *miner_thread(void *userdata) struct thr_info *mythr = userdata; int thr_id = mythr->id; uint32_t max_nonce = 0xffffff; + uint32_t next_nonce; unsigned char *scratchbuf = NULL; /* Set worker threads to nice 19 and then preferentially to SCHED_IDLE @@ -551,7 +553,7 @@ static void *miner_thread(void *userdata) if (opt_algo == ALGO_SCRYPT) { scratchbuf = scrypt_buffer_alloc(); - max_nonce = 0xffff; + max_nonce = 0xffff * opt_n_threads; } while (1) { @@ -563,12 +565,25 @@ static void *miner_thread(void *userdata) bool rc; /* obtain new work from internal workio thread */ - if (unlikely(!get_work(mythr, &work))) { - applog(LOG_ERR, "work retrieval failed, exiting " - "mining thread %d", mythr->id); - goto out; + pthread_mutex_lock(&g_work_lock); + if (!have_longpoll || time(NULL) >= g_work_time + opt_scantime) { + 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; + } + time(&g_work_time); + if (opt_debug) + applog(LOG_DEBUG, "DEBUG: got new work"); } + if (memcmp(work.data, g_work.data, 76)) { + memcpy(&work, &g_work, sizeof(struct work)); + next_nonce = thr_id; + } + pthread_mutex_unlock(&g_work_lock); + work_restart[thr_id].restart = 0; hashes_done = 0; gettimeofday(&tv_start, NULL); @@ -576,7 +591,8 @@ static void *miner_thread(void *userdata) switch (opt_algo) { case ALGO_SCRYPT: rc = scanhash_scrypt(thr_id, work.data, scratchbuf, - work.target, max_nonce, &hashes_done); + work.target, next_nonce + max_nonce, + &next_nonce, &hashes_done); break; default: @@ -595,8 +611,9 @@ static void *miner_thread(void *userdata) if (diffms > 0) { max64 = ((uint64_t)hashes_done * opt_scantime * 1000) / diffms; - if (max64 > 0xfffffffaULL) - max64 = 0xfffffffaULL; + max64 *= opt_n_threads; + if (max64 > 0xffff0000ULL) + max64 = 0xffff0000ULL; max_nonce = max64; } @@ -665,13 +682,19 @@ static void *longpoll_thread(void *userdata) false, true); if (likely(val)) { failures = 0; - json_decref(val); - applog(LOG_INFO, "LONGPOLL detected new block"); - restart_threads(); + pthread_mutex_lock(&g_work_lock); + if (work_decode(json_object_get(val, "result"), &g_work)) { + if (opt_debug) + applog(LOG_DEBUG, "DEBUG: got new work"); + time(&g_work_time); + restart_threads(); + } + pthread_mutex_unlock(&g_work_lock); } else { /* longpoll failed, keep trying */ } + json_decref(val); } out: diff --git a/miner.h b/miner.h index df6d01e..4ed00ca 100644 --- a/miner.h +++ b/miner.h @@ -130,7 +130,7 @@ extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); extern unsigned char *scrypt_buffer_alloc(); extern int scanhash_scrypt(int, unsigned char *pdata, unsigned char *scratchbuf, const unsigned char *ptarget, - uint32_t max_nonce, unsigned long *nHashesDone); + uint32_t max_nonce, uint32_t *next_nonce, unsigned long *hashes_done); extern int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y); @@ -141,6 +141,7 @@ extern int opt_scantime; extern int opt_timeout; extern bool want_longpoll; extern bool have_longpoll; +extern int opt_n_threads; struct thread_q; struct work_restart { diff --git a/scrypt.c b/scrypt.c index 6ea4b3e..e7df5c0 100644 --- a/scrypt.c +++ b/scrypt.c @@ -512,7 +512,7 @@ static int test_hash(const uint32_t *hash, const uint32_t *target) int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf, const unsigned char *ptarget, - uint32_t max_nonce, unsigned long *hashes_done) + uint32_t max_nonce, uint32_t *next_nonce, unsigned long *hashes_done) { uint32_t data[20], hash[8]; #ifdef SCRYPT_3WAY @@ -520,11 +520,10 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf, uint32_t data3[20], hash3[8]; int throughput; #endif - uint32_t n = 0; + unsigned long c = 0; + uint32_t n = *next_nonce; uint32_t Htarg = le32dec(&((const uint32_t *)ptarget)[7]); int i; - - work_restart[thr_id].restart = 0; for (i = 0; i < 19; i++) data[i] = be32dec(&((const uint32_t *)pdata)[i]); @@ -535,16 +534,23 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf, #endif while (1) { - data[19] = n++; + data[19] = n; + n += opt_n_threads; + ++c; #ifdef SCRYPT_3WAY - if (throughput >= 2 && n < max_nonce) { - data2[19] = n++; - if (throughput >= 3 && n < max_nonce) { - data3[19] = n++; + if (throughput >= 2 && n <= max_nonce) { + data2[19] = n; + n += opt_n_threads; + ++c; + if (throughput >= 3 && n <= max_nonce) { + data3[19] = n; + n += opt_n_threads; + ++c; scrypt_1024_1_1_256_sp_3way(data, data2, data3, hash, hash2, hash3, scratchbuf); if (hash3[7] < Htarg || hash3[7] == Htarg && test_hash(hash3, (uint32_t *)ptarget)) { be32enc(&((uint32_t *)pdata)[19], data3[19]); - *hashes_done = n; + *next_nonce = n; + *hashes_done = c; return true; } } else { @@ -552,7 +558,8 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf, } if (hash2[7] < Htarg || hash2[7] == Htarg && test_hash(hash2, (uint32_t *)ptarget)) { be32enc(&((uint32_t *)pdata)[19], data2[19]); - *hashes_done = n; + *next_nonce = n; + *hashes_done = c; return true; } } else { @@ -564,15 +571,16 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf, if (hash[7] < Htarg || hash[7] == Htarg && test_hash(hash, (uint32_t *)ptarget)) { be32enc(&((uint32_t *)pdata)[19], data[19]); - *hashes_done = n; + *next_nonce = n; + *hashes_done = c; return true; } - if ((n >= max_nonce) || work_restart[thr_id].restart) { - *hashes_done = n; + if ((n > max_nonce) || work_restart[thr_id].restart) break; - } } + *next_nonce = n; + *hashes_done = c; return false; }