Browse Source

Refactor Icarus for cross-loop scanhash

Similar to the OpenCL driver, this runs the main thread loop work, share submission, etc in parallel to the Icarus's scanhash
Based on 8 hour testing, this may yield 1.1 MH/s extra.
Luke Dashjr 13 years ago
parent
commit
ac09d5eeb6
1 changed files with 45 additions and 19 deletions
  1. 45 19
      driver-icarus.c

+ 45 - 19
driver-icarus.c

@@ -253,6 +253,12 @@ static void icarus_detect()
 	}
 }
 
+struct icarus_state {
+	bool firstrun;
+	struct timeval tv_workstart;
+	struct work last_work;
+};
+
 static bool icarus_prepare(struct thr_info *thr)
 {
 	struct cgpu_info *icarus = thr->cgpu;
@@ -263,6 +269,10 @@ static bool icarus_prepare(struct thr_info *thr)
 	gettimeofday(&now, NULL);
 	get_datestamp(icarus->init, &now);
 
+	struct icarus_state *state;
+	thr->cgpu_data = state = calloc(1, sizeof(*state));
+	state->firstrun = true;
+
 	return true;
 }
 
@@ -273,16 +283,24 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	struct cgpu_info *icarus;
 	int fd;
-	int ret;
+	int ret, lret;
 
-	unsigned char ob_bin[64], nonce_bin[4];
+	unsigned char ob_bin[64] = {0}, nonce_bin[4] = {0};
 	char *ob_hex, *nonce_hex;
 	uint32_t nonce;
 	uint32_t hash_count;
-	struct timeval tv_start, tv_end, diff;
+	struct timeval tv_end, diff;
 
 	icarus = thr->cgpu;
+	struct icarus_state *state = thr->cgpu_data;
 
+	// Prepare the next work immediately
+	memcpy(ob_bin, work->midstate, 32);
+	memcpy(ob_bin + 52, work->data + 64, 12);
+	rev(ob_bin, 32);
+	rev(ob_bin + 52, 12);
+
+	// Open serial port and wait for the previous run's result
 	fd = icarus_open(icarus->device_path);
 	if (unlikely(-1 == fd)) {
 		applog(LOG_ERR, "Failed to open Icarus on %s",
@@ -290,16 +308,19 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		return 0;
 	}
 
-	memset(ob_bin, 0, sizeof(ob_bin));
-	memcpy(ob_bin, work->midstate, 32);
-	memcpy(ob_bin + 52, work->data + 64, 12);
-	rev(ob_bin, 32);
-	rev(ob_bin + 52, 12);
+	if (!state->firstrun) {
+		/* Icarus will return 8 bytes nonces or nothing */
+		lret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, wr);
+
+		gettimeofday(&tv_end, NULL);
+		timeval_subtract(&diff, &tv_end, &state->tv_workstart);
+	}
+
 #ifndef WIN32
 	tcflush(fd, TCOFLUSH);
 #endif
 
-	gettimeofday(&tv_start, NULL);
+	gettimeofday(&state->tv_workstart, NULL);
 
 	ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
 	if (ret) {
@@ -314,13 +335,17 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		free(ob_hex);
 	}
 
-	/* Icarus will return 8 bytes nonces or nothing */
-	memset(nonce_bin, 0, sizeof(nonce_bin));
-	ret = icarus_gets(nonce_bin, sizeof(nonce_bin), fd, wr);
+	icarus_close(fd);
 
-	gettimeofday(&tv_end, NULL);
-	timeval_subtract(&diff, &tv_end, &tv_start);
+	work->blk.nonce = 0xffffffff;
 
+	if (state->firstrun) {
+		state->firstrun = false;
+		memcpy(&state->last_work, work, sizeof(state->last_work));
+		return 1;
+	}
+
+	// OK, done starting Icarus's next job... now process the last run's result!
 	nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
 	if (nonce_hex) {
 		applog(LOG_DEBUG, "Icarus %d returned (in %d.%06d seconds): %s",
@@ -330,10 +355,8 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
 
-	work->blk.nonce = 0xffffffff;
-	icarus_close(fd);
-
-	if (nonce == 0 && ret) {
+	if (nonce == 0 && lret) {
+		memcpy(&state->last_work, work, sizeof(state->last_work));
 		if (unlikely(diff.tv_sec > 12 || (diff.tv_sec == 11 && diff.tv_usec > 300067)))
 			return 0xffffffff;
 		// Approximately how much of the nonce Icarus scans in 1 second...
@@ -345,7 +368,8 @@ static uint64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 #ifndef __BIG_ENDIAN__
 	nonce = swab32(nonce);
 #endif
-	submit_nonce(thr, work, nonce);
+	submit_nonce(thr, &state->last_work, nonce);
+	memcpy(&state->last_work, work, sizeof(state->last_work));
 
 	hash_count = (nonce & 0x7fffffff);
         if (hash_count == 0)
@@ -366,6 +390,8 @@ static void icarus_shutdown(struct thr_info *thr)
 {
 	struct cgpu_info *icarus;
 
+	free(thr->cgpu_data);
+
 	if (thr->cgpu) {
 		icarus = thr->cgpu;