Merge branch 'master' of github.com:ckolivas/cgminer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
diff --git a/FPGA-README b/FPGA-README
index 9f9c4ab..48751d3 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 <arg> 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 0f1be18..647c9d1 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);