diff --git a/FPGA-README b/FPGA-README index 9f9c4ab4..48751d3a 100644 --- a/FPGA-README +++ b/FPGA-README @@ -213,8 +213,8 @@ only 1 FPGA actually runs on the board (e.g. like an early CM1 Icarus copy bitst --icarus-timing Set how the Icarus timing is calculated - one setting/value for all or comma separated default[=N] Use the default Icarus hash time (2.6316ns) - short Calculate the hash time and stop adjusting it at ~315 difficulty 1 shares (~1hr) - long Re-calculate the hash time continuously + short=[N] Calculate the hash time and stop adjusting it at ~315 difficulty 1 shares (~1hr) + long=[N] Re-calculate the hash time continuously value[=N] Specify the hash time in nanoseconds (e.g. 2.6316) and abort time (e.g. 2.6316=80) If you define fewer comma seperated values than Icarus devices, the last values will be used @@ -236,6 +236,10 @@ Any CPU delays while calculating the hash time will affect the result 'short' mode only requires the computer to be stable until it has completed ~315 difficulty 1 shares 'long' mode requires it to always be stable to ensure accuracy, however, over time it continually corrects itself +The optional additional =N for 'short' or 'long' specifies the limit to set the timeout to in N * 100ms +thus if the timing code calculation is higher while running, it will instead use N * 100ms +This can be set to the appropriate value to ensure the device never goes idle even if the +calculation is negatively affected by system performance When in 'short' or 'long' mode, it will report the hash time value each time it is re-calculated In 'short' or 'long' mode, the scan abort time starts at 5 seconds and uses the default 2.6316ns diff --git a/driver-icarus.c b/driver-icarus.c index 0f1be180..647c9d14 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -72,9 +72,17 @@ ASSERT1(sizeof(uint32_t) == 4); // maybe 1ms? #define ICARUS_READ_TIME(baud) (0.001) -// USB ms timeout to wait +// USB ms timeout to wait - user specified timeouts are multiples of this #define ICARUS_WAIT_TIMEOUT 100 +// Defined in multiples of ICARUS_WAIT_TIMEOUT +// Must of course be greater than ICARUS_READ_COUNT_TIMING/ICARUS_WAIT_TIMEOUT +// There's no need to have this bigger, since the overhead/latency of extra work +// is pretty small once you get beyond a 10s nonce range time and 10s also +// means that nothing slower than 429MH/s can go idle so most icarus devices +// will always mine without idling +#define ICARUS_READ_TIME_LIMIT_MAX 100 + // In timing mode: Default starting value until an estimate can be obtained // 5000 ms allows for up to a ~840MH/s device #define ICARUS_READ_COUNT_TIMING 5000 @@ -160,7 +168,9 @@ enum timing_mode { MODE_DEFAULT, MODE_SHORT, MODE_LONG, MODE_VALUE }; static const char *MODE_DEFAULT_STR = "default"; static const char *MODE_SHORT_STR = "short"; +static const char *MODE_SHORT_STREQ = "short="; static const char *MODE_LONG_STR = "long"; +static const char *MODE_LONG_STREQ = "long="; static const char *MODE_VALUE_STR = "value"; static const char *MODE_UNKNOWN_STR = "unknown"; @@ -176,6 +186,8 @@ struct ICARUS_INFO { double Hs; // ms til we abort int read_time; + // ms limit for (short=/long=) read_time + int read_time_limit; enum timing_mode timing_mode; bool do_icarus_timing; @@ -536,19 +548,46 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus) } info->read_time = 0; + info->read_time_limit = 0; // 0 = no limit - // TODO: allow short=N and long=N if (strcasecmp(buf, MODE_SHORT_STR) == 0) { + // short + info->read_time = ICARUS_READ_COUNT_TIMING; + + info->timing_mode = MODE_SHORT; + info->do_icarus_timing = true; + } else if (strncasecmp(buf, MODE_SHORT_STREQ, strlen(MODE_SHORT_STREQ)) == 0) { + // short=limit info->read_time = ICARUS_READ_COUNT_TIMING; info->timing_mode = MODE_SHORT; info->do_icarus_timing = true; + + info->read_time_limit = atoi(&buf[strlen(MODE_SHORT_STREQ)]); + if (info->read_time_limit < 0) + info->read_time_limit = 0; + if (info->read_time_limit > ICARUS_READ_TIME_LIMIT_MAX) + info->read_time_limit = ICARUS_READ_TIME_LIMIT_MAX; } else if (strcasecmp(buf, MODE_LONG_STR) == 0) { + // long info->read_time = ICARUS_READ_COUNT_TIMING; info->timing_mode = MODE_LONG; info->do_icarus_timing = true; + } else if (strncasecmp(buf, MODE_LONG_STREQ, strlen(MODE_LONG_STREQ)) == 0) { + // long=limit + info->read_time = ICARUS_READ_COUNT_TIMING; + + info->timing_mode = MODE_LONG; + info->do_icarus_timing = true; + + info->read_time_limit = atoi(&buf[strlen(MODE_LONG_STREQ)]); + if (info->read_time_limit < 0) + info->read_time_limit = 0; + if (info->read_time_limit > ICARUS_READ_TIME_LIMIT_MAX) + info->read_time_limit = ICARUS_READ_TIME_LIMIT_MAX; } else if ((Hs = atof(buf)) != 0) { + // ns[=read_time] info->Hs = Hs / NANOSEC; info->fullnonce = info->Hs * (((double)0xffffffff) + 1); @@ -583,10 +622,13 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus) info->min_data_count = MIN_DATA_COUNT; - applog(LOG_DEBUG, "%s: cgid %d Init: mode=%s read_time=%dms Hs=%e", + // All values are in multiples of ICARUS_WAIT_TIMEOUT + info->read_time_limit *= ICARUS_WAIT_TIMEOUT; + + applog(LOG_DEBUG, "%s: cgid %d Init: mode=%s read_time=%dms limit=%dms Hs=%e", icarus->drv->name, icarus->cgminer_id, timing_mode_str(info->timing_mode), - info->read_time, info->Hs); + info->read_time, info->read_time_limit, info->Hs); } static uint32_t mask(int work_division) @@ -866,6 +908,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, int count; double Hs, W, fullnonce; int read_time; + bool limited; int64_t estimate_hashes; uint32_t values; int64_t hash_count_range; @@ -967,7 +1010,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, elapsed.tv_sec, elapsed.tv_usec); } - // ignore possible end condition values ... and hw errors + // Ignore possible end condition values ... and hw errors + // TODO: set limitations on calculated values depending on the device + // to avoid crap values caused by CPU/Task Switching/Swapping/etc if (info->do_icarus_timing && !was_hw_error && ((nonce & info->nonce_mask) > END_CONDITION) @@ -1040,6 +1085,11 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, fullnonce = W + Hs * (((double)0xffffffff) + 1); read_time = SECTOMS(fullnonce) - ICARUS_READ_REDUCE; + if (info->read_time_limit > 0 && read_time > info->read_time_limit) { + read_time = info->read_time_limit; + limited = true; + } else + limited = false; info->Hs = Hs; info->read_time = read_time; @@ -1055,8 +1105,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, else if (info->timing_mode == MODE_SHORT) info->do_icarus_timing = false; - applog(LOG_WARNING, "%s%d Re-estimate: Hs=%e W=%e read_time=%dms fullnonce=%.3fs", - icarus->drv->name, icarus->device_id, Hs, W, read_time, fullnonce); + applog(LOG_WARNING, "%s%d Re-estimate: Hs=%e W=%e read_time=%dms%s fullnonce=%.3fs", + icarus->drv->name, icarus->device_id, Hs, W, read_time, + limited ? " (limited)" : "", fullnonce); } info->history_count++; cgtime(&tv_history_finish); @@ -1078,6 +1129,7 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) // locking access to displaying API debug 'stats' // If locking becomes an issue for any of them, use copy_data=true also root = api_add_int(root, "read_time", &(info->read_time), false); + root = api_add_int(root, "read_time_limit", &(info->read_time_limit), false); root = api_add_double(root, "fullnonce", &(info->fullnonce), false); root = api_add_int(root, "count", &(info->count), false); root = api_add_hs(root, "Hs", &(info->Hs), false);