Drastically increase getwork efficiency

This commit is contained in:
pooler 2012-01-19 16:25:01 +01:00
parent e0dc6649e1
commit 0426d3ace0
6 changed files with 73 additions and 32 deletions

6
NEWS
View file

@ -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

3
README
View file

@ -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

View file

@ -1,4 +1,4 @@
AC_INIT([cpuminer], [2.0])
AC_INIT([cpuminer], [2.1])
AC_PREREQ(2.52)
AC_CANONICAL_SYSTEM

View file

@ -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:

View file

@ -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 {

View file

@ -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,12 +520,11 @@ 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]);
#ifdef SCRYPT_3WAY
@ -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;
}