Browse Source

Merge branch 'cg_merges_20121125' into bfgminer

Luke Dashjr 13 years ago
parent
commit
a746aa88f3
11 changed files with 178 additions and 116 deletions
  1. 42 0
      NEWS
  2. 3 6
      driver-icarus.c
  3. 2 3
      driver-modminer.c
  4. 19 41
      driver-opencl.c
  5. 1 2
      driver-x6500.c
  6. 3 3
      driver-ztex.c
  7. 1 1
      findnonce.c
  8. 30 2
      libztex.c
  9. 68 47
      miner.c
  10. 7 8
      miner.h
  11. 2 3
      util.c

+ 42 - 0
NEWS

@@ -1,5 +1,47 @@
 BFGMiner Version 2.10.0 - Future
 
+- fixes target calc for mips openwrt
+- openwrt needs roundl
+- Get rid of unused last_work in opencl thread data.
+- Do away with the flaky free_work api in the driver code which would often lose
+the work data in opencl and simply flush it before exiting the opencl scanhash.
+- Use base_work for comparison just for cleanness in __copy_work
+- Remove all static work structs, using the make and free functions.
+- Add pool no. to stale share detected message.
+- Add info about which pool share became stale while resubmitting.
+-b Copy the work on opencl_free_work
+- Add an extra slot in the max backlog for ztex to minimise dupes.
+- Do not use or count the getworks submitted which are simply testing that pools
+are still up. This was increasing share leakage and making stats not reflect
+real work.
+- Track all dynamically allocated memory within the work struct by copying work
+structs in a common place, creating freshly allocated heap ram for all arrays
+within the copied struct. Clear all work structs from the same place to ensure
+memory does not leak from arrays within the struct. Convert the gbt coinbase and
+stratum strings within the work struct to heap ram. This will allow arbitrary
+lengths without an upper limit for the strings, preventing the overflows that
+happen with GBT.
+- libztex: Work around ZTEX USB firmware bug exposed by the FreeBSD libusb
+- opencl: Use new dev_error function for REASON_DEV_NOSTART
+- Provide rudimentary support for the balancing failover strategies with stratum
+and GBT by switching pools silently on getwork requests.
+- Convert remaining modminer and bfl uses of usleep to nmsleep.
+- Convert libztex to nmsleep where possible.
+- Convert unreliable usleep calls to nmsleep calls in ztex driver.
+- Support workid for block submission on GBT pools that use it.
+- Provide rudimentary support for literal ipv6 addresses when parsing stratum
+URLs.
+- Work around libcurl cflags not working on hacked up mingw installations on
+windows.
+- Only increase gpu engine speed by a larger step if the temperature is below
+hysteresis instead of increasing it to max speed.
+- Convert pool not responding and pool alive message on backup pools to verbose
+level only since they mean a single failed getwork.
+- Update work block on the longpoll work item before calling restart threads to
+ensure all work but the longpoll work item gets discarded when we call
+discard_stale from restart_threads.
+- Do not attempt to remove the stratum share hash after unsuccessful submission
+since it may already be removed by clear_stratum_shares.
 - Use stratum block change from backup pools as an alternative to longpoll for
 pools that don't support LP.
 - Round some more static string arrays to 4 byte boundaries.

+ 3 - 6
driver-icarus.c

@@ -860,8 +860,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	if (state->firstrun) {
 		state->firstrun = false;
-		clear_work(&state->last_work);
-		workcpy(&state->last_work, work);
+		__copy_work(&state->last_work, work);
 		return 0;
 	}
 
@@ -869,8 +868,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	// aborted before becoming idle, get new work
 	if (ret == ICA_GETS_TIMEOUT || ret == ICA_GETS_RESTART) {
-		clear_work(&state->last_work);
-		workcpy(&state->last_work, work);
+		__copy_work(&state->last_work, work);
 		// ONLY up to just when it aborted
 		// We didn't read a reply so we don't subtract ICARUS_READ_TIME
 		estimate_hashes = ((double)(elapsed.tv_sec)
@@ -894,8 +892,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	curr_hw_errors = icarus->hw_errors;
 	submit_nonce(thr, &state->last_work, nonce);
 	was_hw_error = (curr_hw_errors > icarus->hw_errors);
-	clear_work(&state->last_work);
-	workcpy(&state->last_work, work);
+	__copy_work(&state->last_work, work);
 
 	// Force a USB close/reopen on any hw error
 	if (was_hw_error)

+ 2 - 3
driver-modminer.c

@@ -725,9 +725,8 @@ modminer_scanhash(struct thr_info*thr, struct work*work, int64_t __maybe_unused
 		state->work_running = true;
 
 	if (startwork) {
-		clear_work(&state->last_work);
-		memcpy(&state->last_work, &state->running_work, sizeof(state->last_work));
-		workcpy(&state->running_work, work);
+		__copy_work(&state->last_work, &state->running_work);
+		__copy_work(&state->running_work, work);
 		if (!modminer_start_work(thr))
 			return -1;
 	}

+ 19 - 41
driver-opencl.c

@@ -1530,8 +1530,6 @@ get_opencl_api_extra_device_status(struct cgpu_info *gpu)
 struct opencl_thread_data {
 	cl_int (*queue_kernel_parameters)(_clState *, dev_blk_ctx *, cl_uint);
 	uint32_t *res;
-	struct work *last_work;
-	struct work _last_work;
 };
 
 static uint32_t *blank_res;
@@ -1675,20 +1673,6 @@ static bool opencl_thread_init(struct thr_info *thr)
 	return true;
 }
 
-static void opencl_free_work(struct thr_info *thr, struct work *work)
-{
-	const int thr_id = thr->id;
-	struct opencl_thread_data *thrdata = thr->cgpu_data;
-	_clState *clState = clStates[thr_id];
-
-	clFinish(clState->commandQueue);
-
-	if (thrdata->res[FOUND]) {
-		thrdata->last_work = &thrdata->_last_work;
-		clear_work(thrdata->last_work);
-		workcpy(thrdata->last_work, work);
-	}
-}
 
 static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work)
 {
@@ -1718,9 +1702,6 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	size_t localThreads[1] = { clState->wsize };
 	int64_t hashes;
 
-	/* This finish flushes the readbuffer set with CL_FALSE later */
-	clFinish(clState->commandQueue);
-
 	/* Windows' timer resolution is only 15ms so oversample 5x */
 	if (gpu->dynamic && (++gpu->intervals * dynamic_us) > 70000) {
 		struct timeval tv_gpuend;
@@ -1743,27 +1724,6 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	if (hashes > gpu->max_hashes)
 		gpu->max_hashes = hashes;
 
-	/* FOUND entry is used as a counter to say how many nonces exist */
-	if (thrdata->res[FOUND]) {
-		/* Clear the buffer again */
-		status = clEnqueueWriteBuffer(clState->commandQueue, clState->outputBuffer, CL_FALSE, 0,
-				BUFFERSIZE, blank_res, 0, NULL, NULL);
-		if (unlikely(status != CL_SUCCESS)) {
-			applog(LOG_ERR, "Error: clEnqueueWriteBuffer failed.");
-			return -1;
-		}
-		if (unlikely(thrdata->last_work)) {
-			applog(LOG_DEBUG, "GPU %d found something in last work?", gpu->device_id);
-			postcalc_hash_async(thr, thrdata->last_work, thrdata->res);
-			thrdata->last_work = NULL;
-		} else {
-			applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id);
-			postcalc_hash_async(thr, work, thrdata->res);
-		}
-		memset(thrdata->res, 0, BUFFERSIZE);
-		clFinish(clState->commandQueue);
-	}
-
 	status = thrdata->queue_kernel_parameters(clState, &work->blk, globalThreads[0]);
 	if (unlikely(status != CL_SUCCESS)) {
 		applog(LOG_ERR, "Error: clSetKernelArg of all params failed.");
@@ -1796,6 +1756,25 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
 	 * than enough to prevent repeating work */
 	work->blk.nonce += gpu->max_hashes;
 
+	/* This finish flushes the readbuffer set with CL_FALSE in clEnqueueReadBuffer */
+	clFinish(clState->commandQueue);
+
+	/* FOUND entry is used as a counter to say how many nonces exist */
+	if (thrdata->res[FOUND]) {
+		/* Clear the buffer again */
+		status = clEnqueueWriteBuffer(clState->commandQueue, clState->outputBuffer, CL_FALSE, 0,
+				BUFFERSIZE, blank_res, 0, NULL, NULL);
+		if (unlikely(status != CL_SUCCESS)) {
+			applog(LOG_ERR, "Error: clEnqueueWriteBuffer failed.");
+			return -1;
+		}
+		applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id);
+		postcalc_hash_async(thr, work, thrdata->res);
+		memset(thrdata->res, 0, BUFFERSIZE);
+		/* This finish flushes the writebuffer set with CL_FALSE in clEnqueueWriteBuffer */
+		clFinish(clState->commandQueue);
+	}
+
 	return hashes;
 }
 
@@ -1821,7 +1800,6 @@ struct device_api opencl_api = {
 	.get_api_extra_device_status = get_opencl_api_extra_device_status,
 	.thread_prepare = opencl_thread_prepare,
 	.thread_init = opencl_thread_init,
-	.free_work = opencl_free_work,
 	.prepare_work = opencl_prepare_work,
 	.scanhash = opencl_scanhash,
 	.thread_shutdown = opencl_thread_shutdown,

+ 1 - 2
driver-x6500.c

@@ -684,8 +684,7 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 	dclk_preUpdate(&fpga->dclk);
 	dclk_updateFreq(&fpga->dclk, x6500_dclk_change_clock, thr);
 
-	clear_work(&fpga->prevwork);
-	workcpy(&fpga->prevwork, work);
+	__copy_work(&fpga->prevwork, work);
 
 	return hashes;
 }

+ 3 - 3
driver-ztex.c

@@ -219,9 +219,9 @@ static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 		return -1;
 	}
 	memset(lastnonce, 0, sizeof(uint32_t)*ztex->numNonces);
-	
-	backlog_max = ztex->numNonces * (1 + ztex->extraSolutions);
-	backlog_max *= 2;
+
+	/* Add an extra slot for detecting dupes that lie around */
+	backlog_max = ztex->numNonces * (2 + ztex->extraSolutions);
 	backlog = malloc(sizeof(uint32_t) * backlog_max);
 	if (backlog == NULL) {
 		applog(LOG_ERR, "%s: failed to allocate backlog[%d]", ztex->repr, backlog_max);

+ 1 - 1
findnonce.c

@@ -180,7 +180,7 @@ void postcalc_hash_async(struct thr_info *thr, struct work *work, uint32_t *res)
 	}
 
 	pcd->thr = thr;
-	workcpy(&pcd->work, work);
+	__copy_work(&pcd->work, work);
 	memcpy(&pcd->res, res, BUFFERSIZE);
 
 	if (pthread_create(&pcd->pth, NULL, postcalc_hash, (void *)pcd)) {

+ 30 - 2
libztex.c

@@ -416,6 +416,7 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 	struct libztex_device *newdev;
 	int i, cnt, err;
 	unsigned char buf[64];
+	uint16_t langid;
 
 	newdev = malloc(sizeof(struct libztex_device));
 	dclk_prepare(&newdev->dclk);
@@ -444,13 +445,40 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 		return err;
 	}
 
-	cnt = libusb_get_string_descriptor_ascii (newdev->hndl, newdev->descriptor.iSerialNumber, newdev->snString,
-	                                          LIBZTEX_SNSTRING_LEN + 1);
+	/* We open code string descriptor retrieval and ASCII decoding here
+	 * in order to work around that libusb_get_string_descriptor_ascii()
+	 * in the FreeBSD libusb implementation hits a bug in ZTEX firmware,
+	 * where the device returns more bytes than requested, causing babble,
+	 * which makes FreeBSD return an error to us.
+	 *
+	 * Avoid the mess by doing it manually the same way as libusb-1.0.
+	 */
+
+	cnt = libusb_control_transfer(newdev->hndl, LIBUSB_ENDPOINT_IN,
+	    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | 0,
+	    0x0000, buf, sizeof(buf), 1000);
+	if (unlikely(cnt < 0)) {
+		applog(LOG_ERR, "Ztex check device: Failed to read device LANGIDs with err %d", cnt);
+		return cnt;
+	}
+
+	langid = libusb_le16_to_cpu(((uint16_t *)buf)[1]);
+
+	cnt = libusb_control_transfer(newdev->hndl, LIBUSB_ENDPOINT_IN,
+	    LIBUSB_REQUEST_GET_DESCRIPTOR,
+	    (LIBUSB_DT_STRING << 8) | newdev->descriptor.iSerialNumber,
+	    langid, buf, sizeof(buf), 1000);
 	if (unlikely(cnt < 0)) {
 		applog(LOG_ERR, "Ztex check device: Failed to read device snString with err %d", cnt);
 		return cnt;
 	}
 
+	/* num chars = (all bytes except bLength and bDescriptorType) / 2 */
+	for (i = 0; i <= (cnt - 2) / 2 && i < sizeof(newdev->snString)-1; i++)
+		newdev->snString[i] = buf[2 + i*2];
+
+	newdev->snString[i] = 0;
+
 	cnt = libusb_control_transfer(newdev->hndl, 0xc0, 0x22, 0, 0, buf, 40, 500);
 	if (unlikely(cnt < 0)) {
 		applog(LOG_ERR, "Ztex check device: Failed to read ztex descriptor with err %d", cnt);

+ 68 - 47
miner.c

@@ -281,7 +281,7 @@ int swork_id;
 struct stratum_share {
 	UT_hash_handle hh;
 	bool block;
-	struct work work;
+	struct work *work;
 	int id;
 };
 
@@ -2811,7 +2811,7 @@ static char *prepare_rpc_req(struct work *work, enum pool_protocol proto, const
 {
 	char *rpc_req;
 
-	clear_work(work);
+	clean_work(work);
 	switch (proto) {
 		case PLP_GETWORK:
 			work->getwork_mode = GETWORK_MODE_POOL;
@@ -2953,8 +2953,17 @@ static struct work *make_work(void)
 	return work;
 }
 
-void clear_work(struct work *work)
+/* This is the central place all work that is about to be retired should be
+ * cleaned to remove any dynamically allocated arrays within the struct */
+void clean_work(struct work *work)
 {
+	free(work->job_id);
+	free(work->nonce2);
+	free(work->ntime);
+	work->job_id = NULL;
+	work->nonce2 = NULL;
+	work->ntime = NULL;
+
 	if (work->tmpl) {
 		struct pool *pool = work->pool;
 		mutex_lock(&pool->pool_lock);
@@ -2969,9 +2978,11 @@ void clear_work(struct work *work)
 	}
 }
 
-static void free_work(struct work *work)
+/* All dynamically allocated work structs should be freed here to not leak any
+ * ram from arrays allocated within the work struct */
+void free_work(struct work *work)
 {
-	clear_work(work);
+	clean_work(work);
 	free(work);
 }
 
@@ -3312,11 +3323,20 @@ static void roll_work(struct work *work)
 	work->id = total_work++;
 }
 
-void workcpy(struct work *dest, const struct work *work)
+/* Duplicates any dynamically allocated arrays within the work struct to
+ * prevent a copied work struct from freeing ram belonging to another struct */
+void __copy_work(struct work *work, struct work *base_work)
 {
-	memcpy(dest, work, sizeof(*dest));
+	clean_work(work);
+	memcpy(work, base_work, sizeof(struct work));
+	if (base_work->job_id)
+		work->job_id = strdup(base_work->job_id);
+	if (base_work->nonce2)
+		work->nonce2 = strdup(base_work->nonce2);
+	if (base_work->ntime)
+		work->ntime = strdup(base_work->ntime);
 
-	if (work->tmpl) {
+	if (base_work->tmpl) {
 		struct pool *pool = work->pool;
 		mutex_lock(&pool->pool_lock);
 		++*work->tmpl_refcount;
@@ -3324,11 +3344,21 @@ void workcpy(struct work *dest, const struct work *work)
 	}
 }
 
+/* Generates a copy of an existing work struct, creating fresh heap allocations
+ * for all dynamically allocated arrays within the struct */
+struct work *copy_work(struct work *base_work)
+{
+	struct work *work = make_work();
+
+ 	__copy_work(work, base_work);
+
+	return work;
+}
+
 static struct work *make_clone(struct work *work)
 {
-	struct work *work_clone = make_work();
+	struct work *work_clone = copy_work(work);
 
-	workcpy(work_clone, work);
 	work_clone->clone = true;
 	gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL);
 	work_clone->longpoll = false;
@@ -3392,7 +3422,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work);
 static void *get_work_thread(void *userdata)
 {
 	struct workio_cmd *wc = (struct workio_cmd *)userdata;
-	struct work *ret_work= NULL;
+	struct work *ret_work = NULL;
 	struct curl_ent *ce = NULL;
 	struct pool *pool;
 
@@ -3630,16 +3660,16 @@ next_submit:
 	if (stale_work(work, true)) {
 		work->stale = true;
 		if (unlikely(!list_empty(&submit_waiting))) {
-			applog(LOG_WARNING, "Stale share detected while queued submissions are waiting, discarding");
+			applog(LOG_WARNING, "Pool %d stale share detected while queued submissions are waiting, discarding", pool->pool_no);
 			submit_discard_share(work);
 			goto out;
 		}
 		if (opt_submit_stale)
-			applog(LOG_NOTICE, "Stale share detected, submitting as user requested");
+			applog(LOG_NOTICE, "Pool %d stale share detected, submitting as user requested", pool->pool_no);
 		else if (pool->submit_old)
-			applog(LOG_NOTICE, "Stale share detected, submitting as pool requested");
+			applog(LOG_NOTICE, "Pool %d stale share detected, submitting as pool requested", pool->pool_no);
 		else {
-			applog(LOG_NOTICE, "Stale share detected, discarding");
+			applog(LOG_NOTICE, "Pool %d stale share detected, discarding", pool->pool_no);
 			submit_discard_share(work);
 			goto out;
 		}
@@ -3652,7 +3682,7 @@ next_submit:
 		char *noncehex;
 		char s[1024];
 
-		workcpy(&sshare->work, work);
+		sshare->work = copy_work(work);
 		mutex_lock(&sshare_lock);
 		/* Give the stratum share a unique id */
 		sshare->id = swork_id++;
@@ -3688,28 +3718,28 @@ next_submit:
 		if ((!work->stale) && stale_work(work, true)) {
 			work->stale = true;
 			if (opt_submit_stale)
-				applog(LOG_NOTICE, "Share become stale during submission failure, will retry as user requested");
+				applog(LOG_NOTICE, "Pool %d share became stale during submission failure, will retry as user requested", pool->pool_no);
 			else if (pool->submit_old)
-				applog(LOG_NOTICE, "Share become stale during submission failure, will retry as pool requested");
+				applog(LOG_NOTICE, "Pool %d share became stale during submission failure, will retry as pool requested", pool->pool_no);
 			else {
-				applog(LOG_NOTICE, "Share become stale during submission failure, discarding");
+				applog(LOG_NOTICE, "Pool %d share became stale during submission failure, discarding", pool->pool_no);
 				submit_discard_share(work);
 				break;
 			}
 			staleexpire = time(NULL) + 300;
 		}
 		if (unlikely((opt_retries >= 0) && (++failures > opt_retries))) {
-			applog(LOG_ERR, "Failed %d retries, discarding", opt_retries);
+			applog(LOG_ERR, "Pool %d failed %d submission retries, discarding", pool->pool_no, opt_retries);
 			submit_discard_share(work);
 			break;
 		}
 		else if (work->stale) {
 			if (unlikely(!list_empty(&submit_waiting))) {
-				applog(LOG_WARNING, "Stale share failed to submit while queued submissions are waiting, discarding");
+				applog(LOG_WARNING, "Pool %d stale share failed to submit while queued submissions are waiting, discarding", pool->pool_no);
 				submit_discard_share(work);
 				break;
 			} else if (unlikely(opt_retries < 0 && staleexpire <= time(NULL))) {
-				applog(LOG_NOTICE, "Stale share failed to submit for 5 minutes, discarding");
+				applog(LOG_NOTICE, "Pool %d stale share failed to submit for 5 minutes, discarding", pool->pool_no);
 				submit_discard_share(work);
 				break;
 			}
@@ -5290,7 +5320,7 @@ out_unlock:
 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;
+	struct work *work = sshare->work;
 	uint64_t sharediff = share_diff(work);
 	char hashshow[65];
 	uint32_t *hash32;
@@ -5387,7 +5417,7 @@ fishy:
 		goto out;
 	}
 	stratum_share_result(val, res_val, err_val, sshare);
-	clear_work(&sshare->work);
+	free_work(sshare->work);
 	free(sshare);
 
 	ret = true;
@@ -5419,9 +5449,9 @@ static void clear_stratum_shares(struct pool *pool)
 
 	mutex_lock(&sshare_lock);
 	HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
-		if (sshare->work.pool == pool) {
+		if (sshare->work->pool == pool) {
 			HASH_DEL(stratum_shares, sshare);
-			clear_work(&sshare->work);
+			free_work(sshare->work);
 			free(sshare);
 			cleared++;
 		}
@@ -5507,15 +5537,14 @@ static void *stratum_thread(void *userdata)
 			applog(LOG_INFO, "Unknown stratum msg: %s", s);
 		free(s);
 		if (pool->swork.clean) {
-			struct work work;
-			memset(&work, 0, sizeof(work));
+			struct work *work = make_work();
 
 			/* Generate a single work item to update the current
 			 * block database */
 			pool->swork.clean = false;
-			gen_stratum_work(pool, &work);
+			gen_stratum_work(pool, work);
 			++pool->work_restart_id;
-			if (test_work_current(&work)) {
+			if (test_work_current(work)) {
 				/* Only accept a work restart if this stratum
 				 * connection is from the current pool */
 				if (pool == current_pool()) {
@@ -5524,6 +5553,7 @@ static void *stratum_thread(void *userdata)
 				}
 			} else
 				applog(LOG_NOTICE, "Stratum from pool %d detected new block", pool->pool_no);
+			free_work(work);
 		}
 
 		if (pool->swork.transparency_time != (time_t)-1 && difftime(time(NULL), pool->swork.transparency_time) > 21.09375) {
@@ -5952,17 +5982,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 {
 	unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash;
 	int len, cb1_len, n1_len, cb2_len, i;
-	char header[260], *nonce2;
 	uint32_t *data32, *swap32;
-
-	memset(work->job_id, 0, 64);
-	memset(work->nonce2, 0, 64);
-	memset(work->ntime, 0, 16);
+	char header[260];
 
 	mutex_lock(&pool->pool_lock);
 
 	/* Generate coinbase */
-	nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
+	work->nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
 	pool->nonce2++;
 	cb1_len = strlen(pool->swork.coinbase1) / 2;
 	n1_len = strlen(pool->nonce1) / 2;
@@ -5971,7 +5997,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	coinbase = alloca(len + 1);
 	hex2bin(coinbase, pool->swork.coinbase1, cb1_len);
 	hex2bin(coinbase + cb1_len, pool->nonce1, n1_len);
-	hex2bin(coinbase + cb1_len + n1_len, nonce2, pool->n2size);
+	hex2bin(coinbase + cb1_len + n1_len, work->nonce2, pool->n2size);
 	hex2bin(coinbase + cb1_len + n1_len + pool->n2size, pool->swork.coinbase2, cb2_len);
 
 	/* Generate merkle root */
@@ -6004,10 +6030,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	work->sdiff = pool->swork.diff;
 
 	/* Copy parameters required for share submission */
-	sprintf(work->job_id, "%s", pool->swork.job_id);
-	sprintf(work->nonce2, "%s", nonce2);
-	sprintf(work->ntime, "%s", pool->swork.ntime);
-	free(nonce2);
+	work->job_id = strdup(pool->swork.job_id);
+	work->ntime = strdup(pool->swork.ntime);
 
 	mutex_unlock(&pool->pool_lock);
 
@@ -6122,7 +6146,7 @@ keepwaiting:
 			pool_resus(pool);
 	}
 
-	clear_work(work);
+	clean_work(work);
 	// NOTE: Since we are moving the references (if any), use free instead of free_work here
 	memcpy(work, work_heap, sizeof(struct work));
 	free(work_heap);
@@ -6133,7 +6157,7 @@ out:
 	work->mined = true;
 }
 
-bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv_work_found)
+bool submit_work_sync(struct thr_info *thr, struct work *work_in, struct timeval *tv_work_found)
 {
 	struct workio_cmd *wc;
 
@@ -6144,10 +6168,9 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct t
 		return false;
 	}
 
-	wc->work = make_work();
+	wc->work = copy_work(work_in);
 	wc->cmd = WC_SUBMIT_WORK;
 	wc->thr = thr;
-	workcpy(wc->work, work_in);
 	if (tv_work_found)
 		memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval));
 
@@ -6338,8 +6361,6 @@ void *miner_thread(void *userdata)
 
 	while (1) {
 		mythr->work_restart = false;
-		if (api->free_work && likely(work->pool))
-			api->free_work(mythr, work);
 		get_work(work, mythr, thr_id);
 		cgpu->new_work = true;
 

+ 7 - 8
miner.h

@@ -312,7 +312,6 @@ struct device_api {
 	bool (*thread_prepare)(struct thr_info*);
 	uint64_t (*can_limit_work)(struct thr_info*);
 	bool (*thread_init)(struct thr_info*);
-	void (*free_work)(struct thr_info*, struct work*);
 	bool (*prepare_work)(struct thr_info*, struct work*);
 	int64_t (*scanhash)(struct thr_info*, struct work*, int64_t);
 	void (*hw_error)(struct thr_info*);
@@ -1031,11 +1030,9 @@ struct work {
 	bool		queued;
 
 	bool		stratum;
-	/* These are arbitrary lengths as it is too hard to keep track of
-	 * dynamically allocated ram in work structs */
-	char 		job_id[64];
-	char		nonce2[64];
-	char		ntime[16];
+	char 		*job_id;
+	char		*nonce2;
+	char		*ntime;
 	double		sdiff;
 
 	unsigned char	work_restart_id;
@@ -1057,8 +1054,6 @@ struct work {
 };
 
 extern void get_datestamp(char *, struct timeval *);
-extern void workcpy(struct work *dest, const struct work *src);
-extern void clear_work(struct work *);
 enum test_nonce2_result {
 	TNR_GOOD,
 	TNR_HIGH,
@@ -1090,6 +1085,10 @@ extern void tq_freeze(struct thread_q *tq);
 extern void tq_thaw(struct thread_q *tq);
 extern bool successful_connect;
 extern void adl(void);
+extern void clean_work(struct work *work);
+extern void free_work(struct work *work);
+extern void __copy_work(struct work *work, struct work *base_work);
+extern struct work *copy_work(struct work *base_work);
 
 enum api_data_type {
 	API_ESCAPE,

+ 2 - 3
util.c

@@ -584,9 +584,8 @@ bool fulltest(const unsigned char *hash, const unsigned char *target)
 	swap256(target_swap, target);
 
 	for (i = 0; i < 32/4; i++) {
-		uint32_t h32tmp = swab32(hash32[i]);
-		uint32_t t32tmp = target32[i];
-
+		uint32_t h32tmp = htobe32(hash32[i]);
+		uint32_t t32tmp = htole32(target32[i]);
 		target32[i] = swab32(target32[i]);	/* for printing */
 
 		if (h32tmp > t32tmp) {