Browse Source

Bugfix: gridseed: Implement a proper scanhash routine for GridSeeds

Previous behavior worked, but not intentionally
Nate Woolls 11 years ago
parent
commit
ad5fefc6ae
3 changed files with 122 additions and 55 deletions
  1. 102 23
      driver-gridseed.c
  2. 20 30
      gc3355.c
  3. 0 2
      gc3355.h

+ 102 - 23
driver-gridseed.c

@@ -20,7 +20,9 @@
 
 
 #define GRIDSEED_DEFAULT_FREQUENCY  600
 #define GRIDSEED_DEFAULT_FREQUENCY  600
 // 60Kh/s at 700MHz in ms
 // 60Kh/s at 700MHz in ms
-#define GRIDSEED_HASH_SPEED			0.08571428571429
+#define GRIDSEED_HASH_SPEED         0.08571428571429
+// GridSeed driver currently scans a full nonce range
+#define GRIDSEED_MAX_NONCE          0xffffffff
 
 
 BFG_REGISTER_DRIVER(gridseed_drv)
 BFG_REGISTER_DRIVER(gridseed_drv)
 
 
@@ -76,27 +78,71 @@ struct thr_info *gridseed_thread_by_chip(const struct cgpu_info * const device,
 	return proc->thr[0];
 	return proc->thr[0];
 }
 }
 
 
+// return the number of hashes done in elapsed_ms
 static
 static
-int64_t gridseed_calculate_chip_hashes(struct thr_info *thr)
+int64_t gridseed_calculate_chip_hashes_ms(const struct cgpu_info * const device, int const elapsed_ms)
 {
 {
-	struct cgpu_info *device = thr->cgpu;
 	struct gc3355_info *info = device->device_data;
 	struct gc3355_info *info = device->device_data;
-	struct timeval old_scanhash_time = info->scanhash_time;
+	return GRIDSEED_HASH_SPEED * (double)elapsed_ms * (double)(info->freq);
+}
 
 
-	timer_set_now(&info->scanhash_time);
-	int elapsed_ms = ms_tdiff(&info->scanhash_time, &old_scanhash_time);
+// return the number of hashes done since start_tv
+static
+int64_t gridseed_calculate_chip_hashes(const struct cgpu_info * const device, struct timeval const start_tv)
+{
+	struct timeval now_tv;
+	timer_set_now(&now_tv);
+	int elapsed_ms = ms_tdiff(&now_tv, &start_tv);
 
 
-	return GRIDSEED_HASH_SPEED * (double)elapsed_ms * (double)(info->freq);
+	return gridseed_calculate_chip_hashes_ms(device, elapsed_ms);
 }
 }
 
 
+// adjust calculated hashes that overflow possible values
 static
 static
-void gridseed_hashes_done(struct thr_info *thr)
+int64_t gridseed_fix_hashes_done(int64_t const hashes_done)
 {
 {
-	struct cgpu_info *device = thr->cgpu;
-	int64_t chip_hashes = gridseed_calculate_chip_hashes(thr);
+	int64_t result = hashes_done;
+
+	// not possible to complete more than 0xffffffff nonces
+	if (unlikely(result > 0xffffffff))
+		result = 0xffffffff;
 
 
-	for (struct cgpu_info *proc = device; proc; proc = proc->next_proc)
-		hashes_done2(proc->thr[0], chip_hashes, NULL);
+	return result;
+}
+
+// report on hashes done since start_tv
+// return the number of hashes done since start_tv
+static
+int64_t gridseed_hashes_done(struct cgpu_info * const device, struct timeval const start_tv, int64_t previous_hashes)
+{
+	int64_t total_chip_hashes = gridseed_calculate_chip_hashes(device, start_tv);
+	total_chip_hashes = gridseed_fix_hashes_done(total_chip_hashes);
+
+	int64_t previous_chip_hashes = previous_hashes / device->procs;
+	int64_t recent_chip_hashes = total_chip_hashes - previous_chip_hashes;
+	int64_t total_hashes = 0;
+
+	for_each_managed_proc(proc, device)
+	{
+		total_hashes += recent_chip_hashes;
+		hashes_done2(proc->thr[0], recent_chip_hashes, NULL);
+	}
+
+	return total_hashes;
+}
+
+// return duration in seconds for device to scan a nonce range
+static
+uint32_t gridseed_nonce_range_duration(const struct cgpu_info * const device)
+{
+	struct gc3355_info *info = device->device_data;
+
+	// total hashrate of this device:
+	uint32_t hashes_per_sec = gridseed_calculate_chip_hashes_ms(device, 1000) * info->chips;
+	// amount of time it takes this device to scan a nonce range:
+	uint32_t nonce_range_sec = 0xffffffff / hashes_per_sec;
+
+	return nonce_range_sec;
 }
 }
 
 
 /*
 /*
@@ -195,13 +241,10 @@ void gridseed_thread_shutdown(struct thr_info *thr)
 
 
 // send work to the device
 // send work to the device
 static
 static
-bool gridseed_prepare_work(struct thr_info __maybe_unused *thr, struct work *work)
+bool gridseed_job_start(const struct thr_info * const thr, struct work * const work)
 {
 {
 	struct cgpu_info *device = thr->cgpu;
 	struct cgpu_info *device = thr->cgpu;
-	struct gc3355_info *info = device->device_data;
 	unsigned char cmd[156];
 	unsigned char cmd[156];
-	
-	timer_set_now(&info->scanhash_time);
 
 
 	gc3355_scrypt_reset(device->device_fd);
 	gc3355_scrypt_reset(device->device_fd);
 	gc3355_scrypt_prepare_work(cmd, work);
 	gc3355_scrypt_prepare_work(cmd, work);
@@ -221,6 +264,10 @@ bool gridseed_prepare_work(struct thr_info __maybe_unused *thr, struct work *wor
 		return false;
 		return false;
 	}
 	}
 
 
+	// after sending work to the device, minerloop_scanhash-based
+	// drivers must set work->blk.nonce to the last nonce to hash
+	work->blk.nonce = GRIDSEED_MAX_NONCE;
+
 	return true;
 	return true;
 }
 }
 
 
@@ -231,7 +278,7 @@ void gridseed_submit_nonce(struct thr_info * const thr, const unsigned char buf[
 	
 	
 	uint32_t nonce = *(uint32_t *)(buf + 4);
 	uint32_t nonce = *(uint32_t *)(buf + 4);
 	nonce = le32toh(nonce);
 	nonce = le32toh(nonce);
-	uint32_t chip = nonce / ((uint32_t)0xffffffff / device->procs);
+	uint32_t chip = nonce / (GRIDSEED_MAX_NONCE / device->procs);
 	
 	
 	struct thr_info *proc_thr = gridseed_thread_by_chip(device, chip);
 	struct thr_info *proc_thr = gridseed_thread_by_chip(device, chip);
 	
 	
@@ -239,23 +286,54 @@ void gridseed_submit_nonce(struct thr_info * const thr, const unsigned char buf[
 }
 }
 
 
 // read from device for nonce or command
 // read from device for nonce or command
+// unless the device can target specific nonce ranges, the scanhash routine should loop
+// until the device has processed the work item, scanning the full nonce range
+// return the total number of hashes done
 static
 static
 int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
 int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
 {
 {
 	struct cgpu_info *device = thr->cgpu;
 	struct cgpu_info *device = thr->cgpu;
+	struct timeval start_tv, nonce_range_tv, report_hashes_tv;
+
+	// amount of time it takes this device to scan a nonce range:
+	uint32_t nonce_full_range_sec = gridseed_nonce_range_duration(device);
+	// timer to break out of scanning should we close in on an entire nonce range
+	// should break out before the range is scanned, so we are doing 99% of the range
+	uint64_t nonce_near_range_usec = (nonce_full_range_sec * 1000000. * 0.99);
+	timer_set_delay_from_now(&nonce_range_tv, nonce_near_range_usec);
+
+	// timer to calculate hashes every 10s
+	const uint32_t report_delay = 10 * 1000000;
+	timer_set_delay_from_now(&report_hashes_tv, report_delay);
+
+	// start the job
+	timer_set_now(&start_tv);
+	gridseed_job_start(thr, work);
+
+	// scan for results
 	unsigned char buf[GC3355_READ_SIZE];
 	unsigned char buf[GC3355_READ_SIZE];
 	int read = 0;
 	int read = 0;
 	int fd = device->device_fd;
 	int fd = device->device_fd;
+	int64_t total_hashes = 0;
+	bool range_nearly_scanned = false;
 
 
-	while (!thr->work_restart && (read = gc3355_read(fd, (char *)buf, GC3355_READ_SIZE)) > 0)
+	while (!thr->work_restart                                                   // true when new work is available (miner.c)
+	    && ((read = gc3355_read(fd, (char *)buf, GC3355_READ_SIZE)) >= 0)       // only check for failure - allow 0 bytes
+	    && !(range_nearly_scanned = timer_passed(&nonce_range_tv, NULL)))       // true when we've nearly scanned a nonce range
 	{
 	{
+		if (timer_passed(&report_hashes_tv, NULL))
+		{
+			total_hashes += gridseed_hashes_done(device, start_tv, total_hashes);
+			timer_set_delay_from_now(&report_hashes_tv, report_delay);
+		}
+
+		if (read == 0)
+			continue;
+
 		if ((buf[0] == 0x55) && (buf[1] == 0x20))
 		if ((buf[0] == 0x55) && (buf[1] == 0x20))
 			gridseed_submit_nonce(thr, buf, work);
 			gridseed_submit_nonce(thr, buf, work);
 		else
 		else
-		{
 			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
 			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
-			break;
-		}
 	}
 	}
 
 
 	if (read == -1)
 	if (read == -1)
@@ -264,7 +342,9 @@ int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __may
 		dev_error(device, REASON_DEV_COMMS_ERROR);
 		dev_error(device, REASON_DEV_COMMS_ERROR);
 	}
 	}
 
 
-	gridseed_hashes_done(thr);
+	// calculate remaining hashes for elapsed time
+	// e.g. work_restart ~report_delay after report_hashes_tv
+	gridseed_hashes_done(device, start_tv, total_hashes);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -332,7 +412,6 @@ struct device_drv gridseed_drv =
 	.minerloop = minerloop_scanhash,
 	.minerloop = minerloop_scanhash,
 	
 	
 	// scanhash mining hooks
 	// scanhash mining hooks
-	.prepare_work = gridseed_prepare_work,
 	.scanhash = gridseed_scanhash,
 	.scanhash = gridseed_scanhash,
 	
 	
 	// teardown device
 	// teardown device

+ 20 - 30
gc3355.c

@@ -33,7 +33,9 @@
 int opt_sha2_units = -1;
 int opt_sha2_units = -1;
 int opt_pll_freq = 0; // default is set in gc3355_set_pll_freq
 int opt_pll_freq = 0; // default is set in gc3355_set_pll_freq
 
 
-#define GC3355_CHIP_NAME  "gc3355"
+#define GC3355_CHIP_NAME         "gc3355"
+#define GC3355_COMMAND_DELAY_MS  20
+#define GC3355_WRITE_DELAY_MS    10
 
 
 // General GC3355 commands
 // General GC3355 commands
 
 
@@ -390,20 +392,7 @@ void gc3355_log_protocol(int fd, const char *buf, size_t size, const char *prefi
 
 
 ssize_t gc3355_read(int fd, char *buf, size_t size)
 ssize_t gc3355_read(int fd, char *buf, size_t size)
 {
 {
-	size_t read;
-	int tries = 20;
-	
-	while (tries > 0)
-	{
-		read = serial_read(fd, buf, size);
-		if (read > 0)
-			break;
-		
-		tries--;
-	}
-	
-	if (unlikely(tries == 0))
-		return read;
+	size_t read = serial_read(fd, buf, size);
 	
 	
 	if ((read > 0) && opt_dev_protocol)
 	if ((read > 0) && opt_dev_protocol)
 		gc3355_log_protocol(fd, buf, read, "RECV");
 		gc3355_log_protocol(fd, buf, read, "RECV");
@@ -415,12 +404,21 @@ ssize_t gc3355_write(int fd, const void * const buf, const size_t size)
 {
 {
 	if (opt_dev_protocol)
 	if (opt_dev_protocol)
 		gc3355_log_protocol(fd, buf, size, "SEND");
 		gc3355_log_protocol(fd, buf, size, "SEND");
-	
-	return write(fd, buf, size);
+
+	ssize_t result = write(fd, buf, size);
+
+	// gc3355 can suffer register corruption if multiple writes are
+	// made in a short period of time.
+	// This is not possible to reproduce on Mac OS X where the serial
+	// drivers seem to carry an additional overhead / latency.
+	// This is reproducable on Linux though by removing the following:
+	cgsleep_ms(GC3355_WRITE_DELAY_MS);
+
+	return result;
 }
 }
 
 
 static
 static
-void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
+void gc3355_send_cmds(int fd, const char *cmds[])
 {
 {
 	int i = 0;
 	int i = 0;
 	unsigned char ob_bin[512];
 	unsigned char ob_bin[512];
@@ -430,22 +428,14 @@ void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
 		if (cmd == NULL)
 		if (cmd == NULL)
 			break;
 			break;
 
 
-		if (is_bin)
-			gc3355_write(fd, cmd, size);
-		else
-		{
-			int bin_size = strlen(cmd) / 2;
-			hex2bin(ob_bin, cmd, bin_size);
-			gc3355_write(fd, ob_bin, bin_size);
-		}
-		
+		int bin_size = strlen(cmd) / 2;
+		hex2bin(ob_bin, cmd, bin_size);
+		gc3355_write(fd, ob_bin, bin_size);
+
 		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 	}
 	}
 }
 }
 
 
-#define gc3355_send_cmds_bin(fd, cmds, size)  _gc3355_send_cmds_bin(fd, cmds, true, size)
-#define gc3355_send_cmds(fd, cmds)  _gc3355_send_cmds_bin(fd, cmds, false, -1)
-
 void gc3355_scrypt_only_reset(int fd)
 void gc3355_scrypt_only_reset(int fd)
 {
 {
 	gc3355_send_cmds(fd, scrypt_only_reset_cmd);
 	gc3355_send_cmds(fd, scrypt_only_reset_cmd);

+ 0 - 2
gc3355.h

@@ -27,7 +27,6 @@ int opt_pll_freq;
 
 
 // GridSeed common code begins here
 // GridSeed common code begins here
 
 
-#define GC3355_COMMAND_DELAY_MS 20
 #define GC3355_ORB_DEFAULT_CHIPS   5
 #define GC3355_ORB_DEFAULT_CHIPS   5
 #define GC3355_BLADE_DEFAULT_CHIPS	40
 #define GC3355_BLADE_DEFAULT_CHIPS	40
 #define GC3355_READ_SIZE          12
 #define GC3355_READ_SIZE          12
@@ -36,7 +35,6 @@ struct gc3355_info
 {
 {
 	uint16_t freq;
 	uint16_t freq;
 	unsigned chips;
 	unsigned chips;
-	struct timeval scanhash_time;
 };
 };
 
 
 #define gc3355_open(path)  serial_open(path, 115200, 1, true)
 #define gc3355_open(path)  serial_open(path, 115200, 1, true)