From 07c06bef547a638349f6857f8bc9213ba283cd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=C2=A0Le=C5=9Bniewski?= Date: Sun, 13 Nov 2022 15:04:32 +0100 Subject: [PATCH 1/3] Optimize ESP8266 miner This commit changes how the sequence of strings representing consecutive integers is generated for the hasher. Instead of utilizing the Arduino String conversions, a Counter class is introduced, which can generate consecutive integers much faster. On my Wemos D1 mini this gives a hash rate increase from around 37 kH/s to around 53 kH/s, which is a 43% improvement. --- ESP8266_Code/ESP8266_Code.ino | 74 +++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/ESP8266_Code/ESP8266_Code.ino b/ESP8266_Code/ESP8266_Code.ino index e75168f4..ae09c86e 100644 --- a/ESP8266_Code/ESP8266_Code.ino +++ b/ESP8266_Code/ESP8266_Code.ino @@ -427,6 +427,49 @@ unsigned long lwdTimeOutMillis = LWD_TIMEOUT; #define BLINK_CLIENT_CONNECT 3 #define BLINK_RESET_DEVICE 5 +template +class Counter { +public: + Counter() { reset(); } + + void reset() { + memset(buffer, '0', max_digits); + buffer[max_digits] = '\0'; + val = 0; + len = 1; + } + + Counter & operator++() { + inc_string(max_digits - 1); + ++val; + return *this; + } + + operator unsigned int () const { return val; } + const char * c_str() const { return buffer + max_digits - len; } + size_t strlen() const { return len; } + +protected: + inline void inc_string(int pos) { + if (pos < 0) + return; + + if (buffer[pos] < '9') { + buffer[pos]++; + } else { + buffer[pos] = '0'; + inc_string(pos - 1); + } + + len = max(max_digits - pos, len); + } + +protected: + char buffer[max_digits + 1]; + unsigned int val; + size_t len; +}; + void SetupWifi() { Serial.println("Connecting to: " + String(SSID)); WiFi.mode(WIFI_STA); // Setup ESP in client mode @@ -518,6 +561,23 @@ void handleSystemEvents(void) { yield(); } +// https://stackoverflow.com/questions/9072320/split-string-into-string-array +String getValue(String data, char separator, int index) +{ + int found = 0; + int strIndex[] = {0, -1}; + int max_index = data.length() - 1; + + for (int i = 0; i <= max_index && found <= index; i++) { + if (data.charAt(i) == separator || i == max_index) { + found++; + strIndex[0] = strIndex[1] + 1; + strIndex[1] = (i == max_index) ? i + 1 : i; + } + } + return found > index ? data.substring(strIndex[0], strIndex[1]) : ""; +} + void waitForClientData(void) { client_buffer = ""; @@ -674,8 +734,7 @@ void setup() { void loop() { br_sha1_context sha1_ctx, sha1_ctx_base; uint8_t hashArray[20]; - String duco_numeric_result_str; - + // 1 minute watchdog lwdtFeed(); @@ -742,12 +801,11 @@ void loop() { String result = ""; if (LED_BLINKING) digitalWrite(LED_BUILTIN, LOW); - for (unsigned int duco_numeric_result = 0; duco_numeric_result < job.difficulty; duco_numeric_result++) { + for (Counter<8> counter; counter < difficulty; ++counter) { // Difficulty loop sha1_ctx = sha1_ctx_base; - duco_numeric_result_str = String(duco_numeric_result); - br_sha1_update(&sha1_ctx, duco_numeric_result_str.c_str(), duco_numeric_result_str.length()); + br_sha1_update(&sha1_ctx, counter.c_str(), counter.strlen()); br_sha1_out(&sha1_ctx, hashArray); if (memcmp(job.expected_hash, hashArray, 20) == 0) { @@ -755,9 +813,9 @@ void loop() { if (LED_BLINKING) digitalWrite(LED_BUILTIN, HIGH); unsigned long elapsed_time = micros() - start_time; float elapsed_time_s = elapsed_time * .000001f; - hashrate = duco_numeric_result / elapsed_time_s; + hashrate = counter / elapsed_time_s; share_count++; - client.print(String(duco_numeric_result) + client.print(String(counter) + "," + String(hashrate) + "," @@ -774,7 +832,7 @@ void loop() { Serial.println(client_buffer + " share #" + String(share_count) - + " (" + String(duco_numeric_result) + ")" + + " (" + String(counter) + ")" + " hashrate: " + String(hashrate / 1000, 2) + " kH/s (" From 938a8d4c72775c053c612ad188e76b28005673db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=C2=A0Le=C5=9Bniewski?= Date: Wed, 7 Dec 2022 21:14:46 +0100 Subject: [PATCH 2/3] Increase watchdog timeout to allow high difficulty jobs to complete --- ESP8266_Code/ESP8266_Code.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ESP8266_Code/ESP8266_Code.ino b/ESP8266_Code/ESP8266_Code.ino index ae09c86e..d2e2ea68 100644 --- a/ESP8266_Code/ESP8266_Code.ino +++ b/ESP8266_Code/ESP8266_Code.ino @@ -413,7 +413,7 @@ String START_DIFF = ""; // Loop WDT... please don't feed me... // See lwdtcb() and lwdtFeed() below Ticker lwdTimer; -#define LWD_TIMEOUT 20000 +#define LWD_TIMEOUT 90000 unsigned long lwdCurrentMillis = 0; unsigned long lwdTimeOutMillis = LWD_TIMEOUT; From e455c9c2c3f66ad2581a93f30a819840480a1794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=C2=A0Le=C5=9Bniewski?= Date: Thu, 8 Dec 2022 22:09:23 +0100 Subject: [PATCH 3/3] fixup! Optimize ESP8266 miner --- ESP8266_Code/ESP8266_Code.ino | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/ESP8266_Code/ESP8266_Code.ino b/ESP8266_Code/ESP8266_Code.ino index d2e2ea68..53bc5d94 100644 --- a/ESP8266_Code/ESP8266_Code.ino +++ b/ESP8266_Code/ESP8266_Code.ino @@ -439,29 +439,30 @@ public: len = 1; } - Counter & operator++() { - inc_string(max_digits - 1); + inline Counter & operator++() { + inc_string(buffer + max_digits - 1); ++val; return *this; } - operator unsigned int () const { return val; } - const char * c_str() const { return buffer + max_digits - len; } - size_t strlen() const { return len; } + inline operator unsigned int () const { return val; } + inline const char * c_str() const { return buffer + max_digits - len; } + inline size_t strlen() const { return len; } protected: - inline void inc_string(int pos) { - if (pos < 0) - return; - - if (buffer[pos] < '9') { - buffer[pos]++; + inline void inc_string(char * c) { + // In theory, the line below should be uncommented to avoid writing outside the buffer. In practice however, + // with max_digits set to 10 or more, we can fit all possible unsigned 32-bit integers in the buffer. The + // check is skipped to gain a small extra speed improvement. + // if (c >= buffer) return; + + if (*c < '9') { + *c += 1; } else { - buffer[pos] = '0'; - inc_string(pos - 1); + *c = '0'; + inc_string(c - 1); + len = max(max_digits - (c - buffer) + 1, len); } - - len = max(max_digits - pos, len); } protected: @@ -796,12 +797,12 @@ void loop() { br_sha1_init(&sha1_ctx_base); br_sha1_update(&sha1_ctx_base, job.last_block_hash.c_str(), job.last_block_hash.length()); - float start_time = micros(); + unsigned long start_time = micros(); max_micros_elapsed(start_time, 0); String result = ""; if (LED_BLINKING) digitalWrite(LED_BUILTIN, LOW); - for (Counter<8> counter; counter < difficulty; ++counter) { + for (Counter<10> counter; counter < difficulty; ++counter) { // Difficulty loop sha1_ctx = sha1_ctx_base;