From 0133403e648ce48f08994e4ac42df2557486be84 Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Sat, 18 Mar 2023 23:08:11 +0100 Subject: [PATCH 1/7] use less stack on number print --- cores/arduino/Print.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 1e4c99a65..31ae12b48 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -202,22 +202,35 @@ size_t Print::println(const Printable& x) size_t Print::printNumber(unsigned long n, uint8_t base) { - char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. - char *str = &buf[sizeof(buf) - 1]; - - *str = '\0'; + // shortcut printing just 0 prevents later overhead + if (n == 0) { + return write('0'); + } // prevent crash if called with base == 1 if (base < 2) base = 10; - do { - char c = n % base; + unsigned long reverse = 0; + uint8_t digits = 0; + + // reverse the number and count digits + while (n != 0) { + uint8_t remainder = n % base; + reverse = reverse * base + remainder; n /= base; + digits++; + } + + // from here onwards reuse of variable 'n' to count written chars + do { + char c = reverse % base; + reverse /= base; - *--str = c < 10 ? c + '0' : c + 'A' - 10; - } while(n); + c = (c < 10 ? c + '0' : c + 'A' - 10); + n += write(c); + } while(--digits); - return write(str); + return n; } size_t Print::printFloat(double number, uint8_t digits) From e2f54b1a9614d2e6a2bab30757e22273d7f2c5bd Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Tue, 4 Apr 2023 00:58:41 +0200 Subject: [PATCH 2/7] fixed for 10 digit numbers now working for full long int range --- cores/arduino/Print.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 31ae12b48..dcc7d30aa 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -202,7 +202,7 @@ size_t Print::println(const Printable& x) size_t Print::printNumber(unsigned long n, uint8_t base) { - // shortcut printing just 0 prevents later overhead + // shortcut printing just 0 and prevent later overhead if (n == 0) { return write('0'); } @@ -212,6 +212,10 @@ size_t Print::printNumber(unsigned long n, uint8_t base) unsigned long reverse = 0; uint8_t digits = 0; + char avoid_overflow = n % base; + + // this step and 'avoid_overflow' will make sure it stays in unsigned long range beeing able to print all 10 digits no matter what + n /= base; // reverse the number and count digits while (n != 0) { @@ -222,13 +226,16 @@ size_t Print::printNumber(unsigned long n, uint8_t base) } // from here onwards reuse of variable 'n' to count written chars - do { + while (digits--) { char c = reverse % base; reverse /= base; c = (c < 10 ? c + '0' : c + 'A' - 10); n += write(c); - } while(--digits); + } + + avoid_overflow = (avoid_overflow < 10 ? avoid_overflow + '0' : avoid_overflow + 'A' - 10); + n += write(avoid_overflow); return n; } From 870432ed5a751f213e9e4fcef52e8615a9e3ed22 Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Tue, 4 Apr 2023 01:00:20 +0200 Subject: [PATCH 3/7] improved on base 2 and base 16 print number implementations added compile flag to disable those additional optimized implementations --- cores/arduino/Print.cpp | 114 ++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 27 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index dcc7d30aa..ed4d13111 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -210,34 +210,94 @@ size_t Print::printNumber(unsigned long n, uint8_t base) // prevent crash if called with base == 1 if (base < 2) base = 10; - unsigned long reverse = 0; - uint8_t digits = 0; - char avoid_overflow = n % base; - - // this step and 'avoid_overflow' will make sure it stays in unsigned long range beeing able to print all 10 digits no matter what - n /= base; - - // reverse the number and count digits - while (n != 0) { - uint8_t remainder = n % base; - reverse = reverse * base + remainder; - n /= base; - digits++; - } - - // from here onwards reuse of variable 'n' to count written chars - while (digits--) { - char c = reverse % base; - reverse /= base; - - c = (c < 10 ? c + '0' : c + 'A' - 10); - n += write(c); +// use -D ARDUINO_PRINT_NUMBER_GENERIC_ONLY when compiling to get only the generic version +#ifndef ARDUINO_PRINT_NUMBER_GENERIC_ONLY + switch (base) { + case 16: + // optimized version for hex prints + { + uint8_t *access = (uint8_t*) &n; + uint8_t written = 0; + for (int8_t i=3; i>=0; i--) { + char c; + c = (access[i] & 0xf0) >> 4; + if (c != 0 || written != 0) { + c = (c < 10 ? c + '0' : c + 'A' - 10); + written += write(c); + } // else: skip leading zeros + c = access[i] & 0x0f; + if (c != 0 || written != 0) { + // skip leading zeros + c = (c < 10 ? c + '0' : c + 'A' - 10); + written += write(c); + } // else: skip leading zeros + } + return written; + } + case 2: + // optimized version for binary prints + { + uint8_t *access = (uint8_t*) &n; + uint8_t written = 0; + for (int8_t i=3; i>=0; i--) { + if (access[i] == 0 && written == 0) { + // skip leading zeros + continue; + } + for (int8_t j=7; j>=0; j--) { + char c; + if (j == 0) { + // avoid shift by 0 - undefined + c = (access[i] & 0x01); + } else { + c = (access[i] & 1<> j; + } + if (c == 0 && written == 0) { + // skip leading zeros + continue; + } + c = (c < 10 ? c + '0' : c + 'A' - 10); + written += write(c); + } + } + return written; + } + default: + // the generic implementation +#endif + { + unsigned long reverse = 0; + uint8_t digits = 0; + char avoid_overflow = n % base; + + // this step and 'avoid_overflow' will make sure it stays in unsigned long range beeing able to print all 10 digits no matter what + n /= base; + + // reverse the number and count digits + while (n != 0) { + uint8_t remainder = n % base; + reverse = reverse * base + remainder; + n /= base; + digits++; + } + + // from here onwards reuse of variable 'n' to count written chars + while (digits--) { + char c = reverse % base; + reverse /= base; + + c = (c < 10 ? c + '0' : c + 'A' - 10); + n += write(c); + } + + avoid_overflow = (avoid_overflow < 10 ? avoid_overflow + '0' : avoid_overflow + 'A' - 10); + n += write(avoid_overflow); + + return n; + } +#ifndef ARDUINO_PRINT_NUMBER_GENERIC_ONLY } - - avoid_overflow = (avoid_overflow < 10 ? avoid_overflow + '0' : avoid_overflow + 'A' - 10); - n += write(avoid_overflow); - - return n; +#endif } size_t Print::printFloat(double number, uint8_t digits) From fd90b4539fc0b0d44a23fe670d19e200bbda9153 Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Tue, 4 Apr 2023 01:28:44 +0200 Subject: [PATCH 4/7] fixed comment --- cores/arduino/Print.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index ed4d13111..9080ab751 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -227,7 +227,6 @@ size_t Print::printNumber(unsigned long n, uint8_t base) } // else: skip leading zeros c = access[i] & 0x0f; if (c != 0 || written != 0) { - // skip leading zeros c = (c < 10 ? c + '0' : c + 'A' - 10); written += write(c); } // else: skip leading zeros From 66645a2c6022e8f73a0e7f18a28252a42e512b36 Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Tue, 4 Apr 2023 01:31:54 +0200 Subject: [PATCH 5/7] fixed comment --- cores/arduino/Print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 9080ab751..cec90dde9 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -269,7 +269,7 @@ size_t Print::printNumber(unsigned long n, uint8_t base) uint8_t digits = 0; char avoid_overflow = n % base; - // this step and 'avoid_overflow' will make sure it stays in unsigned long range beeing able to print all 10 digits no matter what + // this step and 'avoid_overflow' will make sure it stays in unsigned long range being able to print all 10 digits no matter what n /= base; // reverse the number and count digits From e5c727ef6a2cb3e95e9e570d1938636449dec537 Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Tue, 4 Apr 2023 11:44:32 +0200 Subject: [PATCH 6/7] fixed printNumber base2 and base16 code for -mint8 --- cores/arduino/Print.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index cec90dde9..7db68f48f 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -218,7 +218,7 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { uint8_t *access = (uint8_t*) &n; uint8_t written = 0; - for (int8_t i=3; i>=0; i--) { + for (int8_t i=sizeof(unsigned long)-1; i>=0; i--) { char c; c = (access[i] & 0xf0) >> 4; if (c != 0 || written != 0) { @@ -238,7 +238,7 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { uint8_t *access = (uint8_t*) &n; uint8_t written = 0; - for (int8_t i=3; i>=0; i--) { + for (int8_t i=sizeof(unsigned long)-1; i>=0; i--) { if (access[i] == 0 && written == 0) { // skip leading zeros continue; From a81294fd87572f2f53a52072e971903451afd176 Mon Sep 17 00:00:00 2001 From: DEvil0000 Date: Tue, 4 Apr 2023 19:38:48 +0200 Subject: [PATCH 7/7] avoid writing to base variable so the compiler has a chance of better optimization due to it being basically const then --- cores/arduino/Print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 7db68f48f..efca8c2be 100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -208,7 +208,7 @@ size_t Print::printNumber(unsigned long n, uint8_t base) } // prevent crash if called with base == 1 - if (base < 2) base = 10; + if (base < 2) return printNumber(n, 10); // use -D ARDUINO_PRINT_NUMBER_GENERIC_ONLY when compiling to get only the generic version #ifndef ARDUINO_PRINT_NUMBER_GENERIC_ONLY