From dc767487e2373dc4703d05b3ca068efe29f62ef1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 26 Jan 2014 20:47:53 +1100 Subject: [PATCH 01/28] Fix displayed diff when solo mining at >2^32 diff. --- sgminer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sgminer.c b/sgminer.c index 6cd81b24..e4194285 100644 --- a/sgminer.c +++ b/sgminer.c @@ -2935,7 +2935,7 @@ static void calc_diff(struct work *work, double known) { struct sgminer_pool_stats *pool_stats = &(work->pool->sgminer_pool_stats); double difficulty; - int intdiff; + uint64_t uintdiff; if (known) work->work_difficulty = known; @@ -2952,8 +2952,8 @@ static void calc_diff(struct work *work, double known) difficulty = work->work_difficulty; pool_stats->last_diff = difficulty; - intdiff = round(difficulty); - suffix_string(intdiff, work->pool->diff, sizeof(work->pool->diff), 0); + uintdiff = round(difficulty); + suffix_string(uintdiff, work->pool->diff, sizeof(work->pool->diff), 0); if (difficulty == pool_stats->min_diff) pool_stats->min_diff_count++; From 796c032aae70772747469f1abfd95c5f31ee9df4 Mon Sep 17 00:00:00 2001 From: Noel Maersk Date: Sun, 16 Feb 2014 14:22:37 +0200 Subject: [PATCH 02/28] misc: note having ported changes up to cgminer 3.12.0. --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 2180820f..a96f0ccf 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,7 @@ ## Version 4.2.0 - TBA -* Forward-port changes from `ckolivas/cgminer` up to 3.11.0. +* Forward-port changes from `ckolivas/cgminer` up to 3.12.0. ## Version 4.1.0 - 7th February 2014 From 011512561ab4cccca4be4ac8f3c4100cd0b4686b Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 31 Jan 2014 10:37:59 +1100 Subject: [PATCH 03/28] Add a call to a driver specific zero stats function when zero stats is called to allow each driver to reset its own stats as well if desired. --- miner.h | 3 +++ sgminer.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/miner.h b/miner.h index 37cd38b4..248c9ca4 100644 --- a/miner.h +++ b/miner.h @@ -355,6 +355,9 @@ struct device_drv { void (*thread_shutdown)(struct thr_info *); void (*thread_enable)(struct thr_info *); + /* What should be zeroed in this device when global zero stats is sent */ + void (*zero_stats)(struct cgpu_info *); + // Does it need to be free()d? bool copy; diff --git a/sgminer.c b/sgminer.c index e4194285..4c1090c4 100644 --- a/sgminer.c +++ b/sgminer.c @@ -4436,6 +4436,11 @@ void zero_stats(void) cgpu->diff_rejected = 0; cgpu->last_share_diff = 0; mutex_unlock(&hash_lock); + + /* Don't take any locks in the driver zero stats function, as + * it's called async from everything else and we don't want to + * deadlock. */ + cgpu->drv->zero_stats(cgpu); } } @@ -7512,6 +7517,7 @@ static void noop_detect(bool __maybe_unused hotplug) #define noop_flush_work noop_reinit_device #define noop_update_work noop_reinit_device #define noop_queue_full noop_get_stats +#define noop_zero_stats noop_reinit_device /* Fill missing driver drv functions with noops */ void fill_device_drv(struct device_drv *drv) @@ -7548,6 +7554,8 @@ void fill_device_drv(struct device_drv *drv) drv->update_work = &noop_update_work; if (!drv->queue_full) drv->queue_full = &noop_queue_full; + if (!drv->zero_stats) + drv->zero_stats = &noop_zero_stats; if (!drv->max_diff) drv->max_diff = 1; if (!drv->working_diff) From 8592226ad2ed1822e721499776b9508182f41fa4 Mon Sep 17 00:00:00 2001 From: ckolivas Date: Thu, 7 Nov 2013 11:01:22 +1100 Subject: [PATCH 04/28] Add a get and queue helper work function. --- miner.h | 3 +++ sgminer.c | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/miner.h b/miner.h index 248c9ca4..7a83f649 100644 --- a/miner.h +++ b/miner.h @@ -1385,7 +1385,10 @@ extern bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce extern bool submit_noffset_nonce(struct thr_info *thr, struct work *work, uint32_t nonce, int noffset); extern struct work *get_work(struct thr_info *thr, const int thr_id); +extern void __add_queued(struct cgpu_info *cgpu, struct work *work); extern struct work *get_queued(struct cgpu_info *cgpu); +extern void add_queued(struct cgpu_info *cgpu, struct work *work); +extern struct work *get_queue_work(struct thr_info *thr, struct cgpu_info *cgpu, int thr_id); extern struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen); extern struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen); extern struct work *clone_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen); diff --git a/sgminer.c b/sgminer.c index 4c1090c4..82ecb09f 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6310,6 +6310,13 @@ static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct de } while (!drv->queue_full(cgpu)); } +/* Add a work item to a cgpu's queued hashlist */ +void __add_queued(struct cgpu_info *cgpu, struct work *work) +{ + cgpu->queued_count++; + HASH_ADD_INT(cgpu->queued_work, id, work); +} + /* This function is for retrieving one work item from the unqueued pointer and * adding it to the hashtable of queued work. Code using this function must be * able to handle NULL as a return which implies there is no work available. */ @@ -6320,7 +6327,7 @@ struct work *get_queued(struct cgpu_info *cgpu) wr_lock(&cgpu->qlock); if (cgpu->unqueued_work) { work = cgpu->unqueued_work; - HASH_ADD_INT(cgpu->queued_work, id, work); + __add_queued(cgpu, work); cgpu->unqueued_work = NULL; } wr_unlock(&cgpu->qlock); @@ -6328,6 +6335,22 @@ struct work *get_queued(struct cgpu_info *cgpu) return work; } +void add_queued(struct cgpu_info *cgpu, struct work *work) +{ + wr_lock(&cgpu->qlock); + __add_queued(cgpu, work); + wr_unlock(&cgpu->qlock); +} + +/* Get fresh work and add it to cgpu's queued hashlist */ +struct work *get_queue_work(struct thr_info *thr, struct cgpu_info *cgpu, int thr_id) +{ + struct work *work = get_work(thr, thr_id); + + add_queued(cgpu, work); + return work; +} + /* This function is for finding an already queued work item in the * given que hashtable. Code using this function must be able * to handle NULL as a return which implies there is no matching work. From 2cea7ce4397466c1707bb817bc4210ee057f2346 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 31 Jan 2014 21:51:34 +1100 Subject: [PATCH 05/28] Discard work that is stale in the get_queued() function, returning NULL instead. --- sgminer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sgminer.c b/sgminer.c index 82ecb09f..f0c14004 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6327,9 +6327,15 @@ struct work *get_queued(struct cgpu_info *cgpu) wr_lock(&cgpu->qlock); if (cgpu->unqueued_work) { work = cgpu->unqueued_work; + if (unlikely(stale_work(work, false))) { + discard_work(work); + work = NULL; + goto out_unlock; + } __add_queued(cgpu, work); cgpu->unqueued_work = NULL; } +out_unlock: wr_unlock(&cgpu->qlock); return work; From ee7fb11cfb3e886ac2fae80f77335e22cf2050f6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 31 Jan 2014 21:57:50 +1100 Subject: [PATCH 06/28] Wake the global work scheduler when we remove a work item from the unqueued work pointer. --- sgminer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sgminer.c b/sgminer.c index f0c14004..43527efd 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6330,6 +6330,7 @@ struct work *get_queued(struct cgpu_info *cgpu) if (unlikely(stale_work(work, false))) { discard_work(work); work = NULL; + wake_gws(); goto out_unlock; } __add_queued(cgpu, work); From d5d34f216815f1bc347b89c82cf9e90fa5bc273a Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 31 Jan 2014 22:01:37 +1100 Subject: [PATCH 07/28] Remove the unqueued work reference when we discard work from get queued as well. --- sgminer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sgminer.c b/sgminer.c index 43527efd..25fe5160 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6332,11 +6332,10 @@ struct work *get_queued(struct cgpu_info *cgpu) work = NULL; wake_gws(); goto out_unlock; - } - __add_queued(cgpu, work); + } else + __add_queued(cgpu, work); cgpu->unqueued_work = NULL; } -out_unlock: wr_unlock(&cgpu->qlock); return work; From ab805ec146922044e0e8781e1f36c7c22070e510 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 31 Jan 2014 22:03:48 +1100 Subject: [PATCH 08/28] Remove wrong goto --- sgminer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sgminer.c b/sgminer.c index 25fe5160..1072232f 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6331,7 +6331,6 @@ struct work *get_queued(struct cgpu_info *cgpu) discard_work(work); work = NULL; wake_gws(); - goto out_unlock; } else __add_queued(cgpu, work); cgpu->unqueued_work = NULL; From 95ac0c435672d4a0bd2b3a1f067c7f2e78dbedf0 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 31 Jan 2014 22:16:11 +1100 Subject: [PATCH 09/28] Export the flush_queue function for use by drivers. --- miner.h | 1 + sgminer.c | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/miner.h b/miner.h index 7a83f649..0d2fd0f9 100644 --- a/miner.h +++ b/miner.h @@ -1396,6 +1396,7 @@ extern void __work_completed(struct cgpu_info *cgpu, struct work *work); extern int age_queued_work(struct cgpu_info *cgpu, double secs); extern void work_completed(struct cgpu_info *cgpu, struct work *work); extern struct work *take_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen); +extern void flush_queue(struct cgpu_info *cgpu); extern void hash_driver_work(struct thr_info *mythr); extern void hash_queued_work(struct thr_info *mythr); extern void _wlog(const char *str); diff --git a/sgminer.c b/sgminer.c index 1072232f..ff0242de 100644 --- a/sgminer.c +++ b/sgminer.c @@ -3766,8 +3766,6 @@ int restart_wait(struct thr_info *thr, unsigned int mstime) return rc; } - -static void flush_queue(struct cgpu_info *cgpu); static void *restart_thread(void __maybe_unused *arg) { @@ -6459,7 +6457,7 @@ struct work *take_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, return work; } -static void flush_queue(struct cgpu_info *cgpu) +void flush_queue(struct cgpu_info *cgpu) { struct work *work = NULL; From 6b246a59f3ffafe018abb80bd632c7f39a036bd3 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 1 Feb 2014 23:01:38 +1100 Subject: [PATCH 10/28] Handle interruptions to various select calls in util.c --- util.c | 13 +++++++++++-- util.h | 10 +++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/util.c b/util.c index c4e883c2..3f51ece9 100644 --- a/util.c +++ b/util.c @@ -1258,11 +1258,14 @@ static enum send_ret __stratum_send(struct pool *pool, char *s, ssize_t len) struct timeval timeout = {1, 0}; ssize_t sent; fd_set wd; - +retry: FD_ZERO(&wd); FD_SET(sock, &wd); - if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1) + if (select(sock + 1, NULL, &wd, NULL, &timeout) < 1) { + if (interrupted()) + goto retry; return SEND_SELECTFAIL; + } #ifdef __APPLE__ sent = send(pool->sock, s + ssent, len, SO_NOSIGPIPE); #elif WIN32 @@ -2184,6 +2187,7 @@ static bool setup_stratum_socket(struct pool *pool) applog(LOG_DEBUG, "Failed sock connect"); continue; } +retry: FD_ZERO(&rw); FD_SET(sockd, &rw); selret = select(sockd + 1, NULL, &rw, NULL, &tv_timeout); @@ -2199,6 +2203,8 @@ static bool setup_stratum_socket(struct pool *pool) break; } } + if (selret < 0 && interrupted()) + goto retry; CLOSESOCKET(sockd); applog(LOG_DEBUG, "Select timeout/failed connect"); continue; @@ -2619,6 +2625,7 @@ int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, co fd_set rd; char buf; +retry: fd = cgsem->pipefd[0]; FD_ZERO(&rd); FD_SET(fd, &rd); @@ -2631,6 +2638,8 @@ int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, co } if (likely(!ret)) return ETIMEDOUT; + if (interrupted()) + goto retry; quitfrom(1, file, func, line, "Failed to sem_timedwait errno=%d cgsem=0x%p", errno, cgsem); /* We don't reach here */ return 0; diff --git a/util.h b/util.h index 23199d86..2e5adf4f 100644 --- a/util.h +++ b/util.h @@ -24,6 +24,10 @@ { return (errno == ETIMEDOUT); } + static inline bool interrupted(void) + { + return (errno == EINTR); + } #elif defined WIN32 #include #include @@ -43,7 +47,11 @@ } static inline bool sock_timeout(void) { - return (errno == WSAETIMEDOUT); + return (WSAGetLastError() == WSAETIMEDOUT); + } + static inline bool interrupted(void) + { + return (WSAGetLastError() == WSAEINTR); } #ifndef SHUT_RDWR #define SHUT_RDWR SD_BOTH From 90cc93c6cc3a63fd5f061fcc02a0de9b90330246 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 1 Feb 2014 23:36:25 +1100 Subject: [PATCH 11/28] Add the ability to display a hexadecimal 32 bit unsigned integer to the API. --- api.c | 12 ++++++++++++ miner.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/api.c b/api.c index 64503963..f52c307a 100644 --- a/api.c +++ b/api.c @@ -729,6 +729,10 @@ static struct api_data *api_add_data_full(struct api_data *root, char *name, enu api_data->data = (void *)malloc(sizeof(uint32_t)); *((uint32_t *)(api_data->data)) = *((uint32_t *)data); break; + case API_HEX32: + api_data->data = (void *)malloc(sizeof(uint32_t)); + *((uint32_t *)(api_data->data)) = *((uint32_t *)data); + break; case API_UINT64: api_data->data = (void *)malloc(sizeof(uint64_t)); *((uint64_t *)(api_data->data)) = *((uint64_t *)data); @@ -815,6 +819,11 @@ struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *dat return api_add_data_full(root, name, API_UINT32, (void *)data, copy_data); } +struct api_data *api_add_hex32(struct api_data *root, char *name, uint32_t *data, bool copy_data) +{ + return api_add_data_full(root, name, API_HEX32, (void *)data, copy_data); +} + struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data) { return api_add_data_full(root, name, API_UINT64, (void *)data, copy_data); @@ -958,6 +967,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson case API_UINT32: sprintf(buf, "%"PRIu32, *((uint32_t *)(root->data))); break; + case API_HEX32: + snprintf(buf, sizeof(buf), "0x%08x", *((uint32_t *)(root->data))); + break; case API_UINT64: sprintf(buf, "%"PRIu64, *((uint64_t *)(root->data))); break; diff --git a/miner.h b/miner.h index 0d2fd0f9..908d2981 100644 --- a/miner.h +++ b/miner.h @@ -1441,6 +1441,7 @@ enum api_data_type { API_INT, API_UINT, API_UINT32, + API_HEX32, API_UINT64, API_DOUBLE, API_ELAPSED, @@ -1477,6 +1478,7 @@ extern struct api_data *api_add_uint16(struct api_data *root, char *name, uint16 extern struct api_data *api_add_int(struct api_data *root, char *name, int *data, bool copy_data); extern struct api_data *api_add_uint(struct api_data *root, char *name, unsigned int *data, bool copy_data); extern struct api_data *api_add_uint32(struct api_data *root, char *name, uint32_t *data, bool copy_data); +extern struct api_data *api_add_hex32(struct api_data *root, char *name, uint32_t *data, bool copy_data); extern struct api_data *api_add_uint64(struct api_data *root, char *name, uint64_t *data, bool copy_data); extern struct api_data *api_add_double(struct api_data *root, char *name, double *data, bool copy_data); extern struct api_data *api_add_elapsed(struct api_data *root, char *name, double *data, bool copy_data); From f7394ff1659b0bcaedf4fcc9761db82b873662f8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 2 Feb 2014 08:37:01 +1100 Subject: [PATCH 12/28] Check for more interrupted conditions in util.c and handle them gracefully. --- util.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 3f51ece9..b5420533 100644 --- a/util.c +++ b/util.c @@ -2596,19 +2596,24 @@ void _cgsem_post(cgsem_t *cgsem, const char *file, const char *func, const int l const char buf = 1; int ret; +retry: ret = write(cgsem->pipefd[1], &buf, 1); if (unlikely(ret == 0)) applog(LOG_WARNING, "Failed to write errno=%d" IN_FMT_FFL, errno, file, func, line); + else if (unlikely(ret < 0 && interrupted)) + goto retry; } void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int line) { char buf; int ret; - +retry: ret = read(cgsem->pipefd[0], &buf, 1); if (unlikely(ret == 0)) applog(LOG_WARNING, "Failed to read errno=%d" IN_FMT_FFL, errno, file, func, line); + else if (unlikely(ret < 0 && interrupted)) + goto retry; } void cgsem_destroy(cgsem_t *cgsem) @@ -2661,6 +2666,8 @@ void cgsem_reset(cgsem_t *cgsem) ret = select(fd + 1, &rd, NULL, NULL, &timeout); if (ret > 0) ret = read(fd, &buf, 1); + else if (unlikely(ret < 0 && interrupted())) + ret = 1; } while (ret > 0); } #else @@ -2679,8 +2686,12 @@ void _cgsem_post(cgsem_t *cgsem, const char *file, const char *func, const int l void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int line) { - if (unlikely(sem_wait(cgsem))) +retry: + if (unlikely(sem_wait(cgsem))) { + if (interrupted()) + goto retry; quitfrom(1, file, func, line, "Failed to sem_wait errno=%d cgsem=0x%p", errno, cgsem); + } } int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line) @@ -2692,12 +2703,15 @@ int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, co cgtime(&tv_now); timeval_to_spec(&ts_now, &tv_now); ms_to_timespec(&abs_timeout, ms); +retry: timeraddspec(&abs_timeout, &ts_now); ret = sem_timedwait(cgsem, &abs_timeout); if (ret) { if (likely(sock_timeout())) return ETIMEDOUT; + if (interrupted()) + goto retry; quitfrom(1, file, func, line, "Failed to sem_timedwait errno=%d cgsem=0x%p", errno, cgsem); } return 0; @@ -2709,6 +2723,8 @@ void cgsem_reset(cgsem_t *cgsem) do { ret = sem_trywait(cgsem); + if (unlikely(ret < 0 && interrupted())) + ret = 0; } while (!ret); } From 7731806417f5e23da175b3c94c375a36c8f2e97c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 2 Feb 2014 10:47:17 +1100 Subject: [PATCH 13/28] Add stratum share submission lag time to verbose information if it's over 1 second. --- sgminer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sgminer.c b/sgminer.c index ff0242de..60f21e47 100644 --- a/sgminer.c +++ b/sgminer.c @@ -260,6 +260,7 @@ struct stratum_share { struct work *work; int id; time_t sshare_time; + time_t sshare_sent; }; static struct stratum_share *stratum_shares = NULL; @@ -5471,6 +5472,15 @@ static void *stratum_sthread(void *userdata) free(sshare); pool->stale_shares++; total_stale++; + } else { + int ssdiff; + + sshare->sshare_sent = time(NULL); + ssdiff = sshare->sshare_sent - sshare->sshare_time; + if (ssdiff > 0) { + applog(LOG_INFO, "Pool %d stratum share submission lag time %d seconds", + pool->pool_no, ssdiff); + } } } From 9c59fe2c31b81c283d8dd99438aec36f946ed0be Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 2 Feb 2014 10:51:21 +1100 Subject: [PATCH 14/28] Add stratum share response lag time to verbose output if it's greater than 1 second. --- sgminer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sgminer.c b/sgminer.c index 60f21e47..37f3307a 100644 --- a/sgminer.c +++ b/sgminer.c @@ -5026,8 +5026,15 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, struct stratum_share *sshare) { struct work *work = sshare->work; + time_t now_t = time(NULL); char hashshow[64]; + int srdiff; + srdiff = now_t - sshare->sshare_sent; + if (srdiff > 0) { + applog(LOG_INFO, "Pool %d stratum share result lag time %d seconds", + work->pool->pool_no, srdiff); + } show_hash(work, hashshow); share_result(val, res_val, err_val, work, hashshow, false, ""); } From b5abf689384d6c240763dbe40daf273083634e92 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sun, 2 Feb 2014 10:54:15 +1100 Subject: [PATCH 15/28] Always show the stratum share lag time in debug mode. --- sgminer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sgminer.c b/sgminer.c index 37f3307a..58a12f5a 100644 --- a/sgminer.c +++ b/sgminer.c @@ -5031,7 +5031,7 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val, int srdiff; srdiff = now_t - sshare->sshare_sent; - if (srdiff > 0) { + if (opt_debug || srdiff > 0) { applog(LOG_INFO, "Pool %d stratum share result lag time %d seconds", work->pool->pool_no, srdiff); } @@ -5484,7 +5484,7 @@ static void *stratum_sthread(void *userdata) sshare->sshare_sent = time(NULL); ssdiff = sshare->sshare_sent - sshare->sshare_time; - if (ssdiff > 0) { + if (opt_debug || ssdiff > 0) { applog(LOG_INFO, "Pool %d stratum share submission lag time %d seconds", pool->pool_no, ssdiff); } From ae837a762f1dae0bdd7380ea9652f5a8f841fd2e Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 29 Jan 2014 10:23:53 +1100 Subject: [PATCH 16/28] API allow multiple commands/replies in one request --- api.c | 227 +++++++++++++++++++++++++++++++++++++++----------------- doc/API | 38 +++++++++- 2 files changed, 197 insertions(+), 68 deletions(-) diff --git a/api.c b/api.c index f52c307a..3dac1ade 100644 --- a/api.c +++ b/api.c @@ -29,12 +29,6 @@ #include "miner.h" #include "util.h" -// Big enough for largest API request -// data is truncated at the end of the last record that fits -// but still closed correctly for JSON -// Current code assumes it can socket send this size + JSON_CLOSE + JSON_END -#define SOCKBUFSIZ 65432 - // BUFSIZ varies on Windows and Linux #define TMPBUFSIZ 8192 @@ -126,7 +120,11 @@ static const char SEPARATOR = '|'; #define SEPSTR "|" static const char GPUSEP = ','; -static const char *APIVERSION = "3.0"; +#define CMDJOIN '+' +#define JOIN_CMD "CMD=" +#define BETWEEN_JOIN SEPSTR + +static const char *APIVERSION = "3.1"; static const char *DEAD = "Dead"; static const char *SICK = "Sick"; static const char *NOSTART = "NoStart"; @@ -215,9 +213,10 @@ static const char ISJSON = '{'; #define JSON_MINECOIN JSON1 _MINECOIN JSON2 #define JSON_DEBUGSET JSON1 _DEBUGSET JSON2 #define JSON_SETCONFIG JSON1 _SETCONFIG JSON2 -#define JSON_USBSTATS JSON1 _USBSTATS JSON2 + #define JSON_END JSON4 JSON5 #define JSON_END_TRUNCATED JSON4_TRUNCATED JSON5 +#define JSON_BETWEEN_JOIN "," static const char *JSON_COMMAND = "command"; static const char *JSON_PARAMETER = "parameter"; @@ -296,7 +295,7 @@ static const char *JSON_PARAMETER = "parameter"; #define MSG_INVNUM 84 #define MSG_CONPAR 85 #define MSG_CONVAL 86 -#define MSG_USBSTA 87 + #define MSG_NOUSTA 88 #define MSG_ZERMIS 94 @@ -418,7 +417,6 @@ struct CODES { { SEVERITY_SUCC, MSG_SETQUOTA,PARAM_SET, "Set pool '%s' to quota %d'" }, { SEVERITY_ERR, MSG_CONPAR, PARAM_NONE, "Missing config parameters 'name,N'" }, { SEVERITY_ERR, MSG_CONVAL, PARAM_STR, "Missing config value N for '%s,N'" }, - { SEVERITY_SUCC, MSG_USBSTA, PARAM_NONE, "USB Statistics" }, { SEVERITY_INFO, MSG_NOUSTA, PARAM_NONE, "No USB Statistics" }, { SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" }, { SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" }, @@ -1061,10 +1059,8 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p int i; - io_reinit(io_data); - if (isjson) - io_put(io_data, JSON_START JSON_STATUS); + io_add(io_data, JSON_START JSON_STATUS); for (i = 0; codes[i].severity != SEVERITY_FAIL; i++) { if (codes[i].code == messageid) { @@ -3045,44 +3041,45 @@ struct CMDS { char *name; void (*func)(struct io_data *, SOCKETTYPE, char *, bool, char); bool iswritemode; + bool joinable; } cmds[] = { - { "version", apiversion, false }, - { "config", minerconfig, false }, - { "devs", devstatus, false }, - { "pools", poolstatus, false }, - { "summary", summary, false }, - { "gpuenable", gpuenable, true }, - { "gpudisable", gpudisable, true }, - { "gpurestart", gpurestart, true }, - { "gpu", gpudev, false }, - { "gpucount", gpucount, false }, - { "switchpool", switchpool, true }, - { "addpool", addpool, true }, - { "poolpriority", poolpriority, true }, - { "poolquota", poolquota, true }, - { "enablepool", enablepool, true }, - { "disablepool", disablepool, true }, - { "removepool", removepool, true }, - { "gpuintensity", gpuintensity, true }, - { "gpumem", gpumem, true }, - { "gpuengine", gpuengine, true }, - { "gpufan", gpufan, true }, - { "gpuvddc", gpuvddc, true }, - { "save", dosave, true }, - { "quit", doquit, true }, - { "privileged", privileged, true }, - { "notify", notify, false }, - { "devdetails", devdetails, false }, - { "restart", dorestart, true }, - { "stats", minerstats, false }, - { "check", checkcommand, false }, - { "failover-only", failoveronly, true }, - { "coin", minecoin, false }, - { "debug", debugstate, true }, - { "setconfig", setconfig, true }, - { "zero", dozero, true }, - { "lockstats", lockstats, true }, - { NULL, NULL, false } + { "version", apiversion, false, true }, + { "config", minerconfig, false, true }, + { "devs", devstatus, false, true }, + { "pools", poolstatus, false, true }, + { "summary", summary, false, true }, + { "gpuenable", gpuenable, true, false }, + { "gpudisable", gpudisable, true, false }, + { "gpurestart", gpurestart, true, false }, + { "gpu", gpudev, false, false }, + { "gpucount", gpucount, false, true }, + { "switchpool", switchpool, true, false }, + { "addpool", addpool, true, false }, + { "poolpriority", poolpriority, true, false }, + { "poolquota", poolquota, true, false }, + { "enablepool", enablepool, true, false }, + { "disablepool", disablepool, true, false }, + { "removepool", removepool, true, false }, + { "gpuintensity", gpuintensity, true, false }, + { "gpumem", gpumem, true, false }, + { "gpuengine", gpuengine, true, false }, + { "gpufan", gpufan, true, false }, + { "gpuvddc", gpuvddc, true, false }, + { "save", dosave, true, false }, + { "quit", doquit, true, false }, + { "privileged", privileged, true, false }, + { "notify", notify, false, true }, + { "devdetails", devdetails, false, true }, + { "restart", dorestart, true, false }, + { "stats", minerstats, false, true }, + { "check", checkcommand, false, false }, + { "failover-only", failoveronly, true, false }, + { "coin", minecoin, false, true }, + { "debug", debugstate, true, false }, + { "setconfig", setconfig, true, false }, + { "zero", dozero, true, false }, + { "lockstats", lockstats, true, true }, + { NULL, NULL, false, false } }; static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group) @@ -3125,6 +3122,49 @@ static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, c io_close(io_data); } +static void head_join(struct io_data *io_data, char *cmdptr, bool isjson, bool *firstjoin) +{ + char *ptr; + + if (*firstjoin) { + if (isjson) + io_add(io_data, JSON0); + *firstjoin = false; + } else { + if (isjson) + io_add(io_data, JSON_BETWEEN_JOIN); + } + + // External supplied string + ptr = escape_string(cmdptr, isjson); + + if (isjson) { + io_add(io_data, JSON1); + io_add(io_data, ptr); + io_add(io_data, JSON2); + } else { + io_add(io_data, JOIN_CMD); + io_add(io_data, ptr); + io_add(io_data, BETWEEN_JOIN); + } + + if (ptr != cmdptr) + free(ptr); +} + +static void tail_join(struct io_data *io_data, bool isjson) +{ + if (io_data->close) { + io_add(io_data, JSON_CLOSE); + io_data->close = false; + } + + if (isjson) { + io_add(io_data, JSON_END); + io_add(io_data, JSON3); + } +} + static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson) { int count, sendc, res, tosend, len, n; @@ -3689,7 +3729,7 @@ void api(int api_thr_id) struct sockaddr_in cli; socklen_t clisiz; char cmdbuf[100]; - char *cmd = NULL; + char *cmd = NULL, *cmdptr, *cmdsbuf; char *param; bool addrok; char group; @@ -3697,7 +3737,7 @@ void api(int api_thr_id) json_t *json_config = NULL; json_t *json_val; bool isjson; - bool did; + bool did, isjoin, firstjoin; int i; SOCKETTYPE *apisock; @@ -3898,27 +3938,80 @@ void api(int api_thr_id) } if (!did) { - for (i = 0; cmds[i].name != NULL; i++) { - if (strcmp(cmd, cmds[i].name) == 0) { - sprintf(cmdbuf, "|%s|", cmd); - if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) - (cmds[i].func)(io_data, c, param, isjson, group); - else { - message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); - applog(LOG_DEBUG, "API: access denied to '%s' for '%s' command", connectaddr, cmds[i].name); + if (strchr(cmd, CMDJOIN)) { + firstjoin = isjoin = true; + // cmd + leading '|' + '\0' + cmdsbuf = malloc(strlen(cmd) + 2); + if (!cmdsbuf) + quithere(1, "OOM cmdsbuf"); + strcpy(cmdsbuf, "|"); + param = NULL; + } else + firstjoin = isjoin = false; + + cmdptr = cmd; + do { + did = false; + if (isjoin) { + cmd = strchr(cmdptr, CMDJOIN); + if (cmd) + *(cmd++) = '\0'; + if (!*cmdptr) + goto inochi; + } + + for (i = 0; cmds[i].name != NULL; i++) { + if (strcmp(cmdptr, cmds[i].name) == 0) { + sprintf(cmdbuf, "|%s|", cmdptr); + if (isjoin) { + if (strstr(cmdsbuf, cmdbuf)) { + did = true; + break; + } + strcat(cmdsbuf, cmdptr); + strcat(cmdsbuf, "|"); + head_join(io_data, cmdptr, isjson, &firstjoin); + if (!cmds[i].joinable) { + message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); + did = true; + tail_join(io_data, isjson); + break; + } + } + if (ISPRIVGROUP(group) || strstr(COMMANDS(group), cmdbuf)) + (cmds[i].func)(io_data, c, param, isjson, group); + else { + message(io_data, MSG_ACCDENY, 0, cmds[i].name, isjson); + applog(LOG_DEBUG, "API: access denied to '%s' for '%s' command", connectaddr, cmds[i].name); + } + + did = true; + if (!isjoin) + send_result(io_data, c, isjson); + else + tail_join(io_data, isjson); + break; } + } - send_result(io_data, c, isjson); - did = true; - break; + if (!did) { + if (isjoin) + head_join(io_data, cmdptr, isjson, &firstjoin); + message(io_data, MSG_INVCMD, 0, NULL, isjson); + if (isjoin) + tail_join(io_data, isjson); + else + send_result(io_data, c, isjson); } - } +inochi: + if (isjoin) + cmdptr = cmd; + } while (isjoin && cmdptr); } - if (!did) { - message(io_data, MSG_INVCMD, 0, NULL, isjson); + if (isjoin) send_result(io_data, c, isjson); - } + if (isjson && json_is_object(json_config)) json_decref(json_config); } diff --git a/doc/API b/doc/API index 9de48223..ae7587d0 100644 --- a/doc/API +++ b/doc/API @@ -109,6 +109,36 @@ The STATUS section is: This defaults to the sgminer version but is the value of --api-description if it was specified at runtime. +With API V3.1 you can also request multiple report replies in a single command +request +e.g. to request both summary and devs, the command would be summary+devs + +This is only available for report commands that don't need parameters, +and is not available for commands that change anything +Any parameters supplied will be ignored + +The extra formatting of the result is to have a section for each command +e.g. summary|STATUS=....|devs|STATUS=... +With JSON, each result is within a section of the command name +e.g. {"summary":{"STATUS":[{"STATUS":"S"...}],"SUMMARY":[...],"id":1}, + "devs":{"STATUS":[{"STATUS:"S"...}],"DEVS":[...],"id":1},"id":1} + +As before, if you supply bad JSON you'll just get a single 'E' STATUS section +in the old format, since it doesn't switch to using the new format until it +correctly processes the JSON and can match a '+' in the command + +If you request a command multiple times, e.g. devs+devs +you'll just get it once +If this results in only one command, it will still use the new layout +with just the one command + +If you request a command that can't be used due to requiring parameters, +a command that isn't a report, or an invalid command, you'll get an 'E' STATUS +for that one but it will still attempt to process all other commands supplied + +Blank/missing commands are ignore e.g. +devs++ +will just show 'devs' using the new layout + For API version 1.10 and later: The list of requests - a (*) means it requires privileged access - and replies: @@ -497,7 +527,13 @@ miner.php - an example web page to access the API Feature Changelog for external applications using the API: -API V3.0 (cgminer v3.9.1) +API V3.1 (cgminer v3.12.1) + +Multiple report request command with '+' e.g. summary+devs + +--------- + +API V3.0 (cgminer v3.11.0) Allow unlimited size replies From a1844cdf442f0be135c4f2c2e605fef6e30116a9 Mon Sep 17 00:00:00 2001 From: Kano Date: Wed, 29 Jan 2014 11:48:39 +1100 Subject: [PATCH 17/28] API-README correct new text format documentation --- doc/API | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/API b/doc/API index ae7587d0..c39f6385 100644 --- a/doc/API +++ b/doc/API @@ -118,7 +118,7 @@ and is not available for commands that change anything Any parameters supplied will be ignored The extra formatting of the result is to have a section for each command -e.g. summary|STATUS=....|devs|STATUS=... +e.g. CMD=summary|STATUS=....|CMD=devs|STATUS=... With JSON, each result is within a section of the command name e.g. {"summary":{"STATUS":[{"STATUS":"S"...}],"SUMMARY":[...],"id":1}, "devs":{"STATUS":[{"STATUS:"S"...}],"DEVS":[...],"id":1},"id":1} From 88c7720caf2d3d146a2a38f775767719dadb5141 Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Mon, 3 Feb 2014 08:13:14 -0500 Subject: [PATCH 18/28] These may not be longs (eg: OSX)... fo a safe cast to ensure. --- api.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api.c b/api.c index 3dac1ade..425c242f 100644 --- a/api.c +++ b/api.c @@ -1005,9 +1005,9 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR); break; case API_TIMEVAL: - sprintf(buf, "%ld.%06ld", - ((struct timeval *)(root->data))->tv_sec, - ((struct timeval *)(root->data))->tv_usec); + snprintf(buf, sizeof(buf), "%ld.%06ld", + (long)((struct timeval *)(root->data))->tv_sec, + (long)((struct timeval *)(root->data))->tv_usec); break; case API_TEMP: sprintf(buf, "%.2f", *((float *)(root->data))); From f8b9e41f28b6a63dc38968dc3eb0f060cf5f1a9e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 6 Feb 2014 14:00:58 +1100 Subject: [PATCH 19/28] Check for when errno is set on windows as well as the windows variant for errors. --- util.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/util.h b/util.h index 2e5adf4f..07ec3fc9 100644 --- a/util.h +++ b/util.h @@ -41,17 +41,19 @@ extern char *WSAErrorMsg(void); #define SOCKERRMSG WSAErrorMsg() + /* Check for windows variants of the errors as well as when ming + * decides to wrap the error into the errno equivalent. */ static inline bool sock_blocks(void) { - return (WSAGetLastError() == WSAEWOULDBLOCK); + return (WSAGetLastError() == WSAEWOULDBLOCK || errno == EAGAIN); } static inline bool sock_timeout(void) { - return (WSAGetLastError() == WSAETIMEDOUT); + return (WSAGetLastError() == WSAETIMEDOUT || errno == ETIMEDOUT); } static inline bool interrupted(void) { - return (WSAGetLastError() == WSAEINTR); + return (WSAGetLastError() == WSAEINTR || errno == EINTR); } #ifndef SHUT_RDWR #define SHUT_RDWR SD_BOTH From 5dad99caf61cd159ece97e95395dc925ea0203b1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 6 Feb 2014 16:08:24 +1100 Subject: [PATCH 20/28] Give device info with share above target message. --- sgminer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sgminer.c b/sgminer.c index 58a12f5a..5d4dc9de 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6053,7 +6053,8 @@ bool submit_tested_work(struct thr_info *thr, struct work *work) update_work_stats(thr, work); if (!fulltest(work->hash, work->target)) { - applog(LOG_INFO, "Share above target"); + applog(LOG_INFO, "%s %d: Share above target", thr->cgpu->drv->name, + thr->cgpu->device_id); return false; } work_out = copy_work(work); From 117c032b92cdcd321350ff91c1693fc37b3ce3c5 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 7 Feb 2014 01:00:35 +1100 Subject: [PATCH 21/28] Slowly remove work even if it's not being used to keep the getwork counter incrementing even if work is not used and as a test that pools are still working. --- sgminer.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sgminer.c b/sgminer.c index 5d4dc9de..abb82e59 100644 --- a/sgminer.c +++ b/sgminer.c @@ -5761,6 +5761,9 @@ static struct work *hash_pop(void) /* Signal hash_pop again in case there are mutliple hash_pop waiters */ pthread_cond_signal(&getq->cond); + + /* Keep track of last getwork grabbed */ + last_getwork = time(NULL); mutex_unlock(stgd_lock); return work; @@ -5920,7 +5923,6 @@ struct work *get_work(struct thr_info *thr, const int thr_id) wake_gws(); } } - last_getwork = time(NULL); applog(LOG_DEBUG, "Got work from get queue to get work for thread %d", thr_id); work->thr_id = thr_id; @@ -8155,8 +8157,14 @@ begin_bench: } mutex_unlock(stgd_lock); - if (ts > max_staged) + if (ts > max_staged) { + /* Keeps slowly generating work even if it's not being + * used to keep last_getwork incrementing and to see + * if pools are still alive. */ + work = hash_pop(); + discard_work(work); continue; + } work = make_work(); From aca8a58f2e2605c476652ad0d501df3caaa630b1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 7 Feb 2014 08:33:00 +1100 Subject: [PATCH 22/28] Only show one decimal place if pool diff is not an integer. --- util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.c b/util.c index b5420533..67a5ec29 100644 --- a/util.c +++ b/util.c @@ -1657,7 +1657,7 @@ static bool parse_diff(struct pool *pool, json_t *val) if ((double)idiff == diff) applog(LOG_NOTICE, "%s difficulty changed to %d", pool->poolname ,idiff); else - applog(LOG_NOTICE, "%s difficulty changed to %f", pool->poolname, diff); + applog(LOG_NOTICE, "%s difficulty changed to %.1f", pool->poolname, diff); } else applog(LOG_DEBUG, "%s difficulty set to %f", pool->poolname, diff); From 26c4be818a34d449534a32ab30e332cc97d70ed9 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 7 Feb 2014 08:48:40 +1100 Subject: [PATCH 23/28] Show device info in noffset nonce share above target message. --- sgminer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sgminer.c b/sgminer.c index abb82e59..753a3141 100644 --- a/sgminer.c +++ b/sgminer.c @@ -6095,7 +6095,8 @@ bool submit_noffset_nonce(struct thr_info *thr, struct work *work_in, uint32_t n ret = true; update_work_stats(thr, work); if (!fulltest(work->hash, work->target)) { - applog(LOG_INFO, "Share above target"); + applog(LOG_INFO, "%s %d: Share above target", thr->cgpu->drv->name, + thr->cgpu->device_id); goto out; } submit_work_async(work); From 7134cd70501108f1f5c63ed0b5765dd665e94996 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 7 Feb 2014 13:28:05 +1100 Subject: [PATCH 24/28] Add debug output when get_work() is blocked for an extended period and add grace time to the device's last valid work to prevent false positives for device failure. --- sgminer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sgminer.c b/sgminer.c index 753a3141..f3587f91 100644 --- a/sgminer.c +++ b/sgminer.c @@ -5912,9 +5912,11 @@ static void gen_stratum_work(struct pool *pool, struct work *work) struct work *get_work(struct thr_info *thr, const int thr_id) { struct work *work = NULL; + time_t diff_t; thread_reportout(thr); applog(LOG_DEBUG, "Popping work from get queue to get work"); + diff_t = time(NULL); while (!work) { work = hash_pop(); if (stale_work(work, false)) { @@ -5923,6 +5925,14 @@ struct work *get_work(struct thr_info *thr, const int thr_id) wake_gws(); } } + diff_t = time(NULL) - diff_t; + /* Since this is a blocking function, we need to add grace time to + * the device's last valid work to not make outages appear to be + * device failures. */ + if (diff_t > 0) { + applog(LOG_DEBUG, "Get work blocked for %d seconds", (int)diff_t); + thr->cgpu->last_device_valid_work += diff_t; + } applog(LOG_DEBUG, "Got work from get queue to get work for thread %d", thr_id); work->thr_id = thr_id; From ac3f6c5705decdce8a982bc067fd50ec1112a6e2 Mon Sep 17 00:00:00 2001 From: Noel Maersk Date: Sun, 16 Feb 2014 15:13:42 +0200 Subject: [PATCH 25/28] misc: add note about ports from ckolivas/cgminer. --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index a96f0ccf..9315cae4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,7 @@ ## Version 4.2.0 - TBA -* Forward-port changes from `ckolivas/cgminer` up to 3.12.0. +* Forward-port changes from `ckolivas/cgminer` up to 3.12.1. ## Version 4.1.0 - 7th February 2014 From b9b3abe264bd5d1e88326a5c961ca9abef90cad4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 8 Feb 2014 07:42:53 +1100 Subject: [PATCH 26/28] Make the pthread cond wait in the getwork scheduler a timed wait in case we miss a wakeup. --- sgminer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sgminer.c b/sgminer.c index f3587f91..c1c4774c 100644 --- a/sgminer.c +++ b/sgminer.c @@ -8143,6 +8143,8 @@ begin_bench: int ts, max_staged = opt_queue; struct pool *pool, *cp; bool lagging = false; + struct timespec then; + struct timeval now; struct work *work; if (opt_work_update) @@ -8155,6 +8157,10 @@ begin_bench: if (!pool_localgen(cp) && !staged_rollable) max_staged += mining_threads; + cgtime(&now); + then.tv_sec = now.tv_sec + 2; + then.tv_nsec = now.tv_usec * 1000; + mutex_lock(stgd_lock); ts = __total_staged(); @@ -8163,7 +8169,7 @@ begin_bench: /* Wait until hash_pop tells us we need to create more work */ if (ts > max_staged) { - pthread_cond_wait(&gws_cond, stgd_lock); + pthread_cond_timedwait(&gws_cond, stgd_lock, &then); ts = __total_staged(); } mutex_unlock(stgd_lock); From a8255243254baeee796eae28c1c4b328b7b57d92 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 8 Feb 2014 11:09:11 +1100 Subject: [PATCH 27/28] We shouldn't block on no work situations directly from the getwork scheduler itself. --- sgminer.c | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/sgminer.c b/sgminer.c index c1c4774c..d287e182 100644 --- a/sgminer.c +++ b/sgminer.c @@ -5713,29 +5713,35 @@ static void pool_resus(struct pool *pool) applog(LOG_INFO, "%s alive", pool->poolname); } -static struct work *hash_pop(void) +/* If this is called non_blocking, it will return NULL for work so that must + * be handled. */ +static struct work *hash_pop(bool blocking) { struct work *work = NULL, *tmp; int hc; mutex_lock(stgd_lock); - while (!HASH_COUNT(staged_work)) { - struct timespec then; - struct timeval now; - int rc; + if (!HASH_COUNT(staged_work)) { + if (!blocking) + goto out_unlock; + do { + struct timespec then; + struct timeval now; + int rc; - cgtime(&now); - then.tv_sec = now.tv_sec + 10; - then.tv_nsec = now.tv_usec * 1000; - pthread_cond_signal(&gws_cond); - rc = pthread_cond_timedwait(&getq->cond, stgd_lock, &then); - /* Check again for !no_work as multiple threads may be - * waiting on this condition and another may set the - * bool separately. */ - if (rc && !no_work) { - no_work = true; - applog(LOG_WARNING, "Waiting for work to be available from pools."); - } + cgtime(&now); + then.tv_sec = now.tv_sec + 10; + then.tv_nsec = now.tv_usec * 1000; + pthread_cond_signal(&gws_cond); + rc = pthread_cond_timedwait(&getq->cond, stgd_lock, &then); + /* Check again for !no_work as multiple threads may be + * waiting on this condition and another may set the + * bool separately. */ + if (rc && !no_work) { + no_work = true; + applog(LOG_WARNING, "Waiting for work to be available from pools."); + } + } while (!HASH_COUNT(staged_work)); } if (no_work) { @@ -5764,6 +5770,7 @@ static struct work *hash_pop(void) /* Keep track of last getwork grabbed */ last_getwork = time(NULL); +out_unlock: mutex_unlock(stgd_lock); return work; @@ -5918,7 +5925,7 @@ struct work *get_work(struct thr_info *thr, const int thr_id) applog(LOG_DEBUG, "Popping work from get queue to get work"); diff_t = time(NULL); while (!work) { - work = hash_pop(); + work = hash_pop(true); if (stale_work(work, false)) { discard_work(work); work = NULL; @@ -8178,8 +8185,9 @@ begin_bench: /* Keeps slowly generating work even if it's not being * used to keep last_getwork incrementing and to see * if pools are still alive. */ - work = hash_pop(); - discard_work(work); + work = hash_pop(false); + if (work) + discard_work(work); continue; } From edc94b07ced37aaa071f7337ea92a045e3d579ca Mon Sep 17 00:00:00 2001 From: Noel Maersk Date: Wed, 19 Feb 2014 18:21:32 +0200 Subject: [PATCH 28/28] misc: update NEWS with what's been ported from ckolivas/cgminer. --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 9315cae4..b8975f4c 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,7 +2,7 @@ ## Version 4.2.0 - TBA -* Forward-port changes from `ckolivas/cgminer` up to 3.12.1. +* Forward-port changes from `ckolivas/cgminer` up to 3.12.3. ## Version 4.1.0 - 7th February 2014