From d4acb08bad259e7882a215a7b6c416616dd24823 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 9 Mar 2022 14:16:23 -0800 Subject: [PATCH 01/59] README.md: Fix incorrect link --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ff335e4..da92359 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,7 @@ a single library needs to be installed since v1.1: * Search for "AceRoutine". Click Install. -The direct dependency to the [AceRoutine](https://github.com/bxparks/AceRoutine) +The direct dependency to the [AceCommon](https://github.com/bxparks/AceCommon) library was removed in v1.4.2, but some of the programs under `tests/` and `examples/` may still require the `AceCommon` library to be installed. @@ -479,12 +479,12 @@ sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 ``` -The `CoroutineScheduler` consumes only 2 bytes of memory no matter how many -coroutines are created. That's because it depends on a singly-linked list whose -pointers live on the `Coroutine` object, not in the `CoroutineScheduler`. But -using the `CoroutineScheduler::loop()` instead of calling -`Coroutine::runCoroutine()` directly increases flash memory usage by 70-100 -bytes. +The `CoroutineScheduler` consumes only 2 bytes (8-bit processors) or 4 bytes +(32-bit processors) of static memory no matter how many coroutines are created. +That's because it depends on a singly-linked list whose pointers live on the +`Coroutine` object, not in the `CoroutineScheduler`. But using the +`CoroutineScheduler::loop()` instead of calling `Coroutine::runCoroutine()` +directly increases flash memory usage by 70-100 bytes. The `Channel` object requires 2 copies of the parameterized `` type so its size is equal to `1 + 2 * sizeof(T)`, rounded to the nearest memory alignment From c0e8bf7b2f87aa5d59cd1d39b2ddea9624d4dc5c Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 9 Mar 2022 14:18:02 -0800 Subject: [PATCH 02/59] README.md: Fix grammar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da92359..b6ed267 100644 --- a/README.md +++ b/README.md @@ -305,7 +305,7 @@ The development version can be installed by cloning the following git repo: * AceRoutine (https://github.com/bxparks/AceRoutine) -You can copy these directories to the `./libraries` directory used by the +You can copy this directory to the `./libraries` directory used by the Arduino IDE. (The result is a directory named `./libraries/AceRoutine`). Or you can create symlinks from `/.libraries` to this directory. From eeced2dab194366d975258d787e31561861ff184 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 09:17:05 -0700 Subject: [PATCH 03/59] Coroutine.h: Add setCName(), getCName(), setFName(), getFName(), printNameTo() --- src/ace_routine/Coroutine.h | 57 ++++++++++++++++++++++++- tests/AceRoutineTest/AceRoutineTest.ino | 40 ++++++++++++++++- tests/AceRoutineTest/Makefile | 2 +- 3 files changed, 95 insertions(+), 4 deletions(-) diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index ead0fba..288f5a4 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -29,6 +29,7 @@ SOFTWARE. #include // Print #include "ClockInterface.h" +class __FlashStringHelper; class AceRoutineTest_statusStrings; class SuspendTest_suspendAndResume; @@ -279,6 +280,13 @@ class CoroutineTemplate { friend class ::AceRoutineTest_statusStrings; friend class ::SuspendTest_suspendAndResume; + public: + /** Coroutine name is a `const char*` c-string. */ + static const uint8_t kNameTypeCString = 0; + + /** Coroutine name is a `const __FlashStringHelper*` f-string. */ + static const uint8_t kNameTypeFString = 1; + public: /** * The body of the coroutine. The COROUTINE macro creates a subclass of @@ -308,12 +316,53 @@ class CoroutineTemplate { */ virtual void setupCoroutine() {} + /** + * Return the type of the name string, either kNameTypeCString or + * kNameTypeFString. + */ + uint8_t getNameType() const { return mNameType; } + + /** Set the name of the coroutine to the given c-string. */ + void setCName(const char* name) { + mNameType = kNameTypeCString; + mName = name; + } + + /** Set the name of the coroutine to the given f-string. */ + void setFName(const __FlashStringHelper* name) { + mNameType = kNameTypeFString; + mName = (const char*) name; + } + + /** Get name of the coroutine assuming it's a c-string. Nullable. */ + const char* getCName() const { return mName; } + + /** Get name of the coroutine assuming it's an f-string. Nullable. */ + const __FlashStringHelper* getFName() const { + return (const __FlashStringHelper*) mName; + } + + /** + * Print name to the given Printer. If the name is null, then print the + * hexadecimal representation of the pointer to the coroutine. + */ + void printNameTo(Print& printer) const { + if (mName == nullptr) { + printer.print("0x"); + printer.print((uintptr_t) this, 16); + } else if (mNameType == kNameTypeCString) { + printer.print(mName); + } else { + printer.print((const __FlashStringHelper*) mName); + } + } + /** * Suspend the coroutine at the next scheduler iteration. If the coroutine * is already in the process of ending or is already terminated, then this * method does nothing. A coroutine cannot use this method to suspend * itself, it can only suspend some other coroutine. Currently, there is no - * ability for a coroutine to suspend itself, that would require the + * ability for a coroutine to suspend itself. I think that would require the * addition of a COROUTINE_SUSPEND() macro. Also, this method works only if * the CoroutineScheduler::loop() is used because the suspend functionality * is implemented by the CoroutineScheduler. @@ -668,6 +717,12 @@ class CoroutineTemplate { /** Address of the label used by the computed-goto. */ void* mJumpPoint = nullptr; + /** Name of the coroutine. (Optional) */ + const char* mName = nullptr; + + /** String type of the coroutine mName. */ + uint8_t mNameType = kNameTypeCString; + /** Run-state of the coroutine. */ Status mStatus = kStatusYielding; diff --git a/tests/AceRoutineTest/AceRoutineTest.ino b/tests/AceRoutineTest/AceRoutineTest.ino index 0e3d172..67e5b50 100644 --- a/tests/AceRoutineTest/AceRoutineTest.ino +++ b/tests/AceRoutineTest/AceRoutineTest.ino @@ -1,13 +1,16 @@ #line 2 "AceRoutineTest.ino" +#include +#include // PrintStr<> #include -#include +#include // TestRunner #include "ace_routine/testing/TestableCoroutine.h" #include "ace_routine/testing/TestableClockInterface.h" using namespace ace_routine; using namespace ace_routine::testing; -using namespace aunit; +using aunit::TestRunner; +using ace_common::PrintStr; // --------------------------------------------------------------------------- @@ -157,6 +160,39 @@ test(AceRoutineTest, macroCoroutine) { // --------------------------------------------------------------------------- +test(AceRoutineTest, name_cstring) { + simpleCoroutine.setCName("simple"); + assertEqual(simpleCoroutine.getNameType(), Coroutine::kNameTypeCString); + assertEqual(simpleCoroutine.getCName(), "simple"); + + PrintStr<16> str; + simpleCoroutine.printNameTo(str); + assertEqual(str.cstr(), "simple"); +} + +test(AceRoutineTest, name_fstring) { + simpleCoroutine.setFName(F("simple")); + assertEqual(simpleCoroutine.getNameType(), Coroutine::kNameTypeFString); + assertEqual(simpleCoroutine.getFName(), F("simple")); + + PrintStr<16> str; + simpleCoroutine.printNameTo(str); + assertEqual(str.cstr(), "simple"); +} + +test(AceRoutineTest, name_nullptr) { + simpleCoroutine.setCName(nullptr); + assertEqual(simpleCoroutine.getNameType(), Coroutine::kNameTypeCString); + assertEqual(simpleCoroutine.getCName(), (const char*) nullptr); + + // Name is printed as a pointer, so begins with "0x". + PrintStr<16> str; + simpleCoroutine.printNameTo(str); + assertEqual(strncmp(str.cstr(), "0x", 2), 0); +} + +// --------------------------------------------------------------------------- + void setup() { #if defined(ARDUINO) delay(1000); // some boards reboot twice diff --git a/tests/AceRoutineTest/Makefile b/tests/AceRoutineTest/Makefile index 01662f3..e99684d 100644 --- a/tests/AceRoutineTest/Makefile +++ b/tests/AceRoutineTest/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := AceRoutineTest -ARDUINO_LIBS := AUnit AceRoutine +ARDUINO_LIBS := AUnit AceRoutine AceCommon include ../../../EpoxyDuino/EpoxyDuino.mk From a1f4c6078e901b3ec07cd3f02cb5104384dae447 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 09:43:41 -0700 Subject: [PATCH 04/59] MemoryBenchmark: Regenerate after adding support for coroutine names --- examples/MemoryBenchmark/README.md | 247 ++++++++++---------- examples/MemoryBenchmark/attiny.txt | 34 +-- examples/MemoryBenchmark/esp32.txt | 40 ++-- examples/MemoryBenchmark/esp8266.txt | 28 +-- examples/MemoryBenchmark/generate_readme.py | 9 +- examples/MemoryBenchmark/micro.txt | 34 +-- examples/MemoryBenchmark/nano.txt | 34 +-- examples/MemoryBenchmark/stm32.txt | 34 +-- examples/MemoryBenchmark/teensy32.txt | 34 +-- 9 files changed, 254 insertions(+), 240 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index e7f60ee..d0005a5 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -14,7 +14,7 @@ calculated flash size can jump around in unexpected ways. **NOTE**: This file was auto-generated using `make README.md`. DO NOT EDIT. -**Version**: AceRoutine v1.4.2 +**Version**: AceRoutine v1.5 **Changes**: @@ -102,6 +102,13 @@ calculated flash size can jump around in unexpected ways. * ESP32 Core from 1.0.6 to 2.0.2 * Teensyduino from 1.54 to 1.56 +* v1.5 + * Add support for human-readable names to coroutine. + * Increases flash usage by 6-10 bytes per coroutine, even if name isn't + used. + * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per + coroutine. + ## How to Generate This requires the [AUniter](https://github.com/bxparks/AUniter) script @@ -172,32 +179,32 @@ $ make README.md | One Delay Function | 450/ 13 | 50/ 2 | | Two Delay Functions | 508/ 15 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 632/ 32 | 232/ 21 | -| Two Coroutines | 802/ 51 | 402/ 40 | +| One Coroutine | 638/ 35 | 238/ 24 | +| Two Coroutines | 822/ 57 | 422/ 46 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 600/ 32 | 200/ 21 | -| Two Coroutines (micros) | 738/ 51 | 338/ 40 | +| One Coroutine (micros) | 606/ 35 | 206/ 24 | +| Two Coroutines (micros) | 758/ 57 | 358/ 46 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 728/ 32 | 328/ 21 | -| Two Coroutines (seconds) | 926/ 51 | 526/ 40 | +| One Coroutine (seconds) | 734/ 35 | 334/ 24 | +| Two Coroutines (seconds) | 946/ 57 | 546/ 46 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 760/ 34 | 360/ 23 | -| Scheduler, Two Coroutines | 924/ 53 | 524/ 42 | +| Scheduler, One Coroutine | 766/ 37 | 366/ 26 | +| Scheduler, Two Coroutines | 944/ 59 | 544/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 728/ 34 | 328/ 23 | -| Scheduler, Two Coroutines (micros) | 860/ 53 | 460/ 42 | +| Scheduler, One Coroutine (micros) | 734/ 37 | 334/ 26 | +| Scheduler, Two Coroutines (micros) | 880/ 59 | 480/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 856/ 34 | 456/ 23 | -| Scheduler, Two Coroutines (seconds) | 1048/ 53 | 648/ 42 | +| Scheduler, One Coroutine (seconds) | 862/ 37 | 462/ 26 | +| Scheduler, Two Coroutines (seconds) | 1068/ 59 | 668/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 812/ 34 | 412/ 23 | -| Scheduler, Two Coroutines (setup) | 1072/ 53 | 672/ 42 | +| Scheduler, One Coroutine (setup) | 818/ 37 | 418/ 26 | +| Scheduler, Two Coroutines (setup) | 1092/ 59 | 692/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 790/ 34 | 390/ 23 | -| Scheduler, Two Coroutines (man setup) | 1058/ 53 | 658/ 42 | +| Scheduler, One Coroutine (man setup) | 796/ 37 | 396/ 26 | +| Scheduler, Two Coroutines (man setup) | 1078/ 59 | 678/ 48 | |---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | -| Blink Coroutine | 756/ 32 | 356/ 21 | +| Blink Coroutine | 762/ 35 | 362/ 24 | +--------------------------------------------------------------------+ ``` @@ -217,32 +224,32 @@ $ make README.md | One Delay Function | 654/ 13 | 48/ 2 | | Two Delay Functions | 714/ 15 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 844/ 32 | 238/ 21 | -| Two Coroutines | 1016/ 51 | 410/ 40 | +| One Coroutine | 850/ 35 | 244/ 24 | +| Two Coroutines | 1036/ 57 | 430/ 46 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 816/ 32 | 210/ 21 | -| Two Coroutines (micros) | 960/ 51 | 354/ 40 | +| One Coroutine (micros) | 822/ 35 | 216/ 24 | +| Two Coroutines (micros) | 980/ 57 | 374/ 46 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 944/ 32 | 338/ 21 | -| Two Coroutines (seconds) | 1148/ 51 | 542/ 40 | +| One Coroutine (seconds) | 950/ 35 | 344/ 24 | +| Two Coroutines (seconds) | 1168/ 57 | 562/ 46 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 968/ 34 | 362/ 23 | -| Scheduler, Two Coroutines | 1132/ 53 | 526/ 42 | +| Scheduler, One Coroutine | 974/ 37 | 368/ 26 | +| Scheduler, Two Coroutines | 1152/ 59 | 546/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 940/ 34 | 334/ 23 | -| Scheduler, Two Coroutines (micros) | 1076/ 53 | 470/ 42 | +| Scheduler, One Coroutine (micros) | 946/ 37 | 340/ 26 | +| Scheduler, Two Coroutines (micros) | 1096/ 59 | 490/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 1068/ 34 | 462/ 23 | -| Scheduler, Two Coroutines (seconds) | 1264/ 53 | 658/ 42 | +| Scheduler, One Coroutine (seconds) | 1074/ 37 | 468/ 26 | +| Scheduler, Two Coroutines (seconds) | 1284/ 59 | 678/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 1018/ 34 | 412/ 23 | -| Scheduler, Two Coroutines (setup) | 1282/ 53 | 676/ 42 | +| Scheduler, One Coroutine (setup) | 1024/ 37 | 418/ 26 | +| Scheduler, Two Coroutines (setup) | 1302/ 59 | 696/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 996/ 34 | 390/ 23 | -| Scheduler, Two Coroutines (man setup) | 1268/ 53 | 662/ 42 | +| Scheduler, One Coroutine (man setup) | 1002/ 37 | 396/ 26 | +| Scheduler, Two Coroutines (man setup) | 1288/ 59 | 682/ 48 | |---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | -| Blink Coroutine | 1158/ 32 | 552/ 21 | +| Blink Coroutine | 1164/ 35 | 558/ 24 | +--------------------------------------------------------------------+ ``` @@ -262,32 +269,32 @@ $ make README.md | One Delay Function | 3602/ 153 | 48/ 2 | | Two Delay Functions | 3662/ 155 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 3732/ 172 | 178/ 21 | -| Two Coroutines | 3904/ 191 | 350/ 40 | +| One Coroutine | 3738/ 175 | 184/ 24 | +| Two Coroutines | 3924/ 197 | 370/ 46 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 3704/ 172 | 150/ 21 | -| Two Coroutines (micros) | 3848/ 191 | 294/ 40 | +| One Coroutine (micros) | 3710/ 175 | 156/ 24 | +| Two Coroutines (micros) | 3868/ 197 | 314/ 46 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 3832/ 172 | 278/ 21 | -| Two Coroutines (seconds) | 4036/ 191 | 482/ 40 | +| One Coroutine (seconds) | 3838/ 175 | 284/ 24 | +| Two Coroutines (seconds) | 4056/ 197 | 502/ 46 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 3856/ 174 | 302/ 23 | -| Scheduler, Two Coroutines | 4020/ 193 | 466/ 42 | +| Scheduler, One Coroutine | 3862/ 177 | 308/ 26 | +| Scheduler, Two Coroutines | 4040/ 199 | 486/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 3828/ 174 | 274/ 23 | -| Scheduler, Two Coroutines (micros) | 3964/ 193 | 410/ 42 | +| Scheduler, One Coroutine (micros) | 3834/ 177 | 280/ 26 | +| Scheduler, Two Coroutines (micros) | 3984/ 199 | 430/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 3956/ 174 | 402/ 23 | -| Scheduler, Two Coroutines (seconds) | 4152/ 193 | 598/ 42 | +| Scheduler, One Coroutine (seconds) | 3962/ 177 | 408/ 26 | +| Scheduler, Two Coroutines (seconds) | 4172/ 199 | 618/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 3906/ 174 | 352/ 23 | -| Scheduler, Two Coroutines (setup) | 4170/ 193 | 616/ 42 | +| Scheduler, One Coroutine (setup) | 3912/ 177 | 358/ 26 | +| Scheduler, Two Coroutines (setup) | 4190/ 199 | 636/ 48 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 3884/ 174 | 330/ 23 | -| Scheduler, Two Coroutines (man setup) | 4156/ 193 | 602/ 42 | +| Scheduler, One Coroutine (man setup) | 3890/ 177 | 336/ 26 | +| Scheduler, Two Coroutines (man setup) | 4176/ 199 | 622/ 48 | |---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | -| Blink Coroutine | 4154/ 172 | 600/ 21 | +| Blink Coroutine | 4160/ 175 | 606/ 24 | +--------------------------------------------------------------------+ ``` @@ -307,32 +314,32 @@ $ make README.md | One Delay Function | 21912/ 3544 | 28/ 4 | | Two Delay Functions | 21960/ 3544 | 76/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 22012/ 3564 | 128/ 24 | -| Two Coroutines | 22156/ 3584 | 272/ 44 | +| One Coroutine | 22016/ 3568 | 132/ 28 | +| Two Coroutines | 22164/ 3592 | 280/ 52 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 22076/ 3564 | 192/ 24 | -| Two Coroutines (micros) | 22220/ 3584 | 336/ 44 | +| One Coroutine (micros) | 22080/ 3568 | 196/ 28 | +| Two Coroutines (micros) | 22228/ 3592 | 344/ 52 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 22028/ 3564 | 144/ 24 | -| Two Coroutines (seconds) | 22188/ 3584 | 304/ 44 | +| One Coroutine (seconds) | 22032/ 3568 | 148/ 28 | +| Two Coroutines (seconds) | 22196/ 3592 | 312/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 22084/ 3568 | 200/ 28 | -| Scheduler, Two Coroutines | 22188/ 3588 | 304/ 48 | +| Scheduler, One Coroutine | 22088/ 3572 | 204/ 32 | +| Scheduler, Two Coroutines | 22192/ 3596 | 308/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 22148/ 3568 | 264/ 28 | -| Scheduler, Two Coroutines (micros) | 22252/ 3588 | 368/ 48 | +| Scheduler, One Coroutine (micros) | 22152/ 3572 | 268/ 32 | +| Scheduler, Two Coroutines (micros) | 22256/ 3596 | 372/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 22100/ 3568 | 216/ 28 | -| Scheduler, Two Coroutines (seconds) | 22220/ 3588 | 336/ 48 | +| Scheduler, One Coroutine (seconds) | 22104/ 3572 | 220/ 32 | +| Scheduler, Two Coroutines (seconds) | 22224/ 3596 | 340/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 22108/ 3568 | 224/ 28 | -| Scheduler, Two Coroutines (setup) | 22240/ 3588 | 356/ 48 | +| Scheduler, One Coroutine (setup) | 22112/ 3572 | 228/ 32 | +| Scheduler, Two Coroutines (setup) | 22244/ 3596 | 360/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 22100/ 3568 | 216/ 28 | -| Scheduler, Two Coroutines (man setup) | 22236/ 3588 | 352/ 48 | +| Scheduler, One Coroutine (man setup) | 22104/ 3572 | 220/ 32 | +| Scheduler, Two Coroutines (man setup) | 22240/ 3596 | 356/ 56 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | -| Blink Coroutine | 22228/ 3560 | 344/ 20 | +| Blink Coroutine | 22232/ 3564 | 348/ 24 | +--------------------------------------------------------------------+ ``` @@ -353,31 +360,31 @@ $ make README.md | Two Delay Functions | 260441/27916 | 112/ 0 | |---------------------------------------+--------------+-------------| | One Coroutine | 260525/27944 | 196/ 28 | -| Two Coroutines | 260669/27960 | 340/ 44 | +| Two Coroutines | 260669/27968 | 340/ 52 | |---------------------------------------+--------------+-------------| | One Coroutine (micros) | 260541/27944 | 212/ 28 | -| Two Coroutines (micros) | 260701/27960 | 372/ 44 | +| Two Coroutines (micros) | 260701/27968 | 372/ 52 | |---------------------------------------+--------------+-------------| | One Coroutine (seconds) | 260541/27944 | 212/ 28 | -| Two Coroutines (seconds) | 260717/27960 | 388/ 44 | +| Two Coroutines (seconds) | 260717/27968 | 388/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 260573/27944 | 244/ 28 | -| Scheduler, Two Coroutines | 260701/27968 | 372/ 52 | +| Scheduler, One Coroutine | 260573/27952 | 244/ 36 | +| Scheduler, Two Coroutines | 260717/27976 | 388/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 260589/27944 | 260/ 28 | -| Scheduler, Two Coroutines (micros) | 260733/27968 | 404/ 52 | +| Scheduler, One Coroutine (micros) | 260589/27952 | 260/ 36 | +| Scheduler, Two Coroutines (micros) | 260733/27976 | 404/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 260589/27944 | 260/ 28 | -| Scheduler, Two Coroutines (seconds) | 260749/27968 | 420/ 52 | +| Scheduler, One Coroutine (seconds) | 260589/27952 | 260/ 36 | +| Scheduler, Two Coroutines (seconds) | 260749/27976 | 420/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 260605/27944 | 276/ 28 | -| Scheduler, Two Coroutines (setup) | 260765/27968 | 436/ 52 | +| Scheduler, One Coroutine (setup) | 260605/27952 | 276/ 36 | +| Scheduler, Two Coroutines (setup) | 260781/27976 | 452/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 260589/27944 | 260/ 28 | -| Scheduler, Two Coroutines (man setup) | 260749/27968 | 420/ 52 | +| Scheduler, One Coroutine (man setup) | 260589/27952 | 260/ 36 | +| Scheduler, Two Coroutines (man setup) | 260765/27976 | 436/ 60 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | -| Blink Coroutine | 261133/28008 | 804/ 92 | +| Blink Coroutine | 261133/28016 | 804/ 100 | +--------------------------------------------------------------------+ ``` @@ -394,35 +401,35 @@ $ make README.md |---------------------------------------+--------------+-------------| | Baseline | 204573/16060 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 204921/16084 | 348/ 24 | -| Two Delay Functions | 204993/16084 | 420/ 24 | +| One Delay Function | 204713/16068 | 140/ 8 | +| Two Delay Functions | 204785/16068 | 212/ 8 | |---------------------------------------+--------------+-------------| -| One Coroutine | 205025/16108 | 452/ 48 | -| Two Coroutines | 205189/16124 | 616/ 64 | +| One Coroutine | 204821/16092 | 248/ 32 | +| Two Coroutines | 204989/16116 | 416/ 56 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 205013/16108 | 440/ 48 | -| Two Coroutines (micros) | 205177/16124 | 604/ 64 | +| One Coroutine (micros) | 204809/16092 | 236/ 32 | +| Two Coroutines (micros) | 204977/16116 | 404/ 56 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 205041/16108 | 468/ 48 | -| Two Coroutines (seconds) | 205221/16124 | 648/ 64 | +| One Coroutine (seconds) | 204837/16092 | 264/ 32 | +| Two Coroutines (seconds) | 205021/16116 | 448/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 205089/16108 | 516/ 48 | -| Scheduler, Two Coroutines | 205229/16132 | 656/ 72 | +| Scheduler, One Coroutine | 204885/16100 | 312/ 40 | +| Scheduler, Two Coroutines | 205025/16124 | 452/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 205077/16108 | 504/ 48 | -| Scheduler, Two Coroutines (micros) | 205217/16132 | 644/ 72 | +| Scheduler, One Coroutine (micros) | 204873/16100 | 300/ 40 | +| Scheduler, Two Coroutines (micros) | 205013/16124 | 440/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 205105/16108 | 532/ 48 | -| Scheduler, Two Coroutines (seconds) | 205261/16132 | 688/ 72 | +| Scheduler, One Coroutine (seconds) | 204901/16100 | 328/ 40 | +| Scheduler, Two Coroutines (seconds) | 205057/16124 | 484/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 205117/16108 | 544/ 48 | -| Scheduler, Two Coroutines (setup) | 205289/16132 | 716/ 72 | +| Scheduler, One Coroutine (setup) | 204913/16100 | 340/ 40 | +| Scheduler, Two Coroutines (setup) | 205085/16124 | 512/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 205109/16108 | 536/ 48 | -| Scheduler, Two Coroutines (man setup) | 205289/16132 | 716/ 72 | +| Scheduler, One Coroutine (man setup) | 204905/16100 | 332/ 40 | +| Scheduler, Two Coroutines (man setup) | 205085/16124 | 512/ 64 | |---------------------------------------+--------------+-------------| -| Blink Function | 205273/16092 | 700/ 32 | -| Blink Coroutine | 205377/16108 | 804/ 48 | +| Blink Function | 205065/16076 | 492/ 16 | +| Blink Coroutine | 205173/16100 | 600/ 40 | +--------------------------------------------------------------------+ ``` @@ -443,32 +450,32 @@ $ make README.md | One Delay Function | 10264/ 4156 | 32/ 4 | | Two Delay Functions | 10292/ 4156 | 60/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 10380/ 4176 | 148/ 24 | -| Two Coroutines | 10496/ 4196 | 264/ 44 | +| One Coroutine | 10384/ 4180 | 152/ 28 | +| Two Coroutines | 10504/ 4204 | 272/ 52 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 10436/ 4176 | 204/ 24 | -| Two Coroutines (micros) | 10540/ 4196 | 308/ 44 | +| One Coroutine (micros) | 10440/ 4180 | 208/ 28 | +| Two Coroutines (micros) | 10548/ 4204 | 316/ 52 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 10400/ 4176 | 168/ 24 | -| Two Coroutines (seconds) | 10536/ 4196 | 304/ 44 | +| One Coroutine (seconds) | 10404/ 4180 | 172/ 28 | +| Two Coroutines (seconds) | 10544/ 4204 | 312/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 10444/ 4180 | 212/ 28 | -| Scheduler, Two Coroutines | 10556/ 4200 | 324/ 48 | +| Scheduler, One Coroutine | 10448/ 4184 | 216/ 32 | +| Scheduler, Two Coroutines | 10564/ 4208 | 332/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 10500/ 4180 | 268/ 28 | -| Scheduler, Two Coroutines (micros) | 10600/ 4200 | 368/ 48 | +| Scheduler, One Coroutine (micros) | 10504/ 4184 | 272/ 32 | +| Scheduler, Two Coroutines (micros) | 10608/ 4208 | 376/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 10464/ 4180 | 232/ 28 | -| Scheduler, Two Coroutines (seconds) | 10596/ 4200 | 364/ 48 | +| Scheduler, One Coroutine (seconds) | 10468/ 4184 | 236/ 32 | +| Scheduler, Two Coroutines (seconds) | 10604/ 4208 | 372/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 10476/ 4180 | 244/ 28 | -| Scheduler, Two Coroutines (setup) | 10620/ 4200 | 388/ 48 | +| Scheduler, One Coroutine (setup) | 10480/ 4184 | 248/ 32 | +| Scheduler, Two Coroutines (setup) | 10628/ 4208 | 396/ 56 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 10464/ 4180 | 232/ 28 | -| Scheduler, Two Coroutines (man setup) | 10608/ 4200 | 376/ 48 | +| Scheduler, One Coroutine (man setup) | 10468/ 4184 | 236/ 32 | +| Scheduler, Two Coroutines (man setup) | 10616/ 4208 | 384/ 56 | |---------------------------------------+--------------+-------------| | Blink Function | 10688/ 4160 | 456/ 8 | -| Blink Coroutine | 10812/ 4176 | 580/ 24 | +| Blink Coroutine | 10816/ 4180 | 584/ 28 | +--------------------------------------------------------------------+ ``` diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index 7bc5d2f..7055626 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -1,21 +1,21 @@ 0 400 8192 11 512 1 450 8192 13 512 2 508 8192 15 512 -3 632 8192 32 512 -4 802 8192 51 512 -5 600 8192 32 512 -6 738 8192 51 512 -7 728 8192 32 512 -8 926 8192 51 512 -9 760 8192 34 512 -10 924 8192 53 512 -11 728 8192 34 512 -12 860 8192 53 512 -13 856 8192 34 512 -14 1048 8192 53 512 -15 812 8192 34 512 -16 1072 8192 53 512 -17 790 8192 34 512 -18 1058 8192 53 512 +3 638 8192 35 512 +4 822 8192 57 512 +5 606 8192 35 512 +6 758 8192 57 512 +7 734 8192 35 512 +8 946 8192 57 512 +9 766 8192 37 512 +10 944 8192 59 512 +11 734 8192 37 512 +12 880 8192 59 512 +13 862 8192 37 512 +14 1068 8192 59 512 +15 818 8192 37 512 +16 1092 8192 59 512 +17 796 8192 37 512 +18 1078 8192 59 512 19 546 8192 14 512 -20 756 8192 32 512 +20 762 8192 35 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 128bb41..49e7d7e 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -1,21 +1,21 @@ 0 204573 1310720 16060 327680 -1 204921 1310720 16084 327680 -2 204993 1310720 16084 327680 -3 205025 1310720 16108 327680 -4 205189 1310720 16124 327680 -5 205013 1310720 16108 327680 -6 205177 1310720 16124 327680 -7 205041 1310720 16108 327680 -8 205221 1310720 16124 327680 -9 205089 1310720 16108 327680 -10 205229 1310720 16132 327680 -11 205077 1310720 16108 327680 -12 205217 1310720 16132 327680 -13 205105 1310720 16108 327680 -14 205261 1310720 16132 327680 -15 205117 1310720 16108 327680 -16 205289 1310720 16132 327680 -17 205109 1310720 16108 327680 -18 205289 1310720 16132 327680 -19 205273 1310720 16092 327680 -20 205377 1310720 16108 327680 +1 204713 1310720 16068 327680 +2 204785 1310720 16068 327680 +3 204821 1310720 16092 327680 +4 204989 1310720 16116 327680 +5 204809 1310720 16092 327680 +6 204977 1310720 16116 327680 +7 204837 1310720 16092 327680 +8 205021 1310720 16116 327680 +9 204885 1310720 16100 327680 +10 205025 1310720 16124 327680 +11 204873 1310720 16100 327680 +12 205013 1310720 16124 327680 +13 204901 1310720 16100 327680 +14 205057 1310720 16124 327680 +15 204913 1310720 16100 327680 +16 205085 1310720 16124 327680 +17 204905 1310720 16100 327680 +18 205085 1310720 16124 327680 +19 205065 1310720 16076 327680 +20 205173 1310720 16100 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 471a11b..7d62d3b 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -2,20 +2,20 @@ 1 260377 1044464 27916 81920 2 260441 1044464 27916 81920 3 260525 1044464 27944 81920 -4 260669 1044464 27960 81920 +4 260669 1044464 27968 81920 5 260541 1044464 27944 81920 -6 260701 1044464 27960 81920 +6 260701 1044464 27968 81920 7 260541 1044464 27944 81920 -8 260717 1044464 27960 81920 -9 260573 1044464 27944 81920 -10 260701 1044464 27968 81920 -11 260589 1044464 27944 81920 -12 260733 1044464 27968 81920 -13 260589 1044464 27944 81920 -14 260749 1044464 27968 81920 -15 260605 1044464 27944 81920 -16 260765 1044464 27968 81920 -17 260589 1044464 27944 81920 -18 260749 1044464 27968 81920 +8 260717 1044464 27968 81920 +9 260573 1044464 27952 81920 +10 260717 1044464 27976 81920 +11 260589 1044464 27952 81920 +12 260733 1044464 27976 81920 +13 260589 1044464 27952 81920 +14 260749 1044464 27976 81920 +15 260605 1044464 27952 81920 +16 260781 1044464 27976 81920 +17 260589 1044464 27952 81920 +18 260765 1044464 27976 81920 19 261001 1044464 27988 81920 -20 261133 1044464 28008 81920 +20 261133 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index fcdc69f..27da327 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -38,7 +38,7 @@ **NOTE**: This file was auto-generated using `make README.md`. DO NOT EDIT. -**Version**: AceRoutine v1.4.2 +**Version**: AceRoutine v1.5 **Changes**: @@ -126,6 +126,13 @@ * ESP32 Core from 1.0.6 to 2.0.2 * Teensyduino from 1.54 to 1.56 +* v1.5 + * Add support for human-readable names to coroutine. + * Increases flash usage by 6-10 bytes per coroutine, even if name isn't + used. + * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per + coroutine. + ## How to Generate This requires the [AUniter](https://github.com/bxparks/AUniter) script diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index ad43f16..71da112 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -1,21 +1,21 @@ 0 3554 28672 151 2560 1 3602 28672 153 2560 2 3662 28672 155 2560 -3 3732 28672 172 2560 -4 3904 28672 191 2560 -5 3704 28672 172 2560 -6 3848 28672 191 2560 -7 3832 28672 172 2560 -8 4036 28672 191 2560 -9 3856 28672 174 2560 -10 4020 28672 193 2560 -11 3828 28672 174 2560 -12 3964 28672 193 2560 -13 3956 28672 174 2560 -14 4152 28672 193 2560 -15 3906 28672 174 2560 -16 4170 28672 193 2560 -17 3884 28672 174 2560 -18 4156 28672 193 2560 +3 3738 28672 175 2560 +4 3924 28672 197 2560 +5 3710 28672 175 2560 +6 3868 28672 197 2560 +7 3838 28672 175 2560 +8 4056 28672 197 2560 +9 3862 28672 177 2560 +10 4040 28672 199 2560 +11 3834 28672 177 2560 +12 3984 28672 199 2560 +13 3962 28672 177 2560 +14 4172 28672 199 2560 +15 3912 28672 177 2560 +16 4190 28672 199 2560 +17 3890 28672 177 2560 +18 4176 28672 199 2560 19 3994 28672 154 2560 -20 4154 28672 172 2560 +20 4160 28672 175 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 2e6cb05..f639e58 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -1,21 +1,21 @@ 0 606 30720 11 2048 1 654 30720 13 2048 2 714 30720 15 2048 -3 844 30720 32 2048 -4 1016 30720 51 2048 -5 816 30720 32 2048 -6 960 30720 51 2048 -7 944 30720 32 2048 -8 1148 30720 51 2048 -9 968 30720 34 2048 -10 1132 30720 53 2048 -11 940 30720 34 2048 -12 1076 30720 53 2048 -13 1068 30720 34 2048 -14 1264 30720 53 2048 -15 1018 30720 34 2048 -16 1282 30720 53 2048 -17 996 30720 34 2048 -18 1268 30720 53 2048 +3 850 30720 35 2048 +4 1036 30720 57 2048 +5 822 30720 35 2048 +6 980 30720 57 2048 +7 950 30720 35 2048 +8 1168 30720 57 2048 +9 974 30720 37 2048 +10 1152 30720 59 2048 +11 946 30720 37 2048 +12 1096 30720 59 2048 +13 1074 30720 37 2048 +14 1284 30720 59 2048 +15 1024 30720 37 2048 +16 1302 30720 59 2048 +17 1002 30720 37 2048 +18 1288 30720 59 2048 19 938 30720 14 2048 -20 1158 30720 32 2048 +20 1164 30720 35 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index 6135e2f..ad12082 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -1,21 +1,21 @@ 0 21884 131072 3540 20480 1 21912 131072 3544 20480 2 21960 131072 3544 20480 -3 22012 131072 3564 20480 -4 22156 131072 3584 20480 -5 22076 131072 3564 20480 -6 22220 131072 3584 20480 -7 22028 131072 3564 20480 -8 22188 131072 3584 20480 -9 22084 131072 3568 20480 -10 22188 131072 3588 20480 -11 22148 131072 3568 20480 -12 22252 131072 3588 20480 -13 22100 131072 3568 20480 -14 22220 131072 3588 20480 -15 22108 131072 3568 20480 -16 22240 131072 3588 20480 -17 22100 131072 3568 20480 -18 22236 131072 3588 20480 +3 22016 131072 3568 20480 +4 22164 131072 3592 20480 +5 22080 131072 3568 20480 +6 22228 131072 3592 20480 +7 22032 131072 3568 20480 +8 22196 131072 3592 20480 +9 22088 131072 3572 20480 +10 22192 131072 3596 20480 +11 22152 131072 3572 20480 +12 22256 131072 3596 20480 +13 22104 131072 3572 20480 +14 22224 131072 3596 20480 +15 22112 131072 3572 20480 +16 22244 131072 3596 20480 +17 22104 131072 3572 20480 +18 22240 131072 3596 20480 19 22120 131072 3540 20480 -20 22228 131072 3560 20480 +20 22232 131072 3564 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 564b555..26bad97 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -1,21 +1,21 @@ 0 10232 262144 4152 65536 1 10264 262144 4156 65536 2 10292 262144 4156 65536 -3 10380 262144 4176 65536 -4 10496 262144 4196 65536 -5 10436 262144 4176 65536 -6 10540 262144 4196 65536 -7 10400 262144 4176 65536 -8 10536 262144 4196 65536 -9 10444 262144 4180 65536 -10 10556 262144 4200 65536 -11 10500 262144 4180 65536 -12 10600 262144 4200 65536 -13 10464 262144 4180 65536 -14 10596 262144 4200 65536 -15 10476 262144 4180 65536 -16 10620 262144 4200 65536 -17 10464 262144 4180 65536 -18 10608 262144 4200 65536 +3 10384 262144 4180 65536 +4 10504 262144 4204 65536 +5 10440 262144 4180 65536 +6 10548 262144 4204 65536 +7 10404 262144 4180 65536 +8 10544 262144 4204 65536 +9 10448 262144 4184 65536 +10 10564 262144 4208 65536 +11 10504 262144 4184 65536 +12 10608 262144 4208 65536 +13 10468 262144 4184 65536 +14 10604 262144 4208 65536 +15 10480 262144 4184 65536 +16 10628 262144 4208 65536 +17 10468 262144 4184 65536 +18 10616 262144 4208 65536 19 10688 262144 4160 65536 -20 10812 262144 4176 65536 +20 10816 262144 4180 65536 From ba0d19d420d2f50bb49a9d1769eaabcdf31c6439 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 09:44:40 -0700 Subject: [PATCH 05/59] CoroutineScheduler.h: Change listCoroutine() to use Coroutine::printNameTo() --- src/ace_routine/CoroutineScheduler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ace_routine/CoroutineScheduler.h b/src/ace_routine/CoroutineScheduler.h index 0a0244c..bcdcb33 100644 --- a/src/ace_routine/CoroutineScheduler.h +++ b/src/ace_routine/CoroutineScheduler.h @@ -195,7 +195,7 @@ class CoroutineSchedulerTemplate { for (T_COROUTINE** p = T_COROUTINE::getRoot(); (*p) != nullptr; p = (*p)->getNext()) { printer.print(F("Coroutine ")); - printer.print((uintptr_t) *p); + (*p)->printNameTo(printer); printer.print(F("; status: ")); (*p)->statusPrintTo(printer); printer.println(); From bbb9aa30d3a26b86512e81e19d500ccf1b427e9b Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 09:45:10 -0700 Subject: [PATCH 06/59] examples/SoundManager: Add coroutine names for demo purposes --- examples/SoundManager/SoundManager.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index b96daf9..67c43ee 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -51,12 +51,17 @@ using ace_routine::CoroutineScheduler; SoundRoutine soundRoutine; +EXTERN_COROUTINE(soundManager); void setup() { delay(1000); Serial.begin(115200); while (!Serial); // needed for Leonardo/Micro + // Set names using both c-string and f-string for testing purposes. + soundRoutine.setCName("soundRoutine"); + soundManager.setFName(F("soundManager")); + CoroutineScheduler::setup(); } From d89ed1df519dcac5fa9a2d8ef23db11b2b8fc55c Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 10:09:23 -0700 Subject: [PATCH 07/59] USER_GUIDE.md: Add docs for coroutine names --- CHANGELOG.md | 8 ++++++++ USER_GUIDE.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd9ee71..2a630f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Changelog * Unreleased + * (Re)add support for human-readable coroutine names by adding the following + methods to the `Coroutine` class: `setCName()`, `setFName()`, + `getCName()`, `getFName()`, `getNameType()`, and `printNameTo()`. + * This is an optional feature which helps debugging. Coroutines do not + need to have human readable names. + * Increases flash usage by 6-10 bytes per coroutine. + * Increases static ram usage by 3 bytes (AVR) or 4 bytes (32-bit) per + coroutine. * 1.4.2 (2022-02-04) * Remove dependency to AceCommon library in `libraries.properties`. * AceRoutine core no longer depends on AceCommon. diff --git a/USER_GUIDE.md b/USER_GUIDE.md index cd41375..bfc4c52 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -14,6 +14,7 @@ is installed. * [Overall Structure](#OverallStructure) * [Coroutine Class](#CoroutineClass) * [Coroutine Instance](#CoroutineInstance) + * [Coroutine Names](#CoroutineNames) * [Coroutine Body](#CoroutineBody) * [Begin and End Markers](#BeginAndEnd) * [Yield](#Yield) @@ -244,6 +245,50 @@ MyCoroutine routine2; For more details on manual Coroutine instances, see the [Manual Coroutines](#ManualCoroutines) section below. + +### Coroutine Names + +(Added in v1.5. Prior to v1.3, the name was automatically assigned to the +coroutine using the `COROUTINE()` macro. It was removed in v1.3 to save flash +memory. In v1.5, the feature is added back as an optional feature so that the +end-user can decide whether they want to spend the extra flash storage for this +feature.) + +A coroutine can be assigned a human-readable name through the following methods: + +```C++ +class Coroutine { + public: + static const uint8_t kNameTypeCString = 0; + static const uint8_t kNameTypeFString = 1; + + public: + void Coroutine::setCName(const char* name); + void Coroutine::setFName(const __FlashStringHelper* name); + + const char* Coroutine::getCName() const; + const __FlashStringHelper* Coroutine::getFName() const; + + uint8_t getNameType() const; + void printNameTo(Print& printer) const; +}; +`` + +It is expected that the `setCName()` or `setFName()` will be called in the +global `setup()` function. + +On most 32-bit processors, it makes little difference whether a C-string or an +F-string is used. (The exception is the ESP8266.) On AVR processors, using the +F-string will prevent those strings from consuming precious static RAM. + +The `printNameTo()` method prints the coroutine name to the given `Print` +object, which will usually be the `Serial` object. If the name is not set (hence +is the `nullptr`), `printNameTo()` will print the hexadecimal representation of +the pointer to the Coroutine (e.g. "0xe38a"). + +The `CoroutineScheduler::list()` method will now print the coroutine name if it +is defined. + ## Coroutine Body From 16324c44d7e1bcb1253c32c669b309bbf9f0e46d Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 13:36:20 -0700 Subject: [PATCH 08/59] src/CoroutineProfiler,CoroutineLogBinProfiler: Add support for generating log-log frequency distribution of runCoroutine() execution time --- src/AceRoutine.h | 2 + src/ace_routine/Coroutine.h | 49 +++--- src/ace_routine/CoroutineLogBinProfiler.cpp | 161 ++++++++++++++++++++ src/ace_routine/CoroutineLogBinProfiler.h | 107 +++++++++++++ src/ace_routine/CoroutineProfiler.h | 43 ++++++ src/ace_routine/CoroutineScheduler.h | 11 +- 6 files changed, 352 insertions(+), 21 deletions(-) create mode 100644 src/ace_routine/CoroutineLogBinProfiler.cpp create mode 100644 src/ace_routine/CoroutineLogBinProfiler.h create mode 100644 src/ace_routine/CoroutineProfiler.h diff --git a/src/AceRoutine.h b/src/AceRoutine.h index 7534639..2318da0 100644 --- a/src/AceRoutine.h +++ b/src/AceRoutine.h @@ -48,6 +48,8 @@ SOFTWARE. #include "ace_routine/Coroutine.h" #include "ace_routine/CoroutineScheduler.h" +#include "ace_routine/CoroutineProfiler.h" +#include "ace_routine/CoroutineLogBinProfiler.h" #include "ace_routine/Channel.h" #endif diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index 288f5a4..a1633d7 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -264,6 +264,8 @@ extern className##_##name name namespace ace_routine { +class CoroutineProfiler; + /** A lookup table from Status integer to human-readable strings. */ extern const __FlashStringHelper* const sStatusStrings[]; @@ -481,6 +483,31 @@ class CoroutineTemplate { void setupCoroutine(const __FlashStringHelper* /*name*/) ACE_ROUTINE_DEPRECATED {} + /** Set the profiler. */ + void setProfiler(CoroutineProfiler* profiler) { mProfiler = profiler; } + + CoroutineProfiler* getProfiler() const { return mProfiler; } + + /** + * Get the pointer to the root pointer. Implemented as a function static to + * fix the C++ static initialization problem, making it safe to use this in + * other static contexts. + */ + static CoroutineTemplate** getRoot() { + // Use a static variable inside a function to solve the static + // initialization ordering problem. + static CoroutineTemplate* root; + return &root; + } + + /** + * Return the next pointer as a pointer to the pointer, similar to + * getRoot(). This makes it much easier to manipulate a singly-linked list. + * Also makes setNext() method unnecessary. Should be used only by + * CoroutineScheduler. + */ + CoroutineTemplate** getNext() { return &mNext; } + protected: /** * The execution status of the coroutine, corresponding to the @@ -678,26 +705,6 @@ class CoroutineTemplate { CoroutineTemplate(const CoroutineTemplate&) = delete; CoroutineTemplate& operator=(const CoroutineTemplate&) = delete; - /** - * Get the pointer to the root pointer. Implemented as a function static to - * fix the C++ static initialization problem, making it safe to use this in - * other static contexts. - */ - static CoroutineTemplate** getRoot() { - // Use a static variable inside a function to solve the static - // initialization ordering problem. - static CoroutineTemplate* root; - return &root; - } - - /** - * Return the next pointer as a pointer to the pointer, similar to - * getRoot(). This makes it much easier to manipulate a singly-linked list. - * Also makes setNext() method unnecessary. Should be used only by - * CoroutineScheduler. - */ - CoroutineTemplate** getNext() { return &mNext; } - /** * Insert the current coroutine at the root of the singly linked list. This * is the most efficient and becomes the default with v1.2 because the @@ -739,6 +746,8 @@ class CoroutineTemplate { * milliseconds, microseconds, or seconds. */ uint16_t mDelayDuration; + + CoroutineProfiler* mProfiler = nullptr; }; /** diff --git a/src/ace_routine/CoroutineLogBinProfiler.cpp b/src/ace_routine/CoroutineLogBinProfiler.cpp new file mode 100644 index 0000000..b3ade41 --- /dev/null +++ b/src/ace_routine/CoroutineLogBinProfiler.cpp @@ -0,0 +1,161 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include +#include // memset() +#include // printfTo() +#include "Coroutine.h" +#include "CoroutineLogBinProfiler.h" + +using ace_common::printfTo; + +namespace ace_routine { + +CoroutineLogBinProfiler::CoroutineLogBinProfiler() { + init(); +} + +void CoroutineLogBinProfiler::init() { + memset(mBins, 0, sizeof(mBins)); +} + +void CoroutineLogBinProfiler::updateElapsedMicros(uint32_t micros) { + uint8_t index = 0; // [0, 31] + + // The index is the bit number (0-31) of the most significant bit. So each bin + // contains the number of samples whose elapsed micros is between 2^i and + // 2^(i+1). Example, for Bin 3, and this bin contains the number of samples + // which satsify (8us <= elapsed < 16us). The exception is Bin 0 because it + // includes samples where elapsed = 0 as well, so the sample interval for Bin + // 0 is (0 <= elapsed < 2), instead of (1 <= elapsed < 2). + while (true) { + micros >>= 1; + if (micros == 0) break; + index++; + } + uint16_t count = mBins[index]; + if (count < UINT16_MAX) { + mBins[index]++; + } +} + +// Labels for each bin in mBins. +static const char* kBinLabels[CoroutineLogBinProfiler::kNumBins] = { + "<2us", + "<4us", + "<8us", + "<16us", + "<32us", + "<64us", + "<128us", + "<256us", + "<512us", + "<1ms", + "<2ms", + "<4ms", + "<8ms", + "<16ms", + "<32ms", + "<64ms", + "<128ms", + "<256ms", + "<512ms", + "<1s", + "<2s", + "<4s", + "<8s", + "<16s", + "<32s", + "<64s", + "<128s", + "<256s", + "<512s", + "<1024s", + "<2048s", + "<4096s", +}; + +void CoroutineLogBinProfiler::printHeaderTo( + Print& printer, uint8_t binStart, uint8_t binEnd) const { + if (binEnd <= binStart) return; + + binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; + for (uint8_t i = binStart; i < binEnd; i++) { + ace_common::printfTo(printer, "%6s", kBinLabels[i]); + } +} + +void CoroutineLogBinProfiler::printTo( + Print& printer, uint8_t binStart, uint8_t binEnd) const { + if (binEnd <= binStart) return; + + binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; + for (uint8_t i = binStart; i < binEnd; i++) { + uint16_t count = mBins[i]; + ace_common::printfTo(printer, "%6d", count); + } + + uint32_t remaining = 0; + for (uint8_t i = binEnd; i < kNumBins; i++) { + remaining += mBins[i]; + } + if (remaining > 0) { + ace_common::printfTo(printer, "%6ld", (unsigned long) remaining); + } +} + +void CoroutineLogBinProfiler::printBinsTo( + Print& printer, Coroutine** root, uint8_t binStart, uint8_t binEnd) { + if (binEnd <= binStart) return; + + bool isHeaderPrinted = false; + for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + CoroutineLogBinProfiler* profiler = + (CoroutineLogBinProfiler*) (*p)->getProfiler(); + if (! profiler) continue; + + // Print header if needed. + if (! isHeaderPrinted) { + printfTo(printer, "%12.12s", ""); + profiler->printHeaderTo(printer, binStart, binEnd); + printer.println(); + isHeaderPrinted = true; + } + + // Print the bins. The number of digits is automatically a log10() of the + // counts, so we should be able to visually scan the table and see which + // coroutine is taking too long. + printfTo(printer, "%12.12s", (*p)->getCName()); + profiler->printTo(printer, binStart, binEnd); + printer.println(); + + // TODO: It'd be useful to sum up the remaining buckets after binEnd, and + // print the number of samples that weren't printed in the loop above. + + // Maybe control this using a boolean flag. + profiler->init(); + } +} + +} diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h new file mode 100644 index 0000000..068d843 --- /dev/null +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -0,0 +1,107 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef ACE_ROUTINE_COROUTINE_LOG_BIN_PROFILER_H +#define ACE_ROUTINE_COROUTINE_LOG_BIN_PROFILER_H + +#include // uint8_t, uint32_t +#include "Coroutine.h" +#include "CoroutineProfiler.h" + +class Print; + +namespace ace_routine { + +/** + * Class that maintains the frequency count of the elapsed time of + * runCoroutine() in an array of bins where each bin is a log2() logarithm of + * the elapsed time in microseconds. An instance of this class can be attached + * to a given coroutine through the `Coroutine::setProfiler()` method. + * + * After sufficient number of samples are collected, the frequency distribution + * of all profilers for all coroutines can be printed as a table using the + * `printBinsTo()` static helper function. Each bin is printed as a 5-digit + * number (since the bins use a `uint16_t` integer for the count). The number of + * digits in the printed number is equivalent to the log10() of the frequency + * count. (To see why that's true, imagine if each digit of the bin count was + * replaced by a '*' character.) Therefore the table is a rough ASCII version of + * a log-log graph of the frequency count. + * + * For example, here is the output of `printBinsTo()` for the sample program in + * `examples/SoundManager`: + * + * @verbatim + * <2us <4us <8us <16us <32us <64us<128us<256us<512us <1ms <2ms + * soundManag 621 2091 0 0 5 3 0 0 0 0 1 + * soundRouti 2162 553 1 0 1 2 2 1 0 0 0 + * + * The `init()` method resets the frequency count of the bins. + * + * @endverbatim + */ +class CoroutineLogBinProfiler : public CoroutineProfiler { + public: + static const uint8_t kNumBins = 32; + + public: + /** Constructor. */ + CoroutineLogBinProfiler(); + + /** Clear the bins. */ + void init(); + + void updateElapsedMicros(uint32_t micros) override; + + /** + * Print the header related to this profiler. + * + * @param binStart start index of the bins (0-31) + * @param binEnd end index (exclusive) of the bins (0-32) + */ + void printHeaderTo(Print& printer, uint8_t binStart, uint8_t binEnd) const; + + /** + * Print the bins of this profiler. + * + * @param binStart start index of the bins (0-31) + * @param binEnd end index (exclusive) of the bins (0-32) + */ + void printTo(Print& printer, uint8_t binStart, uint8_t binEnd) const; + + /** + * Loop over all coroutines and print the ASCII version of a histogram. + * + * @param binStart start index of the bins (0-31) + * @param binEnd end inex (exclusive) of the bins (0-32) + */ + static void printBinsTo( + Print& printer, Coroutine** root, uint8_t binStart, uint8_t binEnd); + + public: + uint16_t mBins[kNumBins]; +}; + +} + +#endif diff --git a/src/ace_routine/CoroutineProfiler.h b/src/ace_routine/CoroutineProfiler.h new file mode 100644 index 0000000..da09c71 --- /dev/null +++ b/src/ace_routine/CoroutineProfiler.h @@ -0,0 +1,43 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef ACE_ROUTINE_COROUTINE_PROFILER_H +#define ACE_ROUTINE_COROUTINE_PROFILER_H + +#include // uint32_t + +namespace ace_routine { + +class CoroutineProfiler { + public: + /** + * Process the completion of the runCoroutine() method which took + * `micros` microseconds. + */ + virtual void updateElapsedMicros(uint32_t micros) = 0; +}; + +} + +#endif diff --git a/src/ace_routine/CoroutineScheduler.h b/src/ace_routine/CoroutineScheduler.h index bcdcb33..59a5c3f 100644 --- a/src/ace_routine/CoroutineScheduler.h +++ b/src/ace_routine/CoroutineScheduler.h @@ -29,6 +29,7 @@ SOFTWARE. #include // Serial, Print #endif #include "Coroutine.h" +#include "CoroutineProfiler.h" class Print; @@ -172,7 +173,15 @@ class CoroutineSchedulerTemplate { // its continuation context determines whether to call // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or // Coroutine::isDelaySecondsExpired(). - (*mCurrent)->runCoroutine(); + if ((*mCurrent)->mProfiler) { + uint32_t startMicros = T_COROUTINE::coroutineMicros(); + (*mCurrent)->runCoroutine(); + uint32_t elapsedMicros = T_COROUTINE::coroutineMicros() + - startMicros; + (*mCurrent)->mProfiler->updateElapsedMicros(elapsedMicros); + } else { + (*mCurrent)->runCoroutine(); + } break; case T_COROUTINE::kStatusEnding: From 1120cf673177b2c72e809ebf75dcb8220d4c6ebf Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 13:36:47 -0700 Subject: [PATCH 09/59] examples/SoundManager: Add CoroutineProfiler as a demo --- examples/SoundManager/Makefile | 3 ++- examples/SoundManager/SoundManager.ino | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/examples/SoundManager/Makefile b/examples/SoundManager/Makefile index 41e999f..6660500 100644 --- a/examples/SoundManager/Makefile +++ b/examples/SoundManager/Makefile @@ -2,5 +2,6 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := SoundManager -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceRoutine AceCommon +EXTRA_CXXFLAGS := -g include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index 67c43ee..e11d296 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -45,14 +45,29 @@ */ #include +#include #include #include "SoundRoutine.h" +using ace_routine::Coroutine;; using ace_routine::CoroutineScheduler; +using ace_routine::CoroutineLogBinProfiler; +using ace_common::printfTo; SoundRoutine soundRoutine; EXTERN_COROUTINE(soundManager); +COROUTINE(printProfile) { + COROUTINE_LOOP() { + CoroutineLogBinProfiler::printBinsTo(Serial, getRoot(), 0, 16); + COROUTINE_DELAY_SECONDS(10); + } +} + + +CoroutineLogBinProfiler soundRoutineProfiler; +CoroutineLogBinProfiler soundManagerProfiler; + void setup() { delay(1000); Serial.begin(115200); @@ -62,6 +77,9 @@ void setup() { soundRoutine.setCName("soundRoutine"); soundManager.setFName(F("soundManager")); + soundRoutine.setProfiler(&soundRoutineProfiler); + soundManager.setProfiler(&soundManagerProfiler); + CoroutineScheduler::setup(); } From 4a00a5942a8d99fbed92ff88c4b5fae250939712 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 14:38:27 -0700 Subject: [PATCH 10/59] MemoryBenchmark: Regenerate after adding CoroutineProfiler --- examples/MemoryBenchmark/README.md | 253 ++++++++++---------- examples/MemoryBenchmark/attiny.txt | 34 +-- examples/MemoryBenchmark/esp32.txt | 40 ++-- examples/MemoryBenchmark/esp8266.txt | 34 +-- examples/MemoryBenchmark/generate_readme.py | 9 + examples/MemoryBenchmark/micro.txt | 34 +-- examples/MemoryBenchmark/nano.txt | 34 +-- examples/MemoryBenchmark/stm32.txt | 34 +-- examples/MemoryBenchmark/teensy32.txt | 34 +-- 9 files changed, 262 insertions(+), 244 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index d0005a5..37e38f6 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -108,6 +108,15 @@ calculated flash size can jump around in unexpected ways. used. * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per coroutine. + * Add a `CoroutineLogBinProfiler` to 2 coroutines. + * Use a 3rd coroutine to print the frequency count to the `Serial` + output every 10 seconds. + * Provide `CoroutineLogBinProfiler::printBinsTo()` which prints + a table of the frequency count over all coroutines. This represents a + poor-man's version of the log-log graph of the frequency count. + * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes + for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is + not used. This is a one-time hit. ## How to Generate @@ -179,32 +188,32 @@ $ make README.md | One Delay Function | 450/ 13 | 50/ 2 | | Two Delay Functions | 508/ 15 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 638/ 35 | 238/ 24 | -| Two Coroutines | 822/ 57 | 422/ 46 | +| One Coroutine | 642/ 37 | 242/ 26 | +| Two Coroutines | 834/ 61 | 434/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 606/ 35 | 206/ 24 | -| Two Coroutines (micros) | 758/ 57 | 358/ 46 | +| One Coroutine (micros) | 610/ 37 | 210/ 26 | +| Two Coroutines (micros) | 770/ 61 | 370/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 734/ 35 | 334/ 24 | -| Two Coroutines (seconds) | 946/ 57 | 546/ 46 | +| One Coroutine (seconds) | 738/ 37 | 338/ 26 | +| Two Coroutines (seconds) | 958/ 61 | 558/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 766/ 37 | 366/ 26 | -| Scheduler, Two Coroutines | 944/ 59 | 544/ 48 | +| Scheduler, One Coroutine | 866/ 39 | 466/ 28 | +| Scheduler, Two Coroutines | 1052/ 63 | 652/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 734/ 37 | 334/ 26 | -| Scheduler, Two Coroutines (micros) | 880/ 59 | 480/ 48 | +| Scheduler, One Coroutine (micros) | 834/ 39 | 434/ 28 | +| Scheduler, Two Coroutines (micros) | 988/ 63 | 588/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 862/ 37 | 462/ 26 | -| Scheduler, Two Coroutines (seconds) | 1068/ 59 | 668/ 48 | +| Scheduler, One Coroutine (seconds) | 962/ 39 | 562/ 28 | +| Scheduler, Two Coroutines (seconds) | 1176/ 63 | 776/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 818/ 37 | 418/ 26 | -| Scheduler, Two Coroutines (setup) | 1092/ 59 | 692/ 48 | +| Scheduler, One Coroutine (setup) | 920/ 39 | 520/ 28 | +| Scheduler, Two Coroutines (setup) | 1202/ 63 | 802/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 796/ 37 | 396/ 26 | -| Scheduler, Two Coroutines (man setup) | 1078/ 59 | 678/ 48 | +| Scheduler, One Coroutine (man setup) | 896/ 39 | 496/ 28 | +| Scheduler, Two Coroutines (man setup) | 1186/ 63 | 786/ 52 | |---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | -| Blink Coroutine | 762/ 35 | 362/ 24 | +| Blink Coroutine | 766/ 37 | 366/ 26 | +--------------------------------------------------------------------+ ``` @@ -224,32 +233,32 @@ $ make README.md | One Delay Function | 654/ 13 | 48/ 2 | | Two Delay Functions | 714/ 15 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 850/ 35 | 244/ 24 | -| Two Coroutines | 1036/ 57 | 430/ 46 | +| One Coroutine | 854/ 37 | 248/ 26 | +| Two Coroutines | 1048/ 61 | 442/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 822/ 35 | 216/ 24 | -| Two Coroutines (micros) | 980/ 57 | 374/ 46 | +| One Coroutine (micros) | 826/ 37 | 220/ 26 | +| Two Coroutines (micros) | 992/ 61 | 386/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 950/ 35 | 344/ 24 | -| Two Coroutines (seconds) | 1168/ 57 | 562/ 46 | +| One Coroutine (seconds) | 954/ 37 | 348/ 26 | +| Two Coroutines (seconds) | 1180/ 61 | 574/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 974/ 37 | 368/ 26 | -| Scheduler, Two Coroutines | 1152/ 59 | 546/ 48 | +| Scheduler, One Coroutine | 1078/ 39 | 472/ 28 | +| Scheduler, Two Coroutines | 1264/ 63 | 658/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 946/ 37 | 340/ 26 | -| Scheduler, Two Coroutines (micros) | 1096/ 59 | 490/ 48 | +| Scheduler, One Coroutine (micros) | 1050/ 39 | 444/ 28 | +| Scheduler, Two Coroutines (micros) | 1208/ 63 | 602/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 1074/ 37 | 468/ 26 | -| Scheduler, Two Coroutines (seconds) | 1284/ 59 | 678/ 48 | +| Scheduler, One Coroutine (seconds) | 1178/ 39 | 572/ 28 | +| Scheduler, Two Coroutines (seconds) | 1396/ 63 | 790/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 1024/ 37 | 418/ 26 | -| Scheduler, Two Coroutines (setup) | 1302/ 59 | 696/ 48 | +| Scheduler, One Coroutine (setup) | 1128/ 39 | 522/ 28 | +| Scheduler, Two Coroutines (setup) | 1414/ 63 | 808/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 1002/ 37 | 396/ 26 | -| Scheduler, Two Coroutines (man setup) | 1288/ 59 | 682/ 48 | +| Scheduler, One Coroutine (man setup) | 1106/ 39 | 500/ 28 | +| Scheduler, Two Coroutines (man setup) | 1400/ 63 | 794/ 52 | |---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | -| Blink Coroutine | 1164/ 35 | 558/ 24 | +| Blink Coroutine | 1168/ 37 | 562/ 26 | +--------------------------------------------------------------------+ ``` @@ -269,32 +278,32 @@ $ make README.md | One Delay Function | 3602/ 153 | 48/ 2 | | Two Delay Functions | 3662/ 155 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 3738/ 175 | 184/ 24 | -| Two Coroutines | 3924/ 197 | 370/ 46 | +| One Coroutine | 3742/ 177 | 188/ 26 | +| Two Coroutines | 3936/ 201 | 382/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 3710/ 175 | 156/ 24 | -| Two Coroutines (micros) | 3868/ 197 | 314/ 46 | +| One Coroutine (micros) | 3714/ 177 | 160/ 26 | +| Two Coroutines (micros) | 3880/ 201 | 326/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 3838/ 175 | 284/ 24 | -| Two Coroutines (seconds) | 4056/ 197 | 502/ 46 | +| One Coroutine (seconds) | 3842/ 177 | 288/ 26 | +| Two Coroutines (seconds) | 4068/ 201 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 3862/ 177 | 308/ 26 | -| Scheduler, Two Coroutines | 4040/ 199 | 486/ 48 | +| Scheduler, One Coroutine | 3966/ 179 | 412/ 28 | +| Scheduler, Two Coroutines | 4152/ 203 | 598/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 3834/ 177 | 280/ 26 | -| Scheduler, Two Coroutines (micros) | 3984/ 199 | 430/ 48 | +| Scheduler, One Coroutine (micros) | 3938/ 179 | 384/ 28 | +| Scheduler, Two Coroutines (micros) | 4096/ 203 | 542/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 3962/ 177 | 408/ 26 | -| Scheduler, Two Coroutines (seconds) | 4172/ 199 | 618/ 48 | +| Scheduler, One Coroutine (seconds) | 4066/ 179 | 512/ 28 | +| Scheduler, Two Coroutines (seconds) | 4284/ 203 | 730/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 3912/ 177 | 358/ 26 | -| Scheduler, Two Coroutines (setup) | 4190/ 199 | 636/ 48 | +| Scheduler, One Coroutine (setup) | 4016/ 179 | 462/ 28 | +| Scheduler, Two Coroutines (setup) | 4302/ 203 | 748/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 3890/ 177 | 336/ 26 | -| Scheduler, Two Coroutines (man setup) | 4176/ 199 | 622/ 48 | +| Scheduler, One Coroutine (man setup) | 3994/ 179 | 440/ 28 | +| Scheduler, Two Coroutines (man setup) | 4288/ 203 | 734/ 52 | |---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | -| Blink Coroutine | 4160/ 175 | 606/ 24 | +| Blink Coroutine | 4164/ 177 | 610/ 26 | +--------------------------------------------------------------------+ ``` @@ -314,32 +323,32 @@ $ make README.md | One Delay Function | 21912/ 3544 | 28/ 4 | | Two Delay Functions | 21960/ 3544 | 76/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 22016/ 3568 | 132/ 28 | -| Two Coroutines | 22164/ 3592 | 280/ 52 | +| One Coroutine | 22016/ 3572 | 132/ 32 | +| Two Coroutines | 22164/ 3600 | 280/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 22080/ 3568 | 196/ 28 | -| Two Coroutines (micros) | 22228/ 3592 | 344/ 52 | +| One Coroutine (micros) | 22080/ 3572 | 196/ 32 | +| Two Coroutines (micros) | 22228/ 3600 | 344/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 22032/ 3568 | 148/ 28 | -| Two Coroutines (seconds) | 22196/ 3592 | 312/ 52 | +| One Coroutine (seconds) | 22032/ 3572 | 148/ 32 | +| Two Coroutines (seconds) | 22196/ 3600 | 312/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 22088/ 3572 | 204/ 32 | -| Scheduler, Two Coroutines | 22192/ 3596 | 308/ 56 | +| Scheduler, One Coroutine | 22208/ 3576 | 324/ 36 | +| Scheduler, Two Coroutines | 22312/ 3604 | 428/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 22152/ 3572 | 268/ 32 | -| Scheduler, Two Coroutines (micros) | 22256/ 3596 | 372/ 56 | +| Scheduler, One Coroutine (micros) | 22208/ 3576 | 324/ 36 | +| Scheduler, Two Coroutines (micros) | 22312/ 3604 | 428/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 22104/ 3572 | 220/ 32 | -| Scheduler, Two Coroutines (seconds) | 22224/ 3596 | 340/ 56 | +| Scheduler, One Coroutine (seconds) | 22224/ 3576 | 340/ 36 | +| Scheduler, Two Coroutines (seconds) | 22344/ 3604 | 460/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 22112/ 3572 | 228/ 32 | -| Scheduler, Two Coroutines (setup) | 22244/ 3596 | 360/ 56 | +| Scheduler, One Coroutine (setup) | 22232/ 3576 | 348/ 36 | +| Scheduler, Two Coroutines (setup) | 22364/ 3604 | 480/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 22104/ 3572 | 220/ 32 | -| Scheduler, Two Coroutines (man setup) | 22240/ 3596 | 356/ 56 | +| Scheduler, One Coroutine (man setup) | 22224/ 3576 | 340/ 36 | +| Scheduler, Two Coroutines (man setup) | 22360/ 3604 | 476/ 64 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | -| Blink Coroutine | 22232/ 3564 | 348/ 24 | +| Blink Coroutine | 22232/ 3568 | 348/ 28 | +--------------------------------------------------------------------+ ``` @@ -359,32 +368,32 @@ $ make README.md | One Delay Function | 260377/27916 | 48/ 0 | | Two Delay Functions | 260441/27916 | 112/ 0 | |---------------------------------------+--------------+-------------| -| One Coroutine | 260525/27944 | 196/ 28 | -| Two Coroutines | 260669/27968 | 340/ 52 | +| One Coroutine | 260525/27952 | 196/ 36 | +| Two Coroutines | 260685/27976 | 356/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 260541/27944 | 212/ 28 | -| Two Coroutines (micros) | 260701/27968 | 372/ 52 | +| One Coroutine (micros) | 260541/27952 | 212/ 36 | +| Two Coroutines (micros) | 260701/27976 | 372/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 260541/27944 | 212/ 28 | -| Two Coroutines (seconds) | 260717/27968 | 388/ 52 | +| One Coroutine (seconds) | 260541/27952 | 212/ 36 | +| Two Coroutines (seconds) | 260717/27976 | 388/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 260573/27952 | 244/ 36 | -| Scheduler, Two Coroutines | 260717/27976 | 388/ 60 | +| Scheduler, One Coroutine | 260669/27952 | 340/ 36 | +| Scheduler, Two Coroutines | 260813/27984 | 484/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 260589/27952 | 260/ 36 | -| Scheduler, Two Coroutines (micros) | 260733/27976 | 404/ 60 | +| Scheduler, One Coroutine (micros) | 260669/27952 | 340/ 36 | +| Scheduler, Two Coroutines (micros) | 260813/27984 | 484/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 260589/27952 | 260/ 36 | -| Scheduler, Two Coroutines (seconds) | 260749/27976 | 420/ 60 | +| Scheduler, One Coroutine (seconds) | 260701/27952 | 372/ 36 | +| Scheduler, Two Coroutines (seconds) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 260605/27952 | 276/ 36 | -| Scheduler, Two Coroutines (setup) | 260781/27976 | 452/ 60 | +| Scheduler, One Coroutine (setup) | 260701/27952 | 372/ 36 | +| Scheduler, Two Coroutines (setup) | 260877/27984 | 548/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 260589/27952 | 260/ 36 | -| Scheduler, Two Coroutines (man setup) | 260765/27976 | 436/ 60 | +| Scheduler, One Coroutine (man setup) | 260685/27952 | 356/ 36 | +| Scheduler, Two Coroutines (man setup) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | -| Blink Coroutine | 261133/28016 | 804/ 100 | +| Blink Coroutine | 261149/28016 | 820/ 100 | +--------------------------------------------------------------------+ ``` @@ -401,35 +410,35 @@ $ make README.md |---------------------------------------+--------------+-------------| | Baseline | 204573/16060 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 204713/16068 | 140/ 8 | -| Two Delay Functions | 204785/16068 | 212/ 8 | +| One Delay Function | 205129/16092 | 556/ 32 | +| Two Delay Functions | 205201/16092 | 628/ 32 | |---------------------------------------+--------------+-------------| -| One Coroutine | 204821/16092 | 248/ 32 | -| Two Coroutines | 204989/16116 | 416/ 56 | +| One Coroutine | 205241/16124 | 668/ 64 | +| Two Coroutines | 205413/16148 | 840/ 88 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 204809/16092 | 236/ 32 | -| Two Coroutines (micros) | 204977/16116 | 404/ 56 | +| One Coroutine (micros) | 205229/16124 | 656/ 64 | +| Two Coroutines (micros) | 205401/16148 | 828/ 88 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 204837/16092 | 264/ 32 | -| Two Coroutines (seconds) | 205021/16116 | 448/ 56 | +| One Coroutine (seconds) | 205257/16124 | 684/ 64 | +| Two Coroutines (seconds) | 205445/16148 | 872/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 204885/16100 | 312/ 40 | -| Scheduler, Two Coroutines | 205025/16124 | 452/ 64 | +| Scheduler, One Coroutine | 205397/16124 | 824/ 64 | +| Scheduler, Two Coroutines | 205537/16156 | 964/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 204873/16100 | 300/ 40 | -| Scheduler, Two Coroutines (micros) | 205013/16124 | 440/ 64 | +| Scheduler, One Coroutine (micros) | 205373/16124 | 800/ 64 | +| Scheduler, Two Coroutines (micros) | 205513/16156 | 940/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 204901/16100 | 328/ 40 | -| Scheduler, Two Coroutines (seconds) | 205057/16124 | 484/ 64 | +| Scheduler, One Coroutine (seconds) | 205413/16124 | 840/ 64 | +| Scheduler, Two Coroutines (seconds) | 205569/16156 | 996/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 204913/16100 | 340/ 40 | -| Scheduler, Two Coroutines (setup) | 205085/16124 | 512/ 64 | +| Scheduler, One Coroutine (setup) | 205425/16124 | 852/ 64 | +| Scheduler, Two Coroutines (setup) | 205597/16156 | 1024/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 204905/16100 | 332/ 40 | -| Scheduler, Two Coroutines (man setup) | 205085/16124 | 512/ 64 | +| Scheduler, One Coroutine (man setup) | 205417/16124 | 844/ 64 | +| Scheduler, Two Coroutines (man setup) | 205597/16156 | 1024/ 96 | |---------------------------------------+--------------+-------------| -| Blink Function | 205065/16076 | 492/ 16 | -| Blink Coroutine | 205173/16100 | 600/ 40 | +| Blink Function | 205481/16100 | 908/ 40 | +| Blink Coroutine | 205593/16124 | 1020/ 64 | +--------------------------------------------------------------------+ ``` @@ -450,32 +459,32 @@ $ make README.md | One Delay Function | 10264/ 4156 | 32/ 4 | | Two Delay Functions | 10292/ 4156 | 60/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 10384/ 4180 | 152/ 28 | -| Two Coroutines | 10504/ 4204 | 272/ 52 | +| One Coroutine | 10388/ 4184 | 156/ 32 | +| Two Coroutines | 10508/ 4212 | 276/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 10440/ 4180 | 208/ 28 | -| Two Coroutines (micros) | 10548/ 4204 | 316/ 52 | +| One Coroutine (micros) | 10444/ 4184 | 212/ 32 | +| Two Coroutines (micros) | 10552/ 4212 | 320/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 10404/ 4180 | 172/ 28 | -| Two Coroutines (seconds) | 10544/ 4204 | 312/ 52 | +| One Coroutine (seconds) | 10408/ 4184 | 176/ 32 | +| Two Coroutines (seconds) | 10548/ 4212 | 316/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 10448/ 4184 | 216/ 32 | -| Scheduler, Two Coroutines | 10564/ 4208 | 332/ 56 | +| Scheduler, One Coroutine | 10568/ 4188 | 336/ 36 | +| Scheduler, Two Coroutines | 10684/ 4216 | 452/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 10504/ 4184 | 272/ 32 | -| Scheduler, Two Coroutines (micros) | 10608/ 4208 | 376/ 56 | +| Scheduler, One Coroutine (micros) | 10556/ 4188 | 324/ 36 | +| Scheduler, Two Coroutines (micros) | 10660/ 4216 | 428/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 10468/ 4184 | 236/ 32 | -| Scheduler, Two Coroutines (seconds) | 10604/ 4208 | 372/ 56 | +| Scheduler, One Coroutine (seconds) | 10588/ 4188 | 356/ 36 | +| Scheduler, Two Coroutines (seconds) | 10724/ 4216 | 492/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 10480/ 4184 | 248/ 32 | -| Scheduler, Two Coroutines (setup) | 10628/ 4208 | 396/ 56 | +| Scheduler, One Coroutine (setup) | 10600/ 4188 | 368/ 36 | +| Scheduler, Two Coroutines (setup) | 10748/ 4216 | 516/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 10468/ 4184 | 236/ 32 | -| Scheduler, Two Coroutines (man setup) | 10616/ 4208 | 384/ 56 | +| Scheduler, One Coroutine (man setup) | 10588/ 4188 | 356/ 36 | +| Scheduler, Two Coroutines (man setup) | 10736/ 4216 | 504/ 64 | |---------------------------------------+--------------+-------------| | Blink Function | 10688/ 4160 | 456/ 8 | -| Blink Coroutine | 10816/ 4180 | 584/ 28 | +| Blink Coroutine | 10820/ 4184 | 588/ 32 | +--------------------------------------------------------------------+ ``` diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index 7055626..970946b 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -1,21 +1,21 @@ 0 400 8192 11 512 1 450 8192 13 512 2 508 8192 15 512 -3 638 8192 35 512 -4 822 8192 57 512 -5 606 8192 35 512 -6 758 8192 57 512 -7 734 8192 35 512 -8 946 8192 57 512 -9 766 8192 37 512 -10 944 8192 59 512 -11 734 8192 37 512 -12 880 8192 59 512 -13 862 8192 37 512 -14 1068 8192 59 512 -15 818 8192 37 512 -16 1092 8192 59 512 -17 796 8192 37 512 -18 1078 8192 59 512 +3 642 8192 37 512 +4 834 8192 61 512 +5 610 8192 37 512 +6 770 8192 61 512 +7 738 8192 37 512 +8 958 8192 61 512 +9 866 8192 39 512 +10 1052 8192 63 512 +11 834 8192 39 512 +12 988 8192 63 512 +13 962 8192 39 512 +14 1176 8192 63 512 +15 920 8192 39 512 +16 1202 8192 63 512 +17 896 8192 39 512 +18 1186 8192 63 512 19 546 8192 14 512 -20 762 8192 35 512 +20 766 8192 37 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 49e7d7e..9efefbc 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -1,21 +1,21 @@ 0 204573 1310720 16060 327680 -1 204713 1310720 16068 327680 -2 204785 1310720 16068 327680 -3 204821 1310720 16092 327680 -4 204989 1310720 16116 327680 -5 204809 1310720 16092 327680 -6 204977 1310720 16116 327680 -7 204837 1310720 16092 327680 -8 205021 1310720 16116 327680 -9 204885 1310720 16100 327680 -10 205025 1310720 16124 327680 -11 204873 1310720 16100 327680 -12 205013 1310720 16124 327680 -13 204901 1310720 16100 327680 -14 205057 1310720 16124 327680 -15 204913 1310720 16100 327680 -16 205085 1310720 16124 327680 -17 204905 1310720 16100 327680 -18 205085 1310720 16124 327680 -19 205065 1310720 16076 327680 -20 205173 1310720 16100 327680 +1 205129 1310720 16092 327680 +2 205201 1310720 16092 327680 +3 205241 1310720 16124 327680 +4 205413 1310720 16148 327680 +5 205229 1310720 16124 327680 +6 205401 1310720 16148 327680 +7 205257 1310720 16124 327680 +8 205445 1310720 16148 327680 +9 205397 1310720 16124 327680 +10 205537 1310720 16156 327680 +11 205373 1310720 16124 327680 +12 205513 1310720 16156 327680 +13 205413 1310720 16124 327680 +14 205569 1310720 16156 327680 +15 205425 1310720 16124 327680 +16 205597 1310720 16156 327680 +17 205417 1310720 16124 327680 +18 205597 1310720 16156 327680 +19 205481 1310720 16100 327680 +20 205593 1310720 16124 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 7d62d3b..5add629 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -1,21 +1,21 @@ 0 260329 1044464 27916 81920 1 260377 1044464 27916 81920 2 260441 1044464 27916 81920 -3 260525 1044464 27944 81920 -4 260669 1044464 27968 81920 -5 260541 1044464 27944 81920 -6 260701 1044464 27968 81920 -7 260541 1044464 27944 81920 -8 260717 1044464 27968 81920 -9 260573 1044464 27952 81920 -10 260717 1044464 27976 81920 -11 260589 1044464 27952 81920 -12 260733 1044464 27976 81920 -13 260589 1044464 27952 81920 -14 260749 1044464 27976 81920 -15 260605 1044464 27952 81920 -16 260781 1044464 27976 81920 -17 260589 1044464 27952 81920 -18 260765 1044464 27976 81920 +3 260525 1044464 27952 81920 +4 260685 1044464 27976 81920 +5 260541 1044464 27952 81920 +6 260701 1044464 27976 81920 +7 260541 1044464 27952 81920 +8 260717 1044464 27976 81920 +9 260669 1044464 27952 81920 +10 260813 1044464 27984 81920 +11 260669 1044464 27952 81920 +12 260813 1044464 27984 81920 +13 260701 1044464 27952 81920 +14 260861 1044464 27984 81920 +15 260701 1044464 27952 81920 +16 260877 1044464 27984 81920 +17 260685 1044464 27952 81920 +18 260861 1044464 27984 81920 19 261001 1044464 27988 81920 -20 261133 1044464 28016 81920 +20 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index 27da327..755251c 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -132,6 +132,15 @@ used. * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per coroutine. + * Add a `CoroutineLogBinProfiler` to 2 coroutines. + * Use a 3rd coroutine to print the frequency count to the `Serial` + output every 10 seconds. + * Provide `CoroutineLogBinProfiler::printBinsTo()` which prints + a table of the frequency count over all coroutines. This represents a + poor-man's version of the log-log graph of the frequency count. + * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes + for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is + not used. This is a one-time hit. ## How to Generate diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index 71da112..e99f5b5 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -1,21 +1,21 @@ 0 3554 28672 151 2560 1 3602 28672 153 2560 2 3662 28672 155 2560 -3 3738 28672 175 2560 -4 3924 28672 197 2560 -5 3710 28672 175 2560 -6 3868 28672 197 2560 -7 3838 28672 175 2560 -8 4056 28672 197 2560 -9 3862 28672 177 2560 -10 4040 28672 199 2560 -11 3834 28672 177 2560 -12 3984 28672 199 2560 -13 3962 28672 177 2560 -14 4172 28672 199 2560 -15 3912 28672 177 2560 -16 4190 28672 199 2560 -17 3890 28672 177 2560 -18 4176 28672 199 2560 +3 3742 28672 177 2560 +4 3936 28672 201 2560 +5 3714 28672 177 2560 +6 3880 28672 201 2560 +7 3842 28672 177 2560 +8 4068 28672 201 2560 +9 3966 28672 179 2560 +10 4152 28672 203 2560 +11 3938 28672 179 2560 +12 4096 28672 203 2560 +13 4066 28672 179 2560 +14 4284 28672 203 2560 +15 4016 28672 179 2560 +16 4302 28672 203 2560 +17 3994 28672 179 2560 +18 4288 28672 203 2560 19 3994 28672 154 2560 -20 4160 28672 175 2560 +20 4164 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index f639e58..209e4a1 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -1,21 +1,21 @@ 0 606 30720 11 2048 1 654 30720 13 2048 2 714 30720 15 2048 -3 850 30720 35 2048 -4 1036 30720 57 2048 -5 822 30720 35 2048 -6 980 30720 57 2048 -7 950 30720 35 2048 -8 1168 30720 57 2048 -9 974 30720 37 2048 -10 1152 30720 59 2048 -11 946 30720 37 2048 -12 1096 30720 59 2048 -13 1074 30720 37 2048 -14 1284 30720 59 2048 -15 1024 30720 37 2048 -16 1302 30720 59 2048 -17 1002 30720 37 2048 -18 1288 30720 59 2048 +3 854 30720 37 2048 +4 1048 30720 61 2048 +5 826 30720 37 2048 +6 992 30720 61 2048 +7 954 30720 37 2048 +8 1180 30720 61 2048 +9 1078 30720 39 2048 +10 1264 30720 63 2048 +11 1050 30720 39 2048 +12 1208 30720 63 2048 +13 1178 30720 39 2048 +14 1396 30720 63 2048 +15 1128 30720 39 2048 +16 1414 30720 63 2048 +17 1106 30720 39 2048 +18 1400 30720 63 2048 19 938 30720 14 2048 -20 1164 30720 35 2048 +20 1168 30720 37 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index ad12082..2fdf69c 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -1,21 +1,21 @@ 0 21884 131072 3540 20480 1 21912 131072 3544 20480 2 21960 131072 3544 20480 -3 22016 131072 3568 20480 -4 22164 131072 3592 20480 -5 22080 131072 3568 20480 -6 22228 131072 3592 20480 -7 22032 131072 3568 20480 -8 22196 131072 3592 20480 -9 22088 131072 3572 20480 -10 22192 131072 3596 20480 -11 22152 131072 3572 20480 -12 22256 131072 3596 20480 -13 22104 131072 3572 20480 -14 22224 131072 3596 20480 -15 22112 131072 3572 20480 -16 22244 131072 3596 20480 -17 22104 131072 3572 20480 -18 22240 131072 3596 20480 +3 22016 131072 3572 20480 +4 22164 131072 3600 20480 +5 22080 131072 3572 20480 +6 22228 131072 3600 20480 +7 22032 131072 3572 20480 +8 22196 131072 3600 20480 +9 22208 131072 3576 20480 +10 22312 131072 3604 20480 +11 22208 131072 3576 20480 +12 22312 131072 3604 20480 +13 22224 131072 3576 20480 +14 22344 131072 3604 20480 +15 22232 131072 3576 20480 +16 22364 131072 3604 20480 +17 22224 131072 3576 20480 +18 22360 131072 3604 20480 19 22120 131072 3540 20480 -20 22232 131072 3564 20480 +20 22232 131072 3568 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 26bad97..8b02774 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -1,21 +1,21 @@ 0 10232 262144 4152 65536 1 10264 262144 4156 65536 2 10292 262144 4156 65536 -3 10384 262144 4180 65536 -4 10504 262144 4204 65536 -5 10440 262144 4180 65536 -6 10548 262144 4204 65536 -7 10404 262144 4180 65536 -8 10544 262144 4204 65536 -9 10448 262144 4184 65536 -10 10564 262144 4208 65536 -11 10504 262144 4184 65536 -12 10608 262144 4208 65536 -13 10468 262144 4184 65536 -14 10604 262144 4208 65536 -15 10480 262144 4184 65536 -16 10628 262144 4208 65536 -17 10468 262144 4184 65536 -18 10616 262144 4208 65536 +3 10388 262144 4184 65536 +4 10508 262144 4212 65536 +5 10444 262144 4184 65536 +6 10552 262144 4212 65536 +7 10408 262144 4184 65536 +8 10548 262144 4212 65536 +9 10568 262144 4188 65536 +10 10684 262144 4216 65536 +11 10556 262144 4188 65536 +12 10660 262144 4216 65536 +13 10588 262144 4188 65536 +14 10724 262144 4216 65536 +15 10600 262144 4188 65536 +16 10748 262144 4216 65536 +17 10588 262144 4188 65536 +18 10736 262144 4216 65536 19 10688 262144 4160 65536 -20 10816 262144 4180 65536 +20 10820 262144 4184 65536 From 8dba23b0732d1ed2e136c599b669efee0518b4d3 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 15:10:47 -0700 Subject: [PATCH 11/59] AutoBenchmark: Regenerate after adding CoroutineProfiler; runCoroutine() is slower < 0.7 microseconds --- examples/AutoBenchmark/README.md | 45 ++++++++++++++--------- examples/AutoBenchmark/esp32.txt | 6 +-- examples/AutoBenchmark/esp8266.txt | 6 +-- examples/AutoBenchmark/generate_readme.py | 11 +++++- examples/AutoBenchmark/micro.txt | 6 +-- examples/AutoBenchmark/nano.txt | 4 +- examples/AutoBenchmark/stm32.txt | 4 +- examples/AutoBenchmark/teensy32.txt | 4 +- 8 files changed, 52 insertions(+), 34 deletions(-) diff --git a/examples/AutoBenchmark/README.md b/examples/AutoBenchmark/README.md index 7cdeb5c..1dda3d9 100644 --- a/examples/AutoBenchmark/README.md +++ b/examples/AutoBenchmark/README.md @@ -14,7 +14,7 @@ is the overhead caused by the `Coroutine` context switch. All times in below are in microseconds. -**Version**: AceRoutine v1.4.2 +**Version**: AceRoutine v1.5.0 **DO NOT EDIT**: This file was auto-generated using `make README.md`. @@ -121,6 +121,15 @@ $ make README.md * ESP32 Core from 1.0.6 to 2.0.2 * Teensyduino from 1.54 to 1.56 +* v1.5.0 + * Add `CoroutineProfiler` to `CoroutineScheduler`. + * `CoroutineScheduler::runCoroutine()` becomes slightly slower: + * 0.7 microseconds (AVR) + * 0.5 microseconds (STM32) + * 0.2 microseconds (ESP8266) + * 0.07 microseconds (ESP32) + * 0.15 microseconds (Teensy 3.2) + ## Arduino Nano * 16MHz ATmega328P @@ -130,7 +139,7 @@ $ make README.md ``` Sizes of Objects: -sizeof(Coroutine): 11 +sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 @@ -140,7 +149,7 @@ CPU: |---------------------+--------+-------------+--------| | EmptyLoop | 10000 | 1.700 | 0.000 | | DirectScheduling | 10000 | 2.900 | 1.200 | -| CoroutineScheduling | 10000 | 7.200 | 5.500 | +| CoroutineScheduling | 10000 | 7.900 | 6.200 | +---------------------+--------+-------------+--------+ ``` @@ -154,7 +163,7 @@ CPU: ``` Sizes of Objects: -sizeof(Coroutine): 11 +sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 @@ -162,9 +171,9 @@ CPU: +---------------------+--------+-------------+--------+ | Functionality | iters | micros/iter | diff | |---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 1.800 | 0.000 | -| DirectScheduling | 10000 | 2.900 | 1.100 | -| CoroutineScheduling | 10000 | 7.300 | 5.500 | +| EmptyLoop | 10000 | 1.700 | 0.000 | +| DirectScheduling | 10000 | 2.900 | 1.200 | +| CoroutineScheduling | 10000 | 7.900 | 6.200 | +---------------------+--------+-------------+--------+ ``` @@ -177,7 +186,7 @@ CPU: ``` Sizes of Objects: -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 @@ -187,7 +196,7 @@ CPU: |---------------------+--------+-------------+--------| | EmptyLoop | 30000 | 0.133 | 0.000 | | DirectScheduling | 30000 | 0.533 | 0.400 | -| CoroutineScheduling | 30000 | 1.133 | 1.000 | +| CoroutineScheduling | 30000 | 1.600 | 1.467 | +---------------------+--------+-------------+--------+ ``` @@ -200,7 +209,7 @@ CPU: ``` Sizes of Objects: -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 @@ -208,9 +217,9 @@ CPU: +---------------------+--------+-------------+--------+ | Functionality | iters | micros/iter | diff | |---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 0.100 | 0.000 | -| DirectScheduling | 10000 | 0.500 | 0.400 | -| CoroutineScheduling | 10000 | 0.900 | 0.800 | +| EmptyLoop | 10000 | 0.200 | 0.000 | +| DirectScheduling | 10000 | 0.500 | 0.300 | +| CoroutineScheduling | 10000 | 1.200 | 1.000 | +---------------------+--------+-------------+--------+ ``` @@ -223,7 +232,7 @@ CPU: ``` Sizes of Objects: -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 @@ -232,8 +241,8 @@ CPU: | Functionality | iters | micros/iter | diff | |---------------------+--------+-------------+--------| | EmptyLoop | 30000 | 0.066 | 0.000 | -| DirectScheduling | 30000 | 0.133 | 0.067 | -| CoroutineScheduling | 30000 | 0.333 | 0.267 | +| DirectScheduling | 30000 | 0.100 | 0.034 | +| CoroutineScheduling | 30000 | 0.400 | 0.334 | +---------------------+--------+-------------+--------+ ``` @@ -247,7 +256,7 @@ CPU: ``` Sizes of Objects: -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 @@ -257,7 +266,7 @@ CPU: |---------------------+--------+-------------+--------| | EmptyLoop | 30000 | 0.066 | 0.000 | | DirectScheduling | 30000 | 0.233 | 0.167 | -| CoroutineScheduling | 30000 | 0.533 | 0.467 | +| CoroutineScheduling | 30000 | 0.666 | 0.600 | +---------------------+--------+-------------+--------+ ``` diff --git a/examples/AutoBenchmark/esp32.txt b/examples/AutoBenchmark/esp32.txt index 54bbc70..489da42 100644 --- a/examples/AutoBenchmark/esp32.txt +++ b/examples/AutoBenchmark/esp32.txt @@ -1,9 +1,9 @@ SIZEOF -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 BENCHMARKS EmptyLoop 0.066 30000 -DirectScheduling 0.133 30000 -CoroutineScheduling 0.333 30000 +DirectScheduling 0.100 30000 +CoroutineScheduling 0.400 30000 END diff --git a/examples/AutoBenchmark/esp8266.txt b/examples/AutoBenchmark/esp8266.txt index ec53d60..f6ee050 100644 --- a/examples/AutoBenchmark/esp8266.txt +++ b/examples/AutoBenchmark/esp8266.txt @@ -1,9 +1,9 @@ SIZEOF -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 BENCHMARKS -EmptyLoop 0.100 10000 +EmptyLoop 0.200 10000 DirectScheduling 0.500 10000 -CoroutineScheduling 0.900 10000 +CoroutineScheduling 1.200 10000 END diff --git a/examples/AutoBenchmark/generate_readme.py b/examples/AutoBenchmark/generate_readme.py index dcf3b49..15e394c 100755 --- a/examples/AutoBenchmark/generate_readme.py +++ b/examples/AutoBenchmark/generate_readme.py @@ -38,7 +38,7 @@ All times in below are in microseconds. -**Version**: AceRoutine v1.4.2 +**Version**: AceRoutine v1.5.0 **DO NOT EDIT**: This file was auto-generated using `make README.md`. @@ -145,6 +145,15 @@ * ESP32 Core from 1.0.6 to 2.0.2 * Teensyduino from 1.54 to 1.56 +* v1.5.0 + * Add `CoroutineProfiler` to `CoroutineScheduler`. + * `CoroutineScheduler::runCoroutine()` becomes slightly slower: + * 0.7 microseconds (AVR) + * 0.5 microseconds (STM32) + * 0.2 microseconds (ESP8266) + * 0.07 microseconds (ESP32) + * 0.15 microseconds (Teensy 3.2) + ## Arduino Nano * 16MHz ATmega328P diff --git a/examples/AutoBenchmark/micro.txt b/examples/AutoBenchmark/micro.txt index d422fc0..12320ef 100644 --- a/examples/AutoBenchmark/micro.txt +++ b/examples/AutoBenchmark/micro.txt @@ -1,9 +1,9 @@ SIZEOF -sizeof(Coroutine): 11 +sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 BENCHMARKS -EmptyLoop 1.800 10000 +EmptyLoop 1.700 10000 DirectScheduling 2.900 10000 -CoroutineScheduling 7.300 10000 +CoroutineScheduling 7.900 10000 END diff --git a/examples/AutoBenchmark/nano.txt b/examples/AutoBenchmark/nano.txt index 6c7eaa4..12320ef 100644 --- a/examples/AutoBenchmark/nano.txt +++ b/examples/AutoBenchmark/nano.txt @@ -1,9 +1,9 @@ SIZEOF -sizeof(Coroutine): 11 +sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 BENCHMARKS EmptyLoop 1.700 10000 DirectScheduling 2.900 10000 -CoroutineScheduling 7.200 10000 +CoroutineScheduling 7.900 10000 END diff --git a/examples/AutoBenchmark/stm32.txt b/examples/AutoBenchmark/stm32.txt index cf9fc95..d3caab3 100644 --- a/examples/AutoBenchmark/stm32.txt +++ b/examples/AutoBenchmark/stm32.txt @@ -1,9 +1,9 @@ SIZEOF -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 BENCHMARKS EmptyLoop 0.133 30000 DirectScheduling 0.533 30000 -CoroutineScheduling 1.133 30000 +CoroutineScheduling 1.600 30000 END diff --git a/examples/AutoBenchmark/teensy32.txt b/examples/AutoBenchmark/teensy32.txt index e8b7ca2..358df17 100644 --- a/examples/AutoBenchmark/teensy32.txt +++ b/examples/AutoBenchmark/teensy32.txt @@ -1,9 +1,9 @@ SIZEOF -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 BENCHMARKS EmptyLoop 0.066 30000 DirectScheduling 0.233 30000 -CoroutineScheduling 0.533 30000 +CoroutineScheduling 0.666 30000 END From a233bbc1987c634f1c500b2b360317f5ab8207ed Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 16:18:14 -0700 Subject: [PATCH 12/59] CoroutineLogBinProfiler.h: Change to template class parameterized on T_COROUTINE --- src/ace_routine/Coroutine.h | 23 ++- src/ace_routine/CoroutineLogBinProfiler.cpp | 161 ------------------- src/ace_routine/CoroutineLogBinProfiler.h | 169 ++++++++++++++++++-- 3 files changed, 172 insertions(+), 181 deletions(-) delete mode 100644 src/ace_routine/CoroutineLogBinProfiler.cpp diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index a1633d7..93d35b2 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -27,6 +27,7 @@ SOFTWARE. #include // UINT16_MAX #include // Print +#include // PrintStr<> #include "ClockInterface.h" class __FlashStringHelper; @@ -347,16 +348,28 @@ class CoroutineTemplate { /** * Print name to the given Printer. If the name is null, then print the * hexadecimal representation of the pointer to the coroutine. + * + * @param printer destination of output, usually `Serial` + * @param maxLen truncate to maxLen if given */ - void printNameTo(Print& printer) const { + void printNameTo(Print& printer, uint8_t maxLen = 0) const { + // Need to go through this contortion because vsnprintf() does not support + // flash string parameters, so I can't use something like "%12.12s" with + // a flash string. + ace_common::PrintStr<128> pname; + if (mName == nullptr) { - printer.print("0x"); - printer.print((uintptr_t) this, 16); + pname.print("0x"); + pname.print((uintptr_t) this, 16); } else if (mNameType == kNameTypeCString) { - printer.print(mName); + pname.print(mName); } else { - printer.print((const __FlashStringHelper*) mName); + pname.print((const __FlashStringHelper*) mName); } + + // Print up to maxLen characters. + maxLen = (maxLen == 0) ? pname.length() : maxLen; + printer.write(pname.cstr(), maxLen); } /** diff --git a/src/ace_routine/CoroutineLogBinProfiler.cpp b/src/ace_routine/CoroutineLogBinProfiler.cpp deleted file mode 100644 index b3ade41..0000000 --- a/src/ace_routine/CoroutineLogBinProfiler.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* -MIT License - -Copyright (c) 2022 Brian T. Park - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include -#include // memset() -#include // printfTo() -#include "Coroutine.h" -#include "CoroutineLogBinProfiler.h" - -using ace_common::printfTo; - -namespace ace_routine { - -CoroutineLogBinProfiler::CoroutineLogBinProfiler() { - init(); -} - -void CoroutineLogBinProfiler::init() { - memset(mBins, 0, sizeof(mBins)); -} - -void CoroutineLogBinProfiler::updateElapsedMicros(uint32_t micros) { - uint8_t index = 0; // [0, 31] - - // The index is the bit number (0-31) of the most significant bit. So each bin - // contains the number of samples whose elapsed micros is between 2^i and - // 2^(i+1). Example, for Bin 3, and this bin contains the number of samples - // which satsify (8us <= elapsed < 16us). The exception is Bin 0 because it - // includes samples where elapsed = 0 as well, so the sample interval for Bin - // 0 is (0 <= elapsed < 2), instead of (1 <= elapsed < 2). - while (true) { - micros >>= 1; - if (micros == 0) break; - index++; - } - uint16_t count = mBins[index]; - if (count < UINT16_MAX) { - mBins[index]++; - } -} - -// Labels for each bin in mBins. -static const char* kBinLabels[CoroutineLogBinProfiler::kNumBins] = { - "<2us", - "<4us", - "<8us", - "<16us", - "<32us", - "<64us", - "<128us", - "<256us", - "<512us", - "<1ms", - "<2ms", - "<4ms", - "<8ms", - "<16ms", - "<32ms", - "<64ms", - "<128ms", - "<256ms", - "<512ms", - "<1s", - "<2s", - "<4s", - "<8s", - "<16s", - "<32s", - "<64s", - "<128s", - "<256s", - "<512s", - "<1024s", - "<2048s", - "<4096s", -}; - -void CoroutineLogBinProfiler::printHeaderTo( - Print& printer, uint8_t binStart, uint8_t binEnd) const { - if (binEnd <= binStart) return; - - binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; - for (uint8_t i = binStart; i < binEnd; i++) { - ace_common::printfTo(printer, "%6s", kBinLabels[i]); - } -} - -void CoroutineLogBinProfiler::printTo( - Print& printer, uint8_t binStart, uint8_t binEnd) const { - if (binEnd <= binStart) return; - - binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; - for (uint8_t i = binStart; i < binEnd; i++) { - uint16_t count = mBins[i]; - ace_common::printfTo(printer, "%6d", count); - } - - uint32_t remaining = 0; - for (uint8_t i = binEnd; i < kNumBins; i++) { - remaining += mBins[i]; - } - if (remaining > 0) { - ace_common::printfTo(printer, "%6ld", (unsigned long) remaining); - } -} - -void CoroutineLogBinProfiler::printBinsTo( - Print& printer, Coroutine** root, uint8_t binStart, uint8_t binEnd) { - if (binEnd <= binStart) return; - - bool isHeaderPrinted = false; - for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { - CoroutineLogBinProfiler* profiler = - (CoroutineLogBinProfiler*) (*p)->getProfiler(); - if (! profiler) continue; - - // Print header if needed. - if (! isHeaderPrinted) { - printfTo(printer, "%12.12s", ""); - profiler->printHeaderTo(printer, binStart, binEnd); - printer.println(); - isHeaderPrinted = true; - } - - // Print the bins. The number of digits is automatically a log10() of the - // counts, so we should be able to visually scan the table and see which - // coroutine is taking too long. - printfTo(printer, "%12.12s", (*p)->getCName()); - profiler->printTo(printer, binStart, binEnd); - printer.println(); - - // TODO: It'd be useful to sum up the remaining buckets after binEnd, and - // print the number of samples that weren't printed in the loop above. - - // Maybe control this using a boolean flag. - profiler->init(); - } -} - -} diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h index 068d843..7e1a51c 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -26,10 +26,12 @@ SOFTWARE. #define ACE_ROUTINE_COROUTINE_LOG_BIN_PROFILER_H #include // uint8_t, uint32_t +#include // memset() +#include // Print +#include // printfTo() #include "Coroutine.h" #include "CoroutineProfiler.h" -class Print; namespace ace_routine { @@ -48,30 +50,56 @@ namespace ace_routine { * replaced by a '*' character.) Therefore the table is a rough ASCII version of * a log-log graph of the frequency count. * - * For example, here is the output of `printBinsTo()` for the sample program in - * `examples/SoundManager`: + * For example, here is the output of `printBinsTo(Serial, 0, 9)` for the sample + * program in `examples/SoundManager`: * * @verbatim - * <2us <4us <8us <16us <32us <64us<128us<256us<512us <1ms <2ms - * soundManag 621 2091 0 0 5 3 0 0 0 0 1 - * soundRouti 2162 553 1 0 1 2 2 1 0 0 0 + * <2us <4us <8us <16us <32us <64us<128us<256us<512us + * soundManager 621 2091 0 0 5 3 0 0 0 1 + * soundRoutine 2162 553 1 0 1 2 2 1 0 * * The `init()` method resets the frequency count of the bins. * * @endverbatim */ -class CoroutineLogBinProfiler : public CoroutineProfiler { +template +class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { public: static const uint8_t kNumBins = 32; public: /** Constructor. */ - CoroutineLogBinProfiler(); + CoroutineLogBinProfilerTemplate() { + init(); + } /** Clear the bins. */ - void init(); + void init() { + memset(mBins, 0, sizeof(mBins)); + } - void updateElapsedMicros(uint32_t micros) override; + /** + * Update the count for the calculated elapsed time bin. The bin index is + * the bit number (0-31) of the most significant bit. So each bin contains + * the number of samples whose elapsed micros is between 2^i and 2^(i+1). + * Example, for Bin 3, and this bin contains the number of samples which + * satsify (8us <= elapsed < 16us). The exception is Bin 0 because it + * includes samples where elapsed = 0 as well, so the sample interval for + * Bin 0 is (0 <= elapsed < 2), instead of (1 <= elapsed < 2). + */ + void updateElapsedMicros(uint32_t micros) override { + uint8_t index = 0; // [0, 31] + + while (true) { + micros >>= 1; + if (micros == 0) break; + index++; + } + uint16_t count = mBins[index]; + if (count < UINT16_MAX) { + mBins[index]++; + } + } /** * Print the header related to this profiler. @@ -79,29 +107,140 @@ class CoroutineLogBinProfiler : public CoroutineProfiler { * @param binStart start index of the bins (0-31) * @param binEnd end index (exclusive) of the bins (0-32) */ - void printHeaderTo(Print& printer, uint8_t binStart, uint8_t binEnd) const; + void printHeaderTo(Print& printer, uint8_t binStart, uint8_t binEnd) const { + if (binEnd <= binStart) return; + + binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; + for (uint8_t i = binStart; i < binEnd; i++) { + ace_common::printfTo(printer, "%6.6s", kBinLabels[i]); + } + } /** - * Print the bins of this profiler. + * Print the bins of this profiler as a single line of text with each bin + * printed as a 5-digit number in a 6-character box. If there are any + * remaining counts after the `binEnd`, the cummulative sum of the remaining + * bins are printed in another 6-character box. * * @param binStart start index of the bins (0-31) * @param binEnd end index (exclusive) of the bins (0-32) */ - void printTo(Print& printer, uint8_t binStart, uint8_t binEnd) const; + void printTo(Print& printer, uint8_t binStart, uint8_t binEnd) const { + if (binEnd <= binStart) return; + + binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; + for (uint8_t i = binStart; i < binEnd; i++) { + uint16_t count = mBins[i]; + ace_common::printfTo(printer, "%6u", count); + } + + uint32_t remaining = 0; + for (uint8_t i = binEnd; i < kNumBins; i++) { + remaining += mBins[i]; + } + if (remaining > 0) { + ace_common::printfTo(printer, "%6lu", (unsigned long) remaining); + } + } /** - * Loop over all coroutines and print the ASCII version of a histogram. + * Loop over all coroutines and print the ASCII version of a histogram. This + * assumes that all the coroutines are using the same CoroutineProfiler + * class, so we can use any of the profilers to print the header, and the + * numbers will be lined up properly. * + * @param printer destination of output, usually `Serial` + * @param root pointer to the singly-linked list of Coroutines * @param binStart start index of the bins (0-31) * @param binEnd end inex (exclusive) of the bins (0-32) + * @param clear call init() after printing (default true) */ static void printBinsTo( - Print& printer, Coroutine** root, uint8_t binStart, uint8_t binEnd); + Print& printer, + T_COROUTINE** root, + uint8_t binStart, + uint8_t binEnd, + bool clear = true + ) { + if (binEnd <= binStart) return; + + bool isHeaderPrinted = false; + for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + CoroutineLogBinProfilerTemplate* profiler = + (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + if (! profiler) continue; + + // Print header if needed. + if (! isHeaderPrinted) { + ace_common::printfTo(printer, "%12.12s", ""); + profiler->printHeaderTo(printer, binStart, binEnd); + printer.println(); + isHeaderPrinted = true; + } + + // Print the coroutine name, truncated to 12 characters. The next column + // is a 5-digit number formatted into a 6-character block, so there will + // always be a space between the coroutine name and the next number. + (*p)->printNameTo(printer, 12); + + // Print the bins. The number of digits is automatically a log10() of + // the counts, so we should be able to visually scan the table and see + // which coroutine is taking too long. + profiler->printTo(printer, binStart, binEnd); + printer.println(); + + if (clear) { + profiler->init(); + } + } + } public: + static const char* const kBinLabels[kNumBins]; + uint16_t mBins[kNumBins]; }; +// Labels for each bin in mBins. +template +const char* const CoroutineLogBinProfilerTemplate::kBinLabels[ + CoroutineLogBinProfilerTemplate::kNumBins] = { + "<2us", + "<4us", + "<8us", + "<16us", + "<32us", + "<64us", + "<128us", + "<256us", + "<512us", + "<1ms", + "<2ms", + "<4ms", + "<8ms", + "<16ms", + "<32ms", + "<64ms", + "<128ms", + "<256ms", + "<512ms", + "<1s", + "<2s", + "<4s", + "<8s", + "<16s", + "<32s", + "<64s", + "<128s", + "<256s", + "<512s", + "<1024s", + "<2048s", + "<4096s", +}; + +using CoroutineLogBinProfiler = CoroutineLogBinProfilerTemplate; + } #endif From 01930c5f2363d64b1e95ffbddd300f34063fba59 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 16:23:26 -0700 Subject: [PATCH 13/59] SoundManager.ino: Print fewer bins to fit output into 80 columns --- examples/SoundManager/SoundManager.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index e11d296..4513e70 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -59,8 +59,8 @@ EXTERN_COROUTINE(soundManager); COROUTINE(printProfile) { COROUTINE_LOOP() { - CoroutineLogBinProfiler::printBinsTo(Serial, getRoot(), 0, 16); - COROUTINE_DELAY_SECONDS(10); + CoroutineLogBinProfiler::printBinsTo(Serial, getRoot(), 0, 8); + COROUTINE_DELAY_SECONDS(5); } } From ce2539b9f4f96918e7fb3660ff75aeec36c7ada4 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 18:23:16 -0700 Subject: [PATCH 14/59] src/CoroutineLogBinRenderer.h: Extract rendering logic from CoroutineLogBinProfiler --- examples/SoundManager/SoundManager.ino | 5 +- src/AceRoutine.h | 1 + src/ace_routine/CoroutineLogBinProfiler.h | 147 --------------- src/ace_routine/CoroutineLogBinRenderer.h | 207 ++++++++++++++++++++++ 4 files changed, 211 insertions(+), 149 deletions(-) create mode 100644 src/ace_routine/CoroutineLogBinRenderer.h diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index 4513e70..da5c344 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -52,14 +52,15 @@ using ace_routine::Coroutine;; using ace_routine::CoroutineScheduler; using ace_routine::CoroutineLogBinProfiler; -using ace_common::printfTo; +using ace_routine::CoroutineLogBinRenderer; SoundRoutine soundRoutine; EXTERN_COROUTINE(soundManager); COROUTINE(printProfile) { COROUTINE_LOOP() { - CoroutineLogBinProfiler::printBinsTo(Serial, getRoot(), 0, 8); + CoroutineLogBinRenderer renderer(getRoot()); + renderer.printTableTo(Serial, 0, 8); COROUTINE_DELAY_SECONDS(5); } } diff --git a/src/AceRoutine.h b/src/AceRoutine.h index 2318da0..2ca390d 100644 --- a/src/AceRoutine.h +++ b/src/AceRoutine.h @@ -50,6 +50,7 @@ SOFTWARE. #include "ace_routine/CoroutineScheduler.h" #include "ace_routine/CoroutineProfiler.h" #include "ace_routine/CoroutineLogBinProfiler.h" +#include "ace_routine/CoroutineLogBinRenderer.h" #include "ace_routine/Channel.h" #endif diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h index 7e1a51c..dc61994 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -27,8 +27,6 @@ SOFTWARE. #include // uint8_t, uint32_t #include // memset() -#include // Print -#include // printfTo() #include "Coroutine.h" #include "CoroutineProfiler.h" @@ -50,17 +48,6 @@ namespace ace_routine { * replaced by a '*' character.) Therefore the table is a rough ASCII version of * a log-log graph of the frequency count. * - * For example, here is the output of `printBinsTo(Serial, 0, 9)` for the sample - * program in `examples/SoundManager`: - * - * @verbatim - * <2us <4us <8us <16us <32us <64us<128us<256us<512us - * soundManager 621 2091 0 0 5 3 0 0 0 1 - * soundRoutine 2162 553 1 0 1 2 2 1 0 - * - * The `init()` method resets the frequency count of the bins. - * - * @endverbatim */ template class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { @@ -101,144 +88,10 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { } } - /** - * Print the header related to this profiler. - * - * @param binStart start index of the bins (0-31) - * @param binEnd end index (exclusive) of the bins (0-32) - */ - void printHeaderTo(Print& printer, uint8_t binStart, uint8_t binEnd) const { - if (binEnd <= binStart) return; - - binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; - for (uint8_t i = binStart; i < binEnd; i++) { - ace_common::printfTo(printer, "%6.6s", kBinLabels[i]); - } - } - - /** - * Print the bins of this profiler as a single line of text with each bin - * printed as a 5-digit number in a 6-character box. If there are any - * remaining counts after the `binEnd`, the cummulative sum of the remaining - * bins are printed in another 6-character box. - * - * @param binStart start index of the bins (0-31) - * @param binEnd end index (exclusive) of the bins (0-32) - */ - void printTo(Print& printer, uint8_t binStart, uint8_t binEnd) const { - if (binEnd <= binStart) return; - - binEnd = (binEnd > kNumBins) ? kNumBins : binEnd; - for (uint8_t i = binStart; i < binEnd; i++) { - uint16_t count = mBins[i]; - ace_common::printfTo(printer, "%6u", count); - } - - uint32_t remaining = 0; - for (uint8_t i = binEnd; i < kNumBins; i++) { - remaining += mBins[i]; - } - if (remaining > 0) { - ace_common::printfTo(printer, "%6lu", (unsigned long) remaining); - } - } - - /** - * Loop over all coroutines and print the ASCII version of a histogram. This - * assumes that all the coroutines are using the same CoroutineProfiler - * class, so we can use any of the profilers to print the header, and the - * numbers will be lined up properly. - * - * @param printer destination of output, usually `Serial` - * @param root pointer to the singly-linked list of Coroutines - * @param binStart start index of the bins (0-31) - * @param binEnd end inex (exclusive) of the bins (0-32) - * @param clear call init() after printing (default true) - */ - static void printBinsTo( - Print& printer, - T_COROUTINE** root, - uint8_t binStart, - uint8_t binEnd, - bool clear = true - ) { - if (binEnd <= binStart) return; - - bool isHeaderPrinted = false; - for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { - CoroutineLogBinProfilerTemplate* profiler = - (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); - if (! profiler) continue; - - // Print header if needed. - if (! isHeaderPrinted) { - ace_common::printfTo(printer, "%12.12s", ""); - profiler->printHeaderTo(printer, binStart, binEnd); - printer.println(); - isHeaderPrinted = true; - } - - // Print the coroutine name, truncated to 12 characters. The next column - // is a 5-digit number formatted into a 6-character block, so there will - // always be a space between the coroutine name and the next number. - (*p)->printNameTo(printer, 12); - - // Print the bins. The number of digits is automatically a log10() of - // the counts, so we should be able to visually scan the table and see - // which coroutine is taking too long. - profiler->printTo(printer, binStart, binEnd); - printer.println(); - - if (clear) { - profiler->init(); - } - } - } - public: - static const char* const kBinLabels[kNumBins]; - uint16_t mBins[kNumBins]; }; -// Labels for each bin in mBins. -template -const char* const CoroutineLogBinProfilerTemplate::kBinLabels[ - CoroutineLogBinProfilerTemplate::kNumBins] = { - "<2us", - "<4us", - "<8us", - "<16us", - "<32us", - "<64us", - "<128us", - "<256us", - "<512us", - "<1ms", - "<2ms", - "<4ms", - "<8ms", - "<16ms", - "<32ms", - "<64ms", - "<128ms", - "<256ms", - "<512ms", - "<1s", - "<2s", - "<4s", - "<8s", - "<16s", - "<32s", - "<64s", - "<128s", - "<256s", - "<512s", - "<1024s", - "<2048s", - "<4096s", -}; - using CoroutineLogBinProfiler = CoroutineLogBinProfilerTemplate; } diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h new file mode 100644 index 0000000..07ad082 --- /dev/null +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -0,0 +1,207 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef ACE_ROUTINE_COROUTINE_LOG_BIN_RENDERER_H +#define ACE_ROUTINE_COROUTINE_LOG_BIN_RENDERER_H + +#include // uint8_t, uint32_t +#include // Print +#include // printfTo() +#include "Coroutine.h" // Coroutine +#include "CoroutineProfiler.h" + +namespace ace_routine { + +/** + * Print the information in the CoroutineLogBinProfiler for each Coroutine + * in a human-readable table. For example, the output of `printTableTo(Serial, + * 0, 9)` for `examples/SoundManager` looks like this: + * + * @verbatim + * <2us <4us <8us <16us <32us <64us<128us<256us<512us + * soundManager 621 2091 0 0 5 3 0 0 0 1 + * soundRoutine 2162 553 1 0 1 2 2 1 0 + * + * The `init()` method resets the frequency count of the bins. + * + * @endverbatim + + */ +template +class CoroutineLogBinRendererTemplate { + public: + /** Typedef of the CoroutineLogBinProfiler supported by this class. */ + using Profiler = CoroutineLogBinProfilerTemplate; + + /** Constructor. */ + CoroutineLogBinRendererTemplate(T_COROUTINE** root) + : mRoot(root) + {} + + /** + * Loop over all coroutines and print the ASCII version of a histogram. This + * assumes that all the coroutines are using the same CoroutineProfiler + * class, so we can use any of the profilers to print the header, and the + * numbers will be lined up properly. + * + * @param printer destination of output, usually `Serial` + * @param binStart start index of the bins (0-31) + * @param binEnd end inex (exclusive) of the bins (0-32) + * @param clear call init() after printing (default true) + */ + void printTableTo( + Print& printer, + uint8_t binStart, + uint8_t binEnd, + bool clear = true + ) { + if (binEnd <= binStart) return; + + bool isHeaderPrinted = false; + for (Coroutine** p = mRoot; (*p) != nullptr; p = (*p)->getNext()) { + auto* profiler = (Profiler*) (*p)->getProfiler(); + if (! profiler) continue; + + // Print header if needed. + if (! isHeaderPrinted) { + ace_common::printfTo(printer, "%12.12s", ""); + printHeaderTo(printer, binStart, binEnd); + printer.println(); + isHeaderPrinted = true; + } + + // Print the coroutine name, truncated to 12 characters. The next column + // is a 5-digit number formatted into a 6-character block, so there will + // always be a space between the coroutine name and the next number. + (*p)->printNameTo(printer, 12); + + // Print the bins. The number of digits is automatically a log10() of + // the counts, so we should be able to visually scan the table and see + // which coroutine is taking too long. + printBinsTo(printer, profiler, binStart, binEnd); + printer.println(); + + if (clear) { + profiler->init(); + } + } + } + + private: + /** + * Print the header related to this profiler. + * + * @param printer destination of output + * @param binStart start index of the bins (0-31) + * @param binEnd end index (exclusive) of the bins (0-32) + */ + void printHeaderTo(Print& printer, uint8_t binStart, uint8_t binEnd) const { + if (binEnd <= binStart) return; + + binEnd = (binEnd > Profiler::kNumBins) ? Profiler::kNumBins : binEnd; + for (uint8_t i = binStart; i < binEnd; i++) { + ace_common::printfTo(printer, "%6.6s", kBinLabels[i]); + } + } + + /** + * Print the bins of this profiler as a single line of text with each bin + * printed as a 5-digit number in a 6-character box. If there are any + * remaining counts after the `binEnd`, the cummulative sum of the remaining + * bins are printed in another 6-character box. + * + * @param binStart start index of the bins (0-31) + * @param binEnd end index (exclusive) of the bins (0-32) + */ + void printBinsTo( + Print& printer, + Profiler* profiler, + uint8_t binStart, + uint8_t binEnd) const { + if (binEnd <= binStart) return; + + binEnd = (binEnd > Profiler::kNumBins) ? Profiler::kNumBins : binEnd; + for (uint8_t i = binStart; i < binEnd; i++) { + uint16_t count = profiler->mBins[i]; + ace_common::printfTo(printer, "%6u", count); + } + + uint32_t remaining = 0; + for (uint8_t i = binEnd; i < Profiler::kNumBins; i++) { + remaining += profiler->mBins[i]; + } + if (remaining > 0) { + ace_common::printfTo(printer, "%6lu", (unsigned long) remaining); + } + } + + private: + static const char* const kBinLabels[Profiler::kNumBins]; + + T_COROUTINE** mRoot; +}; + +// Labels for each bin in mBins. +template +const char* const CoroutineLogBinRendererTemplate::kBinLabels[ + CoroutineLogBinProfilerTemplate::kNumBins] = { + "<2us", + "<4us", + "<8us", + "<16us", + "<32us", + "<64us", + "<128us", + "<256us", + "<512us", + "<1ms", + "<2ms", + "<4ms", + "<8ms", + "<16ms", + "<32ms", + "<64ms", + "<128ms", + "<256ms", + "<512ms", + "<1s", + "<2s", + "<4s", + "<8s", + "<16s", + "<32s", + "<64s", + "<128s", + "<256s", + "<512s", + "<1024s", + "<2048s", + "<4096s", +}; + +using CoroutineLogBinRenderer = CoroutineLogBinRendererTemplate; + +} + +#endif From 5dcb848c95e5accec32d2df0c843b15eb4df6cc5 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 18:24:14 -0700 Subject: [PATCH 15/59] {examples,tests}/Makefile: Add AceCommon dependency --- examples/BlinkSlowFastManualRoutine/Makefile | 2 +- examples/BlinkSlowFastRoutine/Makefile | 2 +- examples/CountAndBlink/Makefile | 2 +- examples/Delay/Makefile | 2 +- examples/HelloCoroutine/Makefile | 2 +- examples/HelloManualCoroutine/Makefile | 2 +- examples/HelloScheduler/Makefile | 2 +- examples/MemoryBenchmark/Makefile | 2 +- examples/Pipe/Makefile | 2 +- examples/SoundManager/Makefile | 2 +- examples/Tasks/Makefile | 2 +- tests/ChannelTest/Makefile | 2 +- tests/ResetTest/Makefile | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/BlinkSlowFastManualRoutine/Makefile b/examples/BlinkSlowFastManualRoutine/Makefile index 4d56967..6ae2f9a 100644 --- a/examples/BlinkSlowFastManualRoutine/Makefile +++ b/examples/BlinkSlowFastManualRoutine/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := BlinkSlowFastManualRoutine -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/BlinkSlowFastRoutine/Makefile b/examples/BlinkSlowFastRoutine/Makefile index 00f684c..56ab28b 100644 --- a/examples/BlinkSlowFastRoutine/Makefile +++ b/examples/BlinkSlowFastRoutine/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := BlinkSlowFastRoutine -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/CountAndBlink/Makefile b/examples/CountAndBlink/Makefile index ade004f..68b0b14 100644 --- a/examples/CountAndBlink/Makefile +++ b/examples/CountAndBlink/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := CountAndBlink -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/Delay/Makefile b/examples/Delay/Makefile index 882873c..edd859d 100644 --- a/examples/Delay/Makefile +++ b/examples/Delay/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := Delay -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/HelloCoroutine/Makefile b/examples/HelloCoroutine/Makefile index 66e94e5..72ef17f 100644 --- a/examples/HelloCoroutine/Makefile +++ b/examples/HelloCoroutine/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := HelloCoroutine -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/HelloManualCoroutine/Makefile b/examples/HelloManualCoroutine/Makefile index e8fd352..bfaaf07 100644 --- a/examples/HelloManualCoroutine/Makefile +++ b/examples/HelloManualCoroutine/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := HelloManualCoroutine -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/HelloScheduler/Makefile b/examples/HelloScheduler/Makefile index 2901d3f..b26b516 100644 --- a/examples/HelloScheduler/Makefile +++ b/examples/HelloScheduler/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := HelloScheduler -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/MemoryBenchmark/Makefile b/examples/MemoryBenchmark/Makefile index bf4f415..8ddb22e 100644 --- a/examples/MemoryBenchmark/Makefile +++ b/examples/MemoryBenchmark/Makefile @@ -2,7 +2,7 @@ # EpoxyDuino to compile and run AUnit tests natively on Linux or MacOS. APP_NAME := MemoryBenchmark -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine MORE_CLEAN := more_clean include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/Pipe/Makefile b/examples/Pipe/Makefile index 1349596..252d9a5 100644 --- a/examples/Pipe/Makefile +++ b/examples/Pipe/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := Pipe -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/SoundManager/Makefile b/examples/SoundManager/Makefile index 6660500..24e1f30 100644 --- a/examples/SoundManager/Makefile +++ b/examples/SoundManager/Makefile @@ -2,6 +2,6 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := SoundManager -ARDUINO_LIBS := AceRoutine AceCommon +ARDUINO_LIBS := AceCommon AceRoutine EXTRA_CXXFLAGS := -g include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/Tasks/Makefile b/examples/Tasks/Makefile index aa3bedc..01ce7b2 100644 --- a/examples/Tasks/Makefile +++ b/examples/Tasks/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := Tasks -ARDUINO_LIBS := AceRoutine +ARDUINO_LIBS := AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/tests/ChannelTest/Makefile b/tests/ChannelTest/Makefile index 942e3d1..f7bf2d6 100644 --- a/tests/ChannelTest/Makefile +++ b/tests/ChannelTest/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := ChannelTest -ARDUINO_LIBS := AUnit AceRoutine +ARDUINO_LIBS := AUnit AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/tests/ResetTest/Makefile b/tests/ResetTest/Makefile index 2564b1d..518ebe0 100644 --- a/tests/ResetTest/Makefile +++ b/tests/ResetTest/Makefile @@ -2,5 +2,5 @@ # Makefile to compile and run Arduino programs natively on Linux or MacOS. APP_NAME := ResetTest -ARDUINO_LIBS := AUnit AceRoutine +ARDUINO_LIBS := AUnit AceCommon AceRoutine include ../../../EpoxyDuino/EpoxyDuino.mk From 35b8bec7182375d828a118f91a5206772f3042c2 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 18:40:09 -0700 Subject: [PATCH 16/59] CoroutineLogBinRenderer.h: Rollup bins below startBin and bins above endBin into the first and last bins --- examples/SoundManager/SoundManager.ino | 2 +- src/ace_routine/CoroutineLogBinProfiler.h | 2 + src/ace_routine/CoroutineLogBinRenderer.h | 84 ++++++++++++++--------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index da5c344..e20c81b 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -60,7 +60,7 @@ EXTERN_COROUTINE(soundManager); COROUTINE(printProfile) { COROUTINE_LOOP() { CoroutineLogBinRenderer renderer(getRoot()); - renderer.printTableTo(Serial, 0, 8); + renderer.printTableTo(Serial, 2, 12); COROUTINE_DELAY_SECONDS(5); } } diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h index dc61994..ebc6926 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -48,6 +48,8 @@ namespace ace_routine { * replaced by a '*' character.) Therefore the table is a rough ASCII version of * a log-log graph of the frequency count. * + * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, + * usually `Coroutine` */ template class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h index 07ad082..e34cc96 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -36,17 +36,22 @@ namespace ace_routine { /** * Print the information in the CoroutineLogBinProfiler for each Coroutine * in a human-readable table. For example, the output of `printTableTo(Serial, - * 0, 9)` for `examples/SoundManager` looks like this: + * 2, 10)` for `examples/SoundManager` looks like this: * * @verbatim - * <2us <4us <8us <16us <32us <64us<128us<256us<512us - * soundManager 621 2091 0 0 5 3 0 0 0 1 - * soundRoutine 2162 553 1 0 1 2 2 1 0 + * <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> + * soundManager 1418 0 0 1 0 0 0 0 1 0 + * soundRoutine 1417 0 0 1 1 1 0 0 0 0 + * @endverbatim + * + * The bins below the startBin are rolled into the first bin. The bins above the + * (endBin-1) are rolled into the last bin with the label `>>`. There must be at + * least 2 rendering bins (endBin >= startBin + 2) otherwise nothing is printed. * * The `init()` method resets the frequency count of the bins. * - * @endverbatim - + * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, + * usually `Coroutine` */ template class CoroutineLogBinRendererTemplate { @@ -66,17 +71,17 @@ class CoroutineLogBinRendererTemplate { * numbers will be lined up properly. * * @param printer destination of output, usually `Serial` - * @param binStart start index of the bins (0-31) - * @param binEnd end inex (exclusive) of the bins (0-32) + * @param startBin start index of the bins (0-31) + * @param endBin end inex (exclusive) of the bins (0-32) * @param clear call init() after printing (default true) */ void printTableTo( Print& printer, - uint8_t binStart, - uint8_t binEnd, + uint8_t startBin, + uint8_t endBin, bool clear = true ) { - if (binEnd <= binStart) return; + if (endBin <= startBin) return; bool isHeaderPrinted = false; for (Coroutine** p = mRoot; (*p) != nullptr; p = (*p)->getNext()) { @@ -86,7 +91,7 @@ class CoroutineLogBinRendererTemplate { // Print header if needed. if (! isHeaderPrinted) { ace_common::printfTo(printer, "%12.12s", ""); - printHeaderTo(printer, binStart, binEnd); + printHeaderTo(printer, startBin, endBin); printer.println(); isHeaderPrinted = true; } @@ -99,7 +104,7 @@ class CoroutineLogBinRendererTemplate { // Print the bins. The number of digits is automatically a log10() of // the counts, so we should be able to visually scan the table and see // which coroutine is taking too long. - printBinsTo(printer, profiler, binStart, binEnd); + printBinsTo(printer, profiler, startBin, endBin); printer.println(); if (clear) { @@ -113,56 +118,67 @@ class CoroutineLogBinRendererTemplate { * Print the header related to this profiler. * * @param printer destination of output - * @param binStart start index of the bins (0-31) - * @param binEnd end index (exclusive) of the bins (0-32) + * @param startBin start index of the bins (0-31) + * @param endBin end index (exclusive) of the bins (0-32) */ - void printHeaderTo(Print& printer, uint8_t binStart, uint8_t binEnd) const { - if (binEnd <= binStart) return; + void printHeaderTo(Print& printer, uint8_t startBin, uint8_t endBin) const { + endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; + if (endBin < startBin + 2) return; - binEnd = (binEnd > Profiler::kNumBins) ? Profiler::kNumBins : binEnd; - for (uint8_t i = binStart; i < binEnd; i++) { + for (uint8_t i = startBin; i < endBin - 1; i++) { ace_common::printfTo(printer, "%6.6s", kBinLabels[i]); } + ace_common::printfTo(printer, "%6.6s", ">>"); } /** * Print the bins of this profiler as a single line of text with each bin * printed as a 5-digit number in a 6-character box. If there are any - * remaining counts after the `binEnd`, the cummulative sum of the remaining + * remaining counts after the `endBin`, the cummulative sum of the remaining * bins are printed in another 6-character box. * - * @param binStart start index of the bins (0-31) - * @param binEnd end index (exclusive) of the bins (0-32) + * @param startBin start index of the bins (0-31) + * @param endBin end index (exclusive) of the bins (0-32) */ void printBinsTo( Print& printer, Profiler* profiler, - uint8_t binStart, - uint8_t binEnd) const { - if (binEnd <= binStart) return; + uint8_t startBin, + uint8_t endBin) const { - binEnd = (binEnd > Profiler::kNumBins) ? Profiler::kNumBins : binEnd; - for (uint8_t i = binStart; i < binEnd; i++) { + endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; + if (endBin < startBin + 2) return; + + // Rollup all bins below startBin into the first bin. + uint32_t underCount = 0; + for (uint8_t i = 0; i <= startBin; i++) { + underCount += profiler->mBins[i]; + } + if (underCount > UINT16_MAX) underCount = UINT16_MAX; + ace_common::printfTo(printer, "%6u", underCount); + + // Print interior bins. + for (uint8_t i = startBin + 1; i < endBin - 1; i++) { uint16_t count = profiler->mBins[i]; ace_common::printfTo(printer, "%6u", count); } - uint32_t remaining = 0; - for (uint8_t i = binEnd; i < Profiler::kNumBins; i++) { - remaining += profiler->mBins[i]; - } - if (remaining > 0) { - ace_common::printfTo(printer, "%6lu", (unsigned long) remaining); + // Rollup all bins at or above endBin into the last bin. + uint32_t overCount = 0; + for (uint8_t i = endBin - 1; i < Profiler::kNumBins; i++) { + overCount += profiler->mBins[i]; } + if (overCount > UINT16_MAX) overCount = UINT16_MAX; + ace_common::printfTo(printer, "%6u", overCount); } private: + /** Labels for each bin in CoroutineLogBinProfiler::mBins. */ static const char* const kBinLabels[Profiler::kNumBins]; T_COROUTINE** mRoot; }; -// Labels for each bin in mBins. template const char* const CoroutineLogBinRendererTemplate::kBinLabels[ CoroutineLogBinProfilerTemplate::kNumBins] = { From de3a91458fd782bb59b555d4a40ed8c7d925354f Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 19:00:32 -0700 Subject: [PATCH 17/59] CHANGELOG.md: Add CoroutineProfiler and CoroutineLogBinProfiler --- CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a630f6..85e300a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,22 @@ * Increases flash usage by 6-10 bytes per coroutine. * Increases static ram usage by 3 bytes (AVR) or 4 bytes (32-bit) per coroutine. + * Support `CoroutineProfiler` in `CoroutineScheduler`. + * If a coroutine contains a valid pointer to a `CoroutineProfiler`, then + `CoroutineScheduler::runCoroutine()` will measure the elapsed + microseconds for the `Coroutine::runCoroutine()` to run. + * It then calls `CoroutineProfiler::updateElapsedMicros()` to allow the + profiler to update its internal tracking. + * Provide `CoroutineLogBinProfiler`, and specific subclass that collects + the frequency count of the elapsed microseconds using 32 bins + representing the `log2()` function of the microseconds. + * Provide `CoroutineLogBinProfiler::printBinsTo()` which prints + a table of the frequency count over all coroutines. This represents a + poor-man's version of the log-log graph of the frequency count. + * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes + for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is + not used. This is a one-time hit. + * See [examples/SoundManager](examples/SoundManager) for an example. * 1.4.2 (2022-02-04) * Remove dependency to AceCommon library in `libraries.properties`. * AceRoutine core no longer depends on AceCommon. From ddba0600903d9b760f2def56c551b200b9272b8e Mon Sep 17 00:00:00 2001 From: Brian Park Date: Mon, 14 Mar 2022 19:08:03 -0700 Subject: [PATCH 18/59] CoroutineLogBinRenderer.h: Update labels to account for 2^10 being slightly larger than 1000 --- src/ace_routine/CoroutineLogBinRenderer.h | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h index e34cc96..dc4dd40 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -196,24 +196,24 @@ const char* const CoroutineLogBinRendererTemplate::kBinLabels[ "<4ms", "<8ms", "<16ms", - "<32ms", - "<64ms", - "<128ms", - "<256ms", - "<512ms", + "<33ms", + "<66ms", + "<131ms", + "<262ms", + "<524ms", "<1s", "<2s", "<4s", "<8s", - "<16s", - "<32s", - "<64s", - "<128s", - "<256s", - "<512s", - "<1024s", - "<2048s", - "<4096s", + "<17s", + "<34s", + "<67s", + "<134s", + "<268s", + "<537s", + "<1074s", + "<2147s", + "<4295s", }; using CoroutineLogBinRenderer = CoroutineLogBinRendererTemplate; From 44f9a5439fdb645df5f1e6c2d623896a3ca27a36 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 15 Mar 2022 09:40:15 -0700 Subject: [PATCH 19/59] CoroutineLogBinProfiler.h: Add createProfilers(), deleteProfilers(), initProfilers() --- src/ace_routine/Coroutine.h | 20 +++++++++---- src/ace_routine/CoroutineLogBinProfiler.h | 34 ++++++++++++++++++++++- src/ace_routine/CoroutineLogBinRenderer.h | 8 ++++-- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index 93d35b2..02e46d9 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -350,13 +350,13 @@ class CoroutineTemplate { * hexadecimal representation of the pointer to the coroutine. * * @param printer destination of output, usually `Serial` - * @param maxLen truncate to maxLen if given + * @param maxLen truncate or pad to maxLen if given */ void printNameTo(Print& printer, uint8_t maxLen = 0) const { // Need to go through this contortion because vsnprintf() does not support // flash string parameters, so I can't use something like "%12.12s" with // a flash string. - ace_common::PrintStr<128> pname; + ace_common::PrintStr<64> pname; if (mName == nullptr) { pname.print("0x"); @@ -367,9 +367,19 @@ class CoroutineTemplate { pname.print((const __FlashStringHelper*) mName); } - // Print up to maxLen characters. - maxLen = (maxLen == 0) ? pname.length() : maxLen; - printer.write(pname.cstr(), maxLen); + // Print name, truncated to maxLen or padded to maxLen. + if (maxLen) { + if (pname.length() < maxLen) { + printer.write(pname.cstr()); + for (uint8_t i = pname.length(); i < maxLen; i++) { + printer.write(' '); + } + } else { + printer.write(pname.cstr(), maxLen); + } + } else { + printer.write(pname.cstr()); + } } /** diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h index ebc6926..7f4b9c7 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -73,7 +73,7 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { * the number of samples whose elapsed micros is between 2^i and 2^(i+1). * Example, for Bin 3, and this bin contains the number of samples which * satsify (8us <= elapsed < 16us). The exception is Bin 0 because it - * includes samples where elapsed = 0 as well, so the sample interval for + * includes samples where elapsed is 0 as well, so the sample interval for * Bin 0 is (0 <= elapsed < 2), instead of (1 <= elapsed < 2). */ void updateElapsedMicros(uint32_t micros) override { @@ -90,6 +90,38 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { } } + /** + * Create a profiler on the heap for each coroutine in the singly-linked + * list of coroutines defined by `root`. + */ + static void createProfilers(T_COROUTINE** root) { + for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + auto* profiler = new CoroutineLogBinProfilerTemplate(); + (*p)->setProfiler(profiler); + } + } + + /** Delete the profilers created by createProfilers(). */ + static void deleteProfilers(T_COROUTINE** root) { + for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + auto* profiler = (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + if (profiler) { + delete profiler; + (*p)->setProfiler(nullptr); + } + } + } + + /** Init all profilers for all coroutines defined by `root`. */ + static void initProfilers(T_COROUTINE** root) { + for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + auto* profiler = (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + if (profiler) { + profiler->init(); + } + } + } + public: uint16_t mBins[kNumBins]; }; diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h index dc4dd40..c958f73 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -121,7 +121,9 @@ class CoroutineLogBinRendererTemplate { * @param startBin start index of the bins (0-31) * @param endBin end index (exclusive) of the bins (0-32) */ - void printHeaderTo(Print& printer, uint8_t startBin, uint8_t endBin) const { + static void printHeaderTo( + Print& printer, uint8_t startBin, uint8_t endBin) { + endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; if (endBin < startBin + 2) return; @@ -140,11 +142,11 @@ class CoroutineLogBinRendererTemplate { * @param startBin start index of the bins (0-31) * @param endBin end index (exclusive) of the bins (0-32) */ - void printBinsTo( + static void printBinsTo( Print& printer, Profiler* profiler, uint8_t startBin, - uint8_t endBin) const { + uint8_t endBin) { endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; if (endBin < startBin + 2) return; From 1f13ac071e26303f0661493f3ac0b8c16404d517 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 15 Mar 2022 17:00:12 -0700 Subject: [PATCH 20/59] tests/SchedulerTest: Add coroutine names; fix broken test, pointer value now printed in hex instead of decimal --- tests/SchedulerTest/SchedulerTest.ino | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/SchedulerTest/SchedulerTest.ino b/tests/SchedulerTest/SchedulerTest.ino index 4dd813f..4b9fb57 100644 --- a/tests/SchedulerTest/SchedulerTest.ino +++ b/tests/SchedulerTest/SchedulerTest.ino @@ -77,10 +77,11 @@ test(AceRoutineTest, scheduler) { TestableCoroutineScheduler::list(output); PrintStr<200> expected; - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", (uintptr_t) &a); - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", (uintptr_t) &b); - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", (uintptr_t) &c); - printfTo(expected, "Coroutine %ld; status: Suspended\r\n", + printfTo(expected, "Coroutine coA; status: Yielding\r\n"); + printfTo(expected, "Coroutine coB; status: Yielding\r\n"); + printfTo(expected, "Coroutine 0x%lX; status: Yielding\r\n", + (unsigned long) &c); + printfTo(expected, "Coroutine 0x%lX; status: Suspended\r\n", (uintptr_t) &extra); assertEqual(expected.cstr(), output.cstr()); @@ -410,6 +411,9 @@ void setup() { // suspended coroutine will be retained in the linked list of coroutines. extra.suspend(); + // Set human-readable names to some coroutines. + a.setCName("coA"); + b.setFName(F("coB")); TestableCoroutineScheduler::setup(); } From e1397028968470cd379a7278cc6b0edbe39f3be7 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Tue, 15 Mar 2022 17:07:29 -0700 Subject: [PATCH 21/59] tests/SuspendTest: Fix test, unnamed coroutines now printed in hexadecimal instead of decimal --- tests/SuspendTest/SuspendTest.ino | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/SuspendTest/SuspendTest.ino b/tests/SuspendTest/SuspendTest.ino index 8d9a89c..a436288 100644 --- a/tests/SuspendTest/SuspendTest.ino +++ b/tests/SuspendTest/SuspendTest.ino @@ -33,30 +33,30 @@ test(suspendAndResume) { CoroutineScheduler::list(output); PrintStr<100> expected; - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", - (uintptr_t) &routine1); - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", - (uintptr_t) &routine2); + printfTo(expected, "Coroutine 0x%lX; status: Yielding\r\n", + (unsigned long) &routine1); + printfTo(expected, "Coroutine 0x%lX; status: Yielding\r\n", + (unsigned long) &routine2); assertEqual(expected.cstr(), output.cstr()); output.flush(); expected.flush(); routine2.suspend(); CoroutineScheduler::list(output); - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", - (uintptr_t) &routine1); - printfTo(expected, "Coroutine %ld; status: Suspended\r\n", - (uintptr_t) &routine2); + printfTo(expected, "Coroutine 0x%lX; status: Yielding\r\n", + (unsigned long) &routine1); + printfTo(expected, "Coroutine 0x%lX; status: Suspended\r\n", + (unsigned long) &routine2); assertEqual(expected.cstr(), output.cstr()); output.flush(); expected.flush(); routine2.resume(); CoroutineScheduler::list(output); - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", - (uintptr_t) &routine1); - printfTo(expected, "Coroutine %ld; status: Yielding\r\n", - (uintptr_t) &routine2); + printfTo(expected, "Coroutine 0x%lX; status: Yielding\r\n", + (unsigned long) &routine1); + printfTo(expected, "Coroutine 0x%lX; status: Yielding\r\n", + (unsigned long) &routine2); assertEqual(expected.cstr(), output.cstr()); } From 9882df10b677b7e606e027005e10b004d7713dda Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 10:57:47 -0700 Subject: [PATCH 22/59] CoroutineLogBinProfiler.h: Rename init() to clear(); initProfilers() to clearProfilers() --- src/ace_routine/CoroutineLogBinProfiler.h | 33 +++++++++++++---------- src/ace_routine/CoroutineLogBinRenderer.h | 24 ++++++++++------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h index 7f4b9c7..4d307f6 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -40,13 +40,9 @@ namespace ace_routine { * to a given coroutine through the `Coroutine::setProfiler()` method. * * After sufficient number of samples are collected, the frequency distribution - * of all profilers for all coroutines can be printed as a table using the - * `printBinsTo()` static helper function. Each bin is printed as a 5-digit - * number (since the bins use a `uint16_t` integer for the count). The number of - * digits in the printed number is equivalent to the log10() of the frequency - * count. (To see why that's true, imagine if each digit of the bin count was - * replaced by a '*' character.) Therefore the table is a rough ASCII version of - * a log-log graph of the frequency count. + * of all profilers for all coroutines can be printed by a renderer. An + * implementation of such a render is `CoroutineLogBinRendererTemplate` + * which prints the frequency distribution as a formatted table. * * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, * usually `Coroutine` @@ -59,11 +55,11 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { public: /** Constructor. */ CoroutineLogBinProfilerTemplate() { - init(); + clear(); } /** Clear the bins. */ - void init() { + void clear() { memset(mBins, 0, sizeof(mBins)); } @@ -91,11 +87,20 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { } /** - * Create a profiler on the heap for each coroutine in the singly-linked - * list of coroutines defined by `root`. + * Create a new profiler on the heap and attach it to each coroutine in the + * singly-linked list of coroutines defined by `root`. */ static void createProfilers(T_COROUTINE** root) { for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + + // Delete any existing profiler. + auto* currentProfiler = + (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + if (currentProfiler) { + delete currentProfiler; + } + + // Attach new profiler. auto* profiler = new CoroutineLogBinProfilerTemplate(); (*p)->setProfiler(profiler); } @@ -112,12 +117,12 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { } } - /** Init all profilers for all coroutines defined by `root`. */ - static void initProfilers(T_COROUTINE** root) { + /** Clear counters for all profilers in the coroutines defined by `root`. */ + static void clearProfilers(T_COROUTINE** root) { for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); if (profiler) { - profiler->init(); + profiler->clear(); } } } diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h index c958f73..8899a6f 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -35,11 +35,18 @@ namespace ace_routine { /** * Print the information in the CoroutineLogBinProfiler for each Coroutine - * in a human-readable table. For example, the output of `printTableTo(Serial, - * 2, 10)` for `examples/SoundManager` looks like this: + * in a human-readable table. Each bin is printed as a 5-digit number, since the + * bins use a `uint16_t` integer for the count. The number of digits in the + * printed number is equivalent to the log10() of the frequency count. To see + * why that's true, imagine if each digit of the bin count was replaced by a '*' + * character. Therefore the table is a rough ASCII version of a log-log graph of + * the frequency count. + * + * For example, the output of `printTableTo(Serial, 2, 10)` for + * `examples/SoundManager` looks like this: * * @verbatim - * <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> + * name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> * soundManager 1418 0 0 1 0 0 0 0 1 0 * soundRoutine 1417 0 0 1 1 1 0 0 0 0 * @endverbatim @@ -48,8 +55,6 @@ namespace ace_routine { * (endBin-1) are rolled into the last bin with the label `>>`. There must be at * least 2 rendering bins (endBin >= startBin + 2) otherwise nothing is printed. * - * The `init()` method resets the frequency count of the bins. - * * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, * usually `Coroutine` */ @@ -72,8 +77,9 @@ class CoroutineLogBinRendererTemplate { * * @param printer destination of output, usually `Serial` * @param startBin start index of the bins (0-31) - * @param endBin end inex (exclusive) of the bins (0-32) - * @param clear call init() after printing (default true) + * @param endBin end index (exclusive) of the bins (0-32) + * @param clear call CoroutineLogBinProfiler::clear() after printing + * (default true) */ void printTableTo( Print& printer, @@ -90,7 +96,7 @@ class CoroutineLogBinRendererTemplate { // Print header if needed. if (! isHeaderPrinted) { - ace_common::printfTo(printer, "%12.12s", ""); + ace_common::printfTo(printer, "%-12.12s", "name"); printHeaderTo(printer, startBin, endBin); printer.println(); isHeaderPrinted = true; @@ -108,7 +114,7 @@ class CoroutineLogBinRendererTemplate { printer.println(); if (clear) { - profiler->init(); + profiler->clear(); } } } From ec1712bb1654137691efbc66658749fa4ce07213 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 13:25:11 -0700 Subject: [PATCH 23/59] CoroutineLogBinProfiler.h,LogBinProfilerTest: Extract rollupExteriorBins() into a separate function, for reuse by other renderers --- src/AceRoutine.h | 1 + src/ace_routine/CoroutineLogBinProfiler.h | 41 ++++++++ src/ace_routine/CoroutineLogBinRenderer.h | 51 +++++----- .../LogBinProfilerTest/LogBinProfilerTest.ino | 95 +++++++++++++++++++ tests/LogBinProfilerTest/Makefile | 6 ++ 5 files changed, 168 insertions(+), 26 deletions(-) create mode 100644 tests/LogBinProfilerTest/LogBinProfilerTest.ino create mode 100644 tests/LogBinProfilerTest/Makefile diff --git a/src/AceRoutine.h b/src/AceRoutine.h index 2ca390d..c6ed99f 100644 --- a/src/AceRoutine.h +++ b/src/AceRoutine.h @@ -51,6 +51,7 @@ SOFTWARE. #include "ace_routine/CoroutineProfiler.h" #include "ace_routine/CoroutineLogBinProfiler.h" #include "ace_routine/CoroutineLogBinRenderer.h" +#include "ace_routine/CoroutineLogBinJsonRenderer.h" #include "ace_routine/Channel.h" #endif diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/CoroutineLogBinProfiler.h index 4d307f6..efe1567 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/CoroutineLogBinProfiler.h @@ -133,6 +133,47 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { using CoroutineLogBinProfiler = CoroutineLogBinProfilerTemplate; +/** + * Rollup bins before `startBin` into `startBin` and bins at or after + * `endBin` into the last bin (at `endBin - 1`). This is useful to preserve + * count information when printing only a subset of the `mBins[]` array. If + * `endBin <= startBin`, this function does nothing. If `endBin < startBin - + * 1`, there is only single interior bin, so everything gets rolled up into + * the single bin. This is probably not useful, but at least it's + * mathematically correct. + */ +inline void rollupExteriorBins( + uint16_t dst[], + const uint16_t src[], + uint8_t numBins, + uint8_t startBin, + uint8_t endBin +) { + endBin = (endBin > numBins) ? numBins : endBin; + if (endBin <= startBin) return; + + // Rollup all bins at or below startBin into the startBin. + uint32_t leftRollup = 0; + for (uint8_t i = 0; i <= startBin; i++) { + leftRollup += src[i]; + } + if (leftRollup > UINT16_MAX) leftRollup = UINT16_MAX; + dst[startBin] = leftRollup; + + // Copy the interior bins. + for (uint8_t i = startBin + 1; i < endBin - 1; i++) { + dst[i] = src[i]; + } + + // Rollup all bins at or above the last bin into the last bin. + uint32_t rightRollup = (endBin - 1 == startBin) ? leftRollup : 0; + for (uint8_t i = endBin - 1; i < numBins; i++) { + rightRollup += src[i]; + } + if (rightRollup > UINT16_MAX) rightRollup = UINT16_MAX; + dst[endBin - 1] = rightRollup; +} + } #endif diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h index 8899a6f..b4e10cc 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -80,15 +80,20 @@ class CoroutineLogBinRendererTemplate { * @param endBin end index (exclusive) of the bins (0-32) * @param clear call CoroutineLogBinProfiler::clear() after printing * (default true) + * @param rollup roll-up exterior bins into the startBin and (endBin-1) bin + * (default true) */ void printTableTo( Print& printer, uint8_t startBin, uint8_t endBin, - bool clear = true + bool clear = true, + bool rollup = true ) { if (endBin <= startBin) return; + uint16_t bufBins[Profiler::kNumBins]; + bool isHeaderPrinted = false; for (Coroutine** p = mRoot; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = (Profiler*) (*p)->getProfiler(); @@ -107,10 +112,20 @@ class CoroutineLogBinRendererTemplate { // always be a space between the coroutine name and the next number. (*p)->printNameTo(printer, 12); + // Roll up the exterior bins in to the first and last bins if requested. + const uint16_t* bins; + if (rollup) { + rollupExteriorBins(bufBins, profiler->mBins, Profiler::kNumBins, + startBin, endBin); + bins = bufBins; + } else { + bins = profiler->mBins; + } + // Print the bins. The number of digits is automatically a log10() of // the counts, so we should be able to visually scan the table and see // which coroutine is taking too long. - printBinsTo(printer, profiler, startBin, endBin); + printBinsTo(printer, bins, Profiler::kNumBins, startBin, endBin); printer.println(); if (clear) { @@ -131,7 +146,7 @@ class CoroutineLogBinRendererTemplate { Print& printer, uint8_t startBin, uint8_t endBin) { endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; - if (endBin < startBin + 2) return; + if (endBin <= startBin) return; // needed if startBin = endBin = 0 for (uint8_t i = startBin; i < endBin - 1; i++) { ace_common::printfTo(printer, "%6.6s", kBinLabels[i]); @@ -145,39 +160,23 @@ class CoroutineLogBinRendererTemplate { * remaining counts after the `endBin`, the cummulative sum of the remaining * bins are printed in another 6-character box. * + * @param printer usual `Serial` + * @param bins pointer to array of bins * @param startBin start index of the bins (0-31) * @param endBin end index (exclusive) of the bins (0-32) */ static void printBinsTo( Print& printer, - Profiler* profiler, + const uint16_t bins[], + uint8_t numBins, uint8_t startBin, uint8_t endBin) { - endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; - if (endBin < startBin + 2) return; - - // Rollup all bins below startBin into the first bin. - uint32_t underCount = 0; - for (uint8_t i = 0; i <= startBin; i++) { - underCount += profiler->mBins[i]; - } - if (underCount > UINT16_MAX) underCount = UINT16_MAX; - ace_common::printfTo(printer, "%6u", underCount); - - // Print interior bins. - for (uint8_t i = startBin + 1; i < endBin - 1; i++) { - uint16_t count = profiler->mBins[i]; + endBin = (endBin > numBins) ? numBins : endBin; + for (uint8_t i = startBin; i < endBin; i++) { + uint16_t count = bins[i]; ace_common::printfTo(printer, "%6u", count); } - - // Rollup all bins at or above endBin into the last bin. - uint32_t overCount = 0; - for (uint8_t i = endBin - 1; i < Profiler::kNumBins; i++) { - overCount += profiler->mBins[i]; - } - if (overCount > UINT16_MAX) overCount = UINT16_MAX; - ace_common::printfTo(printer, "%6u", overCount); } private: diff --git a/tests/LogBinProfilerTest/LogBinProfilerTest.ino b/tests/LogBinProfilerTest/LogBinProfilerTest.ino new file mode 100644 index 0000000..c02bda0 --- /dev/null +++ b/tests/LogBinProfilerTest/LogBinProfilerTest.ino @@ -0,0 +1,95 @@ +#line 2 "LogBinProfilerTest.ino" + +#include +#include + +using ace_routine::CoroutineLogBinProfiler; +using ace_routine::rollupExteriorBins; +using aunit::TestRunner; + +// --------------------------------------------------------------------------- +// Test CorooutineLogBinProfiler functions. +// --------------------------------------------------------------------------- + +test(updateElapsedMicros) { + CoroutineLogBinProfiler profiler; + + profiler.updateElapsedMicros(0); + assertEqual(profiler.mBins[0], 1); + + profiler.updateElapsedMicros(1); + assertEqual(profiler.mBins[0], 2); + + profiler.updateElapsedMicros(2); + assertEqual(profiler.mBins[1], 1); + + profiler.updateElapsedMicros(1024); + assertEqual(profiler.mBins[10], 1); + + profiler.updateElapsedMicros(1025); + assertEqual(profiler.mBins[10], 2); + + profiler.updateElapsedMicros(UINT32_MAX); + assertEqual(profiler.mBins[31], 1); +} + +test(rollupExteriorBins) { + CoroutineLogBinProfiler profiler; + profiler.mBins[0] = 1; + profiler.mBins[1] = 2; + profiler.mBins[2] = 3; + profiler.mBins[30] = 11; + profiler.mBins[31] = 12; + + uint16_t bufBins[32]; + + rollupExteriorBins(bufBins, profiler.mBins, profiler.kNumBins, 0, 32); + assertEqual(bufBins[0], 1); + assertEqual(bufBins[1], 2); + assertEqual(bufBins[2], 3); + assertEqual(bufBins[3], 0); + assertEqual(bufBins[30], 11); + assertEqual(bufBins[31], 12); + + rollupExteriorBins(bufBins, profiler.mBins, profiler.kNumBins, 1, 31); + assertEqual(bufBins[1], 3); + assertEqual(bufBins[2], 3); + assertEqual(bufBins[3], 0); + assertEqual(bufBins[29], 0); + assertEqual(bufBins[30], 23); + + rollupExteriorBins(bufBins, profiler.mBins, profiler.kNumBins, 2, 30); + assertEqual(bufBins[2], 6); + assertEqual(bufBins[3], 0); + assertEqual(bufBins[29], 23); + + rollupExteriorBins(bufBins, profiler.mBins, profiler.kNumBins, 10, 12); + assertEqual(bufBins[10], 6); + assertEqual(bufBins[11], 23); + + rollupExteriorBins(bufBins, profiler.mBins, profiler.kNumBins, 10, 11); + assertEqual(bufBins[10], 29); + + // If startBin == endBin, no rollup should be performed, so bufBins[] should + // be untouched. + bufBins[0] = 9999; + bufBins[1] = 9999; + rollupExteriorBins(bufBins, profiler.mBins, profiler.kNumBins, 0, 0); + assertEqual(bufBins[0], 9999); + assertEqual(bufBins[1], 9999); +} + +// --------------------------------------------------------------------------- + +void setup() { +#if ! defined(EPOXY_DUINO) + delay(1000); // some boards reboot twice +#endif + + Serial.begin(115200); + while (!Serial); // Leonardo/Micro +} + +void loop() { + TestRunner::run(); +} diff --git a/tests/LogBinProfilerTest/Makefile b/tests/LogBinProfilerTest/Makefile new file mode 100644 index 0000000..af5037f --- /dev/null +++ b/tests/LogBinProfilerTest/Makefile @@ -0,0 +1,6 @@ +# See https://github.com/bxparks/EpoxyDuino for documentation about this +# Makefile to compile and run Arduino programs natively on Linux or MacOS. + +APP_NAME := LogBinProfilerTest +ARDUINO_LIBS := AUnit AceCommon AceRoutine +include ../../../EpoxyDuino/EpoxyDuino.mk From 82930c3dcbe8409f1f6cc26364d9dc1f230adaa5 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 13:30:54 -0700 Subject: [PATCH 24/59] CoroutineLogBinJsonRenderer.h: Add a renderer that prints JSON version of profiler frequency distributions --- examples/SoundManager/SoundManager.ino | 9 +- src/ace_routine/CoroutineLogBinJsonRenderer.h | 126 ++++++++++++++++++ src/ace_routine/CoroutineLogBinRenderer.h | 2 +- 3 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 src/ace_routine/CoroutineLogBinJsonRenderer.h diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index e20c81b..54b3a5c 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -53,14 +53,19 @@ using ace_routine::Coroutine;; using ace_routine::CoroutineScheduler; using ace_routine::CoroutineLogBinProfiler; using ace_routine::CoroutineLogBinRenderer; +using ace_routine::CoroutineLogBinJsonRenderer; SoundRoutine soundRoutine; EXTERN_COROUTINE(soundManager); COROUTINE(printProfile) { COROUTINE_LOOP() { - CoroutineLogBinRenderer renderer(getRoot()); - renderer.printTableTo(Serial, 2, 12); + CoroutineLogBinRenderer tableRenderer(getRoot()); + tableRenderer.printTableTo(Serial, 2, 12, false /*clear*/); + + CoroutineLogBinJsonRenderer jsonRenderer(getRoot()); + jsonRenderer.printJsonTo(Serial, 2, 12); + COROUTINE_DELAY_SECONDS(5); } } diff --git a/src/ace_routine/CoroutineLogBinJsonRenderer.h b/src/ace_routine/CoroutineLogBinJsonRenderer.h new file mode 100644 index 0000000..7f1996d --- /dev/null +++ b/src/ace_routine/CoroutineLogBinJsonRenderer.h @@ -0,0 +1,126 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef ACE_ROUTINE_COROUTINE_LOG_BIN_JSON_RENDERER_H +#define ACE_ROUTINE_COROUTINE_LOG_BIN_JSON_RENDERER_H + +#include // uint8_t, uint32_t +#include // Print +#include // printfTo() +#include "Coroutine.h" // Coroutine +#include "CoroutineProfiler.h" + +namespace ace_routine { + +/** + * Print the `CoroutineLogBinProfiler bins as a JSON array. For example, here + * is the output from `examples/SoundManager`: + * + * @verbatim + * { + * "soundManager":[1411,0,2,0,0,0,0,0,0,0], + * "soundRoutine":[1411,0,1,1,0,0,0,0,0,0] + * } + * @endverbatim + */ +template +class CoroutineLogBinJsonRendererTemplate { + public: + /** Typedef of the CoroutineLogBinProfiler supported by this class. */ + using Profiler = CoroutineLogBinProfilerTemplate; + + /** Constructor. */ + CoroutineLogBinJsonRendererTemplate(T_COROUTINE** root) + : mRoot(root) + {} + + /** + * Loop over all coroutines and print the bin counts as JSON. + * + * @param printer destination of output, usually `Serial` + * @param startBin start index of the bins (0-31) + * @param endBin end index (exclusive) of the bins (0-32) + * @param clear call CoroutineLogBinProfiler::clear() after printing + * (default true) + * @param rollup roll-up exterior bins into the first and last bins + * (default true) + */ + void printJsonTo( + Print& printer, + uint8_t startBin, + uint8_t endBin, + bool clear = true, + bool rollup = true + ) { + uint16_t bufBins[Profiler::kNumBins]; + + printer.println('{'); + bool lineNeedsTrailingComma = false; + for (Coroutine** p = mRoot; (*p) != nullptr; p = (*p)->getNext()) { + auto* profiler = (Profiler*) (*p)->getProfiler(); + if (! profiler) continue; + + // Roll up the exterior bins in to the first and last bins if requested. + const uint16_t* bins; + if (rollup) { + rollupExteriorBins(bufBins, profiler->mBins, Profiler::kNumBins, + startBin, endBin); + bins = bufBins; + } else { + bins = profiler->mBins; + } + + if (lineNeedsTrailingComma) printer.println(','); + lineNeedsTrailingComma = true; + + printer.print('"'); + (*p)->printNameTo(printer); + printer.print("\":["); + + bool elementNeedsTrailingComma = false; + for (uint8_t i = startBin; i < endBin; i++) { + if (elementNeedsTrailingComma) printer.print(','); + elementNeedsTrailingComma = true; + printer.print(bins[i]); + } + printer.print(']'); + + if (clear) { + profiler->clear(); + } + } + printer.println(); + printer.println('}'); + } + + public: + T_COROUTINE** mRoot; +}; + +using CoroutineLogBinJsonRenderer = + CoroutineLogBinJsonRendererTemplate; + +} + +#endif diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/CoroutineLogBinRenderer.h index b4e10cc..fcc19f5 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/CoroutineLogBinRenderer.h @@ -80,7 +80,7 @@ class CoroutineLogBinRendererTemplate { * @param endBin end index (exclusive) of the bins (0-32) * @param clear call CoroutineLogBinProfiler::clear() after printing * (default true) - * @param rollup roll-up exterior bins into the startBin and (endBin-1) bin + * @param rollup roll-up exterior bins into the first and last bins * (default true) */ void printTableTo( From ebedea8a191fbc5a701d7d44a5783ccde0ae0f63 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 13:45:50 -0700 Subject: [PATCH 25/59] src/*LogBin*.h: Rename CoroutineLogBinXxx classes to LogBinXxx for simplicity --- CHANGELOG.md | 11 +++--- examples/MemoryBenchmark/README.md | 7 +--- examples/MemoryBenchmark/generate_readme.py | 7 +--- examples/SoundManager/SoundManager.ino | 19 +++++----- src/AceRoutine.h | 8 ++--- ...BinJsonRenderer.h => LogBinJsonRenderer.h} | 21 ++++++----- ...utineLogBinProfiler.h => LogBinProfiler.h} | 20 +++++------ ...LogBinRenderer.h => LogBinTableRenderer.h} | 36 +++++++++---------- .../LogBinProfilerTest/LogBinProfilerTest.ino | 6 ++-- 9 files changed, 63 insertions(+), 72 deletions(-) rename src/ace_routine/{CoroutineLogBinJsonRenderer.h => LogBinJsonRenderer.h} (84%) rename src/ace_routine/{CoroutineLogBinProfiler.h => LogBinProfiler.h} (89%) rename src/ace_routine/{CoroutineLogBinRenderer.h => LogBinTableRenderer.h} (85%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85e300a..e32fd7e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,12 +15,15 @@ microseconds for the `Coroutine::runCoroutine()` to run. * It then calls `CoroutineProfiler::updateElapsedMicros()` to allow the profiler to update its internal tracking. - * Provide `CoroutineLogBinProfiler`, and specific subclass that collects + * Provide `LogBinProfiler`, and specific subclass that collects the frequency count of the elapsed microseconds using 32 bins representing the `log2()` function of the microseconds. - * Provide `CoroutineLogBinProfiler::printBinsTo()` which prints - a table of the frequency count over all coroutines. This represents a - poor-man's version of the log-log graph of the frequency count. + * Provide 2 renderers: + * `LogBinTableRenderer::printTo()` prints a formatted table of the + frequency count over all coroutines. This represents a poor-man's + version of the log-log graph of the frequency count. + * `LogBinJsonRenderer::printTo()` prints the frequency count + in JSON format. * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 37e38f6..fd2c782 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -108,12 +108,7 @@ calculated flash size can jump around in unexpected ways. used. * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per coroutine. - * Add a `CoroutineLogBinProfiler` to 2 coroutines. - * Use a 3rd coroutine to print the frequency count to the `Serial` - output every 10 seconds. - * Provide `CoroutineLogBinProfiler::printBinsTo()` which prints - a table of the frequency count over all coroutines. This represents a - poor-man's version of the log-log graph of the frequency count. + * Support `CoroutineProfiler` in the `CoroutineScheduler`. * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index 755251c..f4176fd 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -132,12 +132,7 @@ used. * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per coroutine. - * Add a `CoroutineLogBinProfiler` to 2 coroutines. - * Use a 3rd coroutine to print the frequency count to the `Serial` - output every 10 seconds. - * Provide `CoroutineLogBinProfiler::printBinsTo()` which prints - a table of the frequency count over all coroutines. This represents a - poor-man's version of the log-log graph of the frequency count. + * Support `CoroutineProfiler` in the `CoroutineScheduler`. * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index 54b3a5c..c7cd505 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -51,28 +51,27 @@ using ace_routine::Coroutine;; using ace_routine::CoroutineScheduler; -using ace_routine::CoroutineLogBinProfiler; -using ace_routine::CoroutineLogBinRenderer; -using ace_routine::CoroutineLogBinJsonRenderer; +using ace_routine::LogBinProfiler; +using ace_routine::LogBinTableRenderer; +using ace_routine::LogBinJsonRenderer; SoundRoutine soundRoutine; EXTERN_COROUTINE(soundManager); COROUTINE(printProfile) { COROUTINE_LOOP() { - CoroutineLogBinRenderer tableRenderer(getRoot()); - tableRenderer.printTableTo(Serial, 2, 12, false /*clear*/); + LogBinTableRenderer tableRenderer(getRoot()); + tableRenderer.printTo(Serial, 2, 12, false /*clear*/); - CoroutineLogBinJsonRenderer jsonRenderer(getRoot()); - jsonRenderer.printJsonTo(Serial, 2, 12); + LogBinJsonRenderer jsonRenderer(getRoot()); + jsonRenderer.printTo(Serial, 2, 12); COROUTINE_DELAY_SECONDS(5); } } - -CoroutineLogBinProfiler soundRoutineProfiler; -CoroutineLogBinProfiler soundManagerProfiler; +LogBinProfiler soundRoutineProfiler; +LogBinProfiler soundManagerProfiler; void setup() { delay(1000); diff --git a/src/AceRoutine.h b/src/AceRoutine.h index c6ed99f..9947f94 100644 --- a/src/AceRoutine.h +++ b/src/AceRoutine.h @@ -48,10 +48,10 @@ SOFTWARE. #include "ace_routine/Coroutine.h" #include "ace_routine/CoroutineScheduler.h" -#include "ace_routine/CoroutineProfiler.h" -#include "ace_routine/CoroutineLogBinProfiler.h" -#include "ace_routine/CoroutineLogBinRenderer.h" -#include "ace_routine/CoroutineLogBinJsonRenderer.h" #include "ace_routine/Channel.h" +#include "ace_routine/CoroutineProfiler.h" +#include "ace_routine/LogBinProfiler.h" +#include "ace_routine/LogBinTableRenderer.h" +#include "ace_routine/LogBinJsonRenderer.h" #endif diff --git a/src/ace_routine/CoroutineLogBinJsonRenderer.h b/src/ace_routine/LogBinJsonRenderer.h similarity index 84% rename from src/ace_routine/CoroutineLogBinJsonRenderer.h rename to src/ace_routine/LogBinJsonRenderer.h index 7f1996d..716ce5e 100644 --- a/src/ace_routine/CoroutineLogBinJsonRenderer.h +++ b/src/ace_routine/LogBinJsonRenderer.h @@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef ACE_ROUTINE_COROUTINE_LOG_BIN_JSON_RENDERER_H -#define ACE_ROUTINE_COROUTINE_LOG_BIN_JSON_RENDERER_H +#ifndef ACE_ROUTINE_LOG_BIN_JSON_RENDERER_H +#define ACE_ROUTINE_LOG_BIN_JSON_RENDERER_H #include // uint8_t, uint32_t #include // Print @@ -34,7 +34,7 @@ SOFTWARE. namespace ace_routine { /** - * Print the `CoroutineLogBinProfiler bins as a JSON array. For example, here + * Print the `LogBinProfiler bins as a JSON array. For example, here * is the output from `examples/SoundManager`: * * @verbatim @@ -45,13 +45,13 @@ namespace ace_routine { * @endverbatim */ template -class CoroutineLogBinJsonRendererTemplate { +class LogBinJsonRendererTemplate { public: - /** Typedef of the CoroutineLogBinProfiler supported by this class. */ - using Profiler = CoroutineLogBinProfilerTemplate; + /** Typedef of the LogBinProfiler supported by this class. */ + using Profiler = LogBinProfilerTemplate; /** Constructor. */ - CoroutineLogBinJsonRendererTemplate(T_COROUTINE** root) + LogBinJsonRendererTemplate(T_COROUTINE** root) : mRoot(root) {} @@ -61,12 +61,12 @@ class CoroutineLogBinJsonRendererTemplate { * @param printer destination of output, usually `Serial` * @param startBin start index of the bins (0-31) * @param endBin end index (exclusive) of the bins (0-32) - * @param clear call CoroutineLogBinProfiler::clear() after printing + * @param clear call LogBinProfiler::clear() after printing * (default true) * @param rollup roll-up exterior bins into the first and last bins * (default true) */ - void printJsonTo( + void printTo( Print& printer, uint8_t startBin, uint8_t endBin, @@ -118,8 +118,7 @@ class CoroutineLogBinJsonRendererTemplate { T_COROUTINE** mRoot; }; -using CoroutineLogBinJsonRenderer = - CoroutineLogBinJsonRendererTemplate; +using LogBinJsonRenderer = LogBinJsonRendererTemplate; } diff --git a/src/ace_routine/CoroutineLogBinProfiler.h b/src/ace_routine/LogBinProfiler.h similarity index 89% rename from src/ace_routine/CoroutineLogBinProfiler.h rename to src/ace_routine/LogBinProfiler.h index efe1567..e40f6ca 100644 --- a/src/ace_routine/CoroutineLogBinProfiler.h +++ b/src/ace_routine/LogBinProfiler.h @@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef ACE_ROUTINE_COROUTINE_LOG_BIN_PROFILER_H -#define ACE_ROUTINE_COROUTINE_LOG_BIN_PROFILER_H +#ifndef ACE_ROUTINE_LOG_BIN_PROFILER_H +#define ACE_ROUTINE_LOG_BIN_PROFILER_H #include // uint8_t, uint32_t #include // memset() @@ -41,20 +41,20 @@ namespace ace_routine { * * After sufficient number of samples are collected, the frequency distribution * of all profilers for all coroutines can be printed by a renderer. An - * implementation of such a render is `CoroutineLogBinRendererTemplate` + * implementation of such a render is `LogBinRendererTemplate` * which prints the frequency distribution as a formatted table. * * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, * usually `Coroutine` */ template -class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { +class LogBinProfilerTemplate : public CoroutineProfiler { public: static const uint8_t kNumBins = 32; public: /** Constructor. */ - CoroutineLogBinProfilerTemplate() { + LogBinProfilerTemplate() { clear(); } @@ -95,13 +95,13 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { // Delete any existing profiler. auto* currentProfiler = - (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + (LogBinProfilerTemplate*) (*p)->getProfiler(); if (currentProfiler) { delete currentProfiler; } // Attach new profiler. - auto* profiler = new CoroutineLogBinProfilerTemplate(); + auto* profiler = new LogBinProfilerTemplate(); (*p)->setProfiler(profiler); } } @@ -109,7 +109,7 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { /** Delete the profilers created by createProfilers(). */ static void deleteProfilers(T_COROUTINE** root) { for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { - auto* profiler = (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + auto* profiler = (LogBinProfilerTemplate*) (*p)->getProfiler(); if (profiler) { delete profiler; (*p)->setProfiler(nullptr); @@ -120,7 +120,7 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { /** Clear counters for all profilers in the coroutines defined by `root`. */ static void clearProfilers(T_COROUTINE** root) { for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { - auto* profiler = (CoroutineLogBinProfilerTemplate*) (*p)->getProfiler(); + auto* profiler = (LogBinProfilerTemplate*) (*p)->getProfiler(); if (profiler) { profiler->clear(); } @@ -131,7 +131,7 @@ class CoroutineLogBinProfilerTemplate : public CoroutineProfiler { uint16_t mBins[kNumBins]; }; -using CoroutineLogBinProfiler = CoroutineLogBinProfilerTemplate; +using LogBinProfiler = LogBinProfilerTemplate; /** * Rollup bins before `startBin` into `startBin` and bins at or after diff --git a/src/ace_routine/CoroutineLogBinRenderer.h b/src/ace_routine/LogBinTableRenderer.h similarity index 85% rename from src/ace_routine/CoroutineLogBinRenderer.h rename to src/ace_routine/LogBinTableRenderer.h index fcc19f5..9183d5b 100644 --- a/src/ace_routine/CoroutineLogBinRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -22,8 +22,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#ifndef ACE_ROUTINE_COROUTINE_LOG_BIN_RENDERER_H -#define ACE_ROUTINE_COROUTINE_LOG_BIN_RENDERER_H +#ifndef ACE_ROUTINE_LOG_BIN_TABLE_RENDERER_H +#define ACE_ROUTINE_LOG_BIN_TABLE_RENDERER_H #include // uint8_t, uint32_t #include // Print @@ -34,7 +34,7 @@ SOFTWARE. namespace ace_routine { /** - * Print the information in the CoroutineLogBinProfiler for each Coroutine + * Print the information in the LogBinProfiler for each Coroutine * in a human-readable table. Each bin is printed as a 5-digit number, since the * bins use a `uint16_t` integer for the count. The number of digits in the * printed number is equivalent to the log10() of the frequency count. To see @@ -42,7 +42,7 @@ namespace ace_routine { * character. Therefore the table is a rough ASCII version of a log-log graph of * the frequency count. * - * For example, the output of `printTableTo(Serial, 2, 10)` for + * For example, the output of `printTo(Serial, 2, 10)` for * `examples/SoundManager` looks like this: * * @verbatim @@ -59,31 +59,31 @@ namespace ace_routine { * usually `Coroutine` */ template -class CoroutineLogBinRendererTemplate { +class LogBinRendererTemplate { public: - /** Typedef of the CoroutineLogBinProfiler supported by this class. */ - using Profiler = CoroutineLogBinProfilerTemplate; + /** Typedef of the LogBinProfiler supported by this class. */ + using Profiler = LogBinProfilerTemplate; /** Constructor. */ - CoroutineLogBinRendererTemplate(T_COROUTINE** root) + LogBinRendererTemplate(T_COROUTINE** root) : mRoot(root) {} /** - * Loop over all coroutines and print the ASCII version of a histogram. This - * assumes that all the coroutines are using the same CoroutineProfiler - * class, so we can use any of the profilers to print the header, and the - * numbers will be lined up properly. + * Loop over all coroutines and print the ASCII version of the frequency + * distribution. This assumes that all the coroutines are using the same + * CoroutineProfiler class, so we can use any of the profilers to print the + * header, and the numbers will be lined up properly. * * @param printer destination of output, usually `Serial` * @param startBin start index of the bins (0-31) * @param endBin end index (exclusive) of the bins (0-32) - * @param clear call CoroutineLogBinProfiler::clear() after printing + * @param clear call LogBinProfiler::clear() after printing * (default true) * @param rollup roll-up exterior bins into the first and last bins * (default true) */ - void printTableTo( + void printTo( Print& printer, uint8_t startBin, uint8_t endBin, @@ -180,15 +180,15 @@ class CoroutineLogBinRendererTemplate { } private: - /** Labels for each bin in CoroutineLogBinProfiler::mBins. */ + /** Labels for each bin in LogBinProfiler::mBins. */ static const char* const kBinLabels[Profiler::kNumBins]; T_COROUTINE** mRoot; }; template -const char* const CoroutineLogBinRendererTemplate::kBinLabels[ - CoroutineLogBinProfilerTemplate::kNumBins] = { +const char* const LogBinRendererTemplate::kBinLabels[ + LogBinProfilerTemplate::kNumBins] = { "<2us", "<4us", "<8us", @@ -223,7 +223,7 @@ const char* const CoroutineLogBinRendererTemplate::kBinLabels[ "<4295s", }; -using CoroutineLogBinRenderer = CoroutineLogBinRendererTemplate; +using LogBinTableRenderer = LogBinRendererTemplate; } diff --git a/tests/LogBinProfilerTest/LogBinProfilerTest.ino b/tests/LogBinProfilerTest/LogBinProfilerTest.ino index c02bda0..a69120a 100644 --- a/tests/LogBinProfilerTest/LogBinProfilerTest.ino +++ b/tests/LogBinProfilerTest/LogBinProfilerTest.ino @@ -3,7 +3,7 @@ #include #include -using ace_routine::CoroutineLogBinProfiler; +using ace_routine::LogBinProfiler; using ace_routine::rollupExteriorBins; using aunit::TestRunner; @@ -12,7 +12,7 @@ using aunit::TestRunner; // --------------------------------------------------------------------------- test(updateElapsedMicros) { - CoroutineLogBinProfiler profiler; + LogBinProfiler profiler; profiler.updateElapsedMicros(0); assertEqual(profiler.mBins[0], 1); @@ -34,7 +34,7 @@ test(updateElapsedMicros) { } test(rollupExteriorBins) { - CoroutineLogBinProfiler profiler; + LogBinProfiler profiler; profiler.mBins[0] = 1; profiler.mBins[1] = 2; profiler.mBins[2] = 3; From eeefa39003a24d60b2fea33132b40833d40f84e0 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 13:55:41 -0700 Subject: [PATCH 26/59] examples/SoundManager: Use LogBinProfiler::createProfilers() --- examples/SoundManager/SoundManager.ino | 40 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index c7cd505..52e1e36 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -21,25 +21,36 @@ * Coroutine soundManager; status: Running * First BEEP * Second BEEP + * name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> + * soundManager 1440 0 1 0 0 0 0 0 1 0 + * 0x55C5AB3CE2 1438 1 2 0 0 0 0 0 0 1 + * soundRoutine 1440 0 0 0 2 0 0 0 0 0 + * { + * "soundManager":[1440,0,1,0,0,0,0,0,1,0], + * "0x55C5AB3CE240":[1438,1,2,0,0,0,0,0,0,1], + * "soundRoutine":[1440,0,0,0,2,0,0,0,0,0] + * } * * Request Boop and wait 5 seconds... * Coroutine soundRoutine; status: Yielding * Coroutine soundManager; status: Running * First BOOP * Second BOOP + * name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> + * soundManager 1440 0 1 0 0 0 0 0 1 0 + * 0x55C5AB3CE2 1438 1 2 0 0 0 0 0 0 1 + * soundRoutine 1440 0 0 0 2 0 0 0 0 0 + * { + * "soundManager":[1440,0,1,0,0,0,0,0,1,0], + * "0x55C5AB3CE240":[1438,1,2,0,0,0,0,0,0,1], + * "soundRoutine":[1440,0,0,0,2,0,0,0,0,0] + * } * * Request Silence and wait 5 seconds... * Coroutine soundRoutine; status: Yielding * Coroutine soundManager; status: Running * Wait 5 seconds... * - * - * Request Beep and wait 5 seconds... - * Coroutine soundRoutine; status: Yielding - * Coroutine soundManager; status: Running - * First BEEP - * Second BEEP - * * ... * @endverbatim */ @@ -58,7 +69,9 @@ using ace_routine::LogBinJsonRenderer; SoundRoutine soundRoutine; EXTERN_COROUTINE(soundManager); -COROUTINE(printProfile) { +// Every 5 seconds, print out the elapsed time frequency distribution from the +// LogBinProfiler. +COROUTINE(printProfiler) { COROUTINE_LOOP() { LogBinTableRenderer tableRenderer(getRoot()); tableRenderer.printTo(Serial, 2, 12, false /*clear*/); @@ -70,9 +83,6 @@ COROUTINE(printProfile) { } } -LogBinProfiler soundRoutineProfiler; -LogBinProfiler soundManagerProfiler; - void setup() { delay(1000); Serial.begin(115200); @@ -82,8 +92,12 @@ void setup() { soundRoutine.setCName("soundRoutine"); soundManager.setFName(F("soundManager")); - soundRoutine.setProfiler(&soundRoutineProfiler); - soundManager.setProfiler(&soundManagerProfiler); + // Don't set the name of 'printProfiler' to verify that the name of the + // coroutine becomes the pointer address in hexadecimal. + // printProfiler.setFName(F("printProfiler")); + + // Attach profilers to all coroutines. + LogBinProfiler::createProfilers(Coroutine::getRoot()); CoroutineScheduler::setup(); } From a80f7eedfb2ff29bc7c8684a20242d02880b1326 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 15:26:51 -0700 Subject: [PATCH 27/59] Coroutine.h: Add explicit cast to (const uint8_t*) due to missing overloaded write() in ATtiny85 Core --- src/ace_routine/Coroutine.h | 5 ++++- src/ace_routine/LogBinJsonRenderer.h | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index 02e46d9..e681853 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -375,7 +375,10 @@ class CoroutineTemplate { printer.write(' '); } } else { - printer.write(pname.cstr(), maxLen); + // NOTE: Must cast to (const uint8_t*) because the ATtiny85 core does + // not have a version of write() that accepts a (const char*), in + // contrast to every other Arduino Core. + printer.write((const uint8_t*) pname.cstr(), maxLen); } } else { printer.write(pname.cstr()); diff --git a/src/ace_routine/LogBinJsonRenderer.h b/src/ace_routine/LogBinJsonRenderer.h index 716ce5e..0d31356 100644 --- a/src/ace_routine/LogBinJsonRenderer.h +++ b/src/ace_routine/LogBinJsonRenderer.h @@ -27,7 +27,6 @@ SOFTWARE. #include // uint8_t, uint32_t #include // Print -#include // printfTo() #include "Coroutine.h" // Coroutine #include "CoroutineProfiler.h" From 6ce3a1dd054a9c146573382d108ba49dc22d9a82 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 15:31:30 -0700 Subject: [PATCH 28/59] MemoryBenchmark: Add LogBinProfiler, LogBinTableRenderer, LogBinJsonRenderer --- examples/MemoryBenchmark/MemoryBenchmark.ino | 40 +++++++++- examples/MemoryBenchmark/README.md | 75 ++++++++++++++----- examples/MemoryBenchmark/attiny.txt | 7 +- examples/MemoryBenchmark/collect.sh | 2 +- examples/MemoryBenchmark/esp32.txt | 43 ++++++----- examples/MemoryBenchmark/esp8266.txt | 7 +- examples/MemoryBenchmark/generate_table.awk | 8 +- examples/MemoryBenchmark/micro.txt | 7 +- examples/MemoryBenchmark/nano.txt | 7 +- examples/MemoryBenchmark/stm32.txt | 7 +- examples/MemoryBenchmark/teensy32.txt | 7 +- .../validate_using_epoxy_duino.sh | 2 +- 12 files changed, 154 insertions(+), 58 deletions(-) diff --git a/examples/MemoryBenchmark/MemoryBenchmark.ino b/examples/MemoryBenchmark/MemoryBenchmark.ino index 404f988..1ac57e9 100644 --- a/examples/MemoryBenchmark/MemoryBenchmark.ino +++ b/examples/MemoryBenchmark/MemoryBenchmark.ino @@ -34,8 +34,11 @@ #define FEATURE_SCHEDULER_SETUP_TWO_COROUTINES 16 #define FEATURE_SCHEDULER_MANUAL_SETUP_ONE_COROUTINE 17 #define FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES 18 -#define FEATURE_BLINK_FUNCTION 19 -#define FEATURE_BLINK_COROUTINE 20 +#define FEATURE_LOG_BIN_PROFILER 19 +#define FEATURE_LOG_BIN_TABLE_RENDERER 20 +#define FEATURE_LOG_BIN_JSON_RENDERER 21 +#define FEATURE_BLINK_FUNCTION 22 +#define FEATURE_BLINK_COROUTINE 23 #if FEATURE != FEATURE_BASELINE #include @@ -413,6 +416,17 @@ volatile int disableCompilerOptimization = 0; } } +#elif FEATURE == FEATURE_LOG_BIN_PROFILER \ + || FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER \ + || FEATURE == FEATURE_LOG_BIN_JSON_RENDERER + + COROUTINE(profiled) { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + #elif FEATURE == FEATURE_BLINK_COROUTINE #ifndef LED_BUILTIN @@ -449,6 +463,12 @@ volatile int disableCompilerOptimization = 0; FooClass* foo; #endif +#if FEATURE == FEATURE_LOG_BIN_PROFILER \ + || FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER \ + || FEATURE == FEATURE_LOG_BIN_JSON_RENDERER + LogBinProfiler profiler; +#endif + void setup() { delay(1000); @@ -473,6 +493,12 @@ void setup() { #endif #endif + +#if FEATURE == FEATURE_LOG_BIN_PROFILER \ + || FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER \ + || FEATURE == FEATURE_LOG_BIN_JSON_RENDERER + profiled.setProfiler(&profiler); +#endif } void loop() { @@ -522,6 +548,16 @@ void loop() { CoroutineScheduler::loop(); #elif FEATURE == FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES CoroutineScheduler::loop(); +#elif FEATURE == FEATURE_LOG_BIN_PROFILER + CoroutineScheduler::loop(); +#elif FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER + CoroutineScheduler::loop(); + LogBinTableRenderer renderer(Coroutine::getRoot()); + renderer.printTo(Serial, 0, 32); +#elif FEATURE == FEATURE_LOG_BIN_JSON_RENDERER + CoroutineScheduler::loop(); + LogBinJsonRenderer renderer(Coroutine::getRoot()); + renderer.printTo(Serial, 0, 32); #elif FEATURE == FEATURE_BLINK_COROUTINE blink.runCoroutine(); #elif FEATURE == FEATURE_BLINK_FUNCTION diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index fd2c782..65f70ca 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -112,6 +112,13 @@ calculated flash size can jump around in unexpected ways. * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. + * Add `LogBinProfiler` + * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. + * Add `LogBinTableRenderer` + * Adds about 3500 bytes of flash (probably due to `vsnprintf()`) and 450 + bytes of RAM on AVR. + * Add `LogBinJsonRenderer` + * Adds about 1800 bytes of flash and 200 bytes of RAM. ## How to Generate @@ -207,6 +214,10 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 896/ 39 | 496/ 28 | | Scheduler, Two Coroutines (man setup) | 1186/ 63 | 786/ 52 | |---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 954/ 111 | 554/ 100 | +| Scheduler, LogBinTableRenderer | 4092/ 467 | 3692/ 456 | +| Scheduler, LogBinJsonRenderer | 2356/ 197 | 1956/ 186 | +|---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | | Blink Coroutine | 766/ 37 | 366/ 26 | +--------------------------------------------------------------------+ @@ -252,6 +263,10 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 1106/ 39 | 500/ 28 | | Scheduler, Two Coroutines (man setup) | 1400/ 63 | 794/ 52 | |---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 1166/ 111 | 560/ 100 | +| Scheduler, LogBinTableRenderer | 4702/ 578 | 4096/ 567 | +| Scheduler, LogBinJsonRenderer | 2924/ 308 | 2318/ 297 | +|---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | | Blink Coroutine | 1168/ 37 | 562/ 26 | +--------------------------------------------------------------------+ @@ -297,6 +312,10 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 3994/ 179 | 440/ 28 | | Scheduler, Two Coroutines (man setup) | 4288/ 203 | 734/ 52 | |---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 4054/ 251 | 500/ 100 | +| Scheduler, LogBinTableRenderer | 6760/ 543 | 3206/ 392 | +| Scheduler, LogBinJsonRenderer | 4980/ 273 | 1426/ 122 | +|---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | | Blink Coroutine | 4164/ 177 | 610/ 26 | +--------------------------------------------------------------------+ @@ -342,6 +361,10 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 22224/ 3576 | 340/ 36 | | Scheduler, Two Coroutines (man setup) | 22360/ 3604 | 476/ 64 | |---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 22284/ 3644 | 400/ 104 | +| Scheduler, LogBinTableRenderer | 25164/ 3644 | 3280/ 104 | +| Scheduler, LogBinJsonRenderer | 22956/ 3644 | 1072/ 104 | +|---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | | Blink Coroutine | 22232/ 3568 | 348/ 28 | +--------------------------------------------------------------------+ @@ -387,6 +410,10 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 260685/27952 | 356/ 36 | | Scheduler, Two Coroutines (man setup) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 260765/28024 | 436/ 108 | +| Scheduler, LogBinTableRenderer | 265057/28440 | 4728/ 524 | +| Scheduler, LogBinJsonRenderer | 264785/28104 | 4456/ 188 | +|---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | | Blink Coroutine | 261149/28016 | 820/ 100 | +--------------------------------------------------------------------+ @@ -405,35 +432,39 @@ $ make README.md |---------------------------------------+--------------+-------------| | Baseline | 204573/16060 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 205129/16092 | 556/ 32 | -| Two Delay Functions | 205201/16092 | 628/ 32 | +| One Delay Function | 204985/16084 | 412/ 24 | +| Two Delay Functions | 205057/16084 | 484/ 24 | +|---------------------------------------+--------------+-------------| +| One Coroutine | 205097/16116 | 524/ 56 | +| Two Coroutines | 205269/16140 | 696/ 80 | |---------------------------------------+--------------+-------------| -| One Coroutine | 205241/16124 | 668/ 64 | -| Two Coroutines | 205413/16148 | 840/ 88 | +| One Coroutine (micros) | 205085/16116 | 512/ 56 | +| Two Coroutines (micros) | 205257/16140 | 684/ 80 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 205229/16124 | 656/ 64 | -| Two Coroutines (micros) | 205401/16148 | 828/ 88 | +| One Coroutine (seconds) | 205113/16116 | 540/ 56 | +| Two Coroutines (seconds) | 205301/16140 | 728/ 80 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 205257/16124 | 684/ 64 | -| Two Coroutines (seconds) | 205445/16148 | 872/ 88 | +| Scheduler, One Coroutine | 205253/16116 | 680/ 56 | +| Scheduler, Two Coroutines | 205393/16148 | 820/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 205397/16124 | 824/ 64 | -| Scheduler, Two Coroutines | 205537/16156 | 964/ 96 | +| Scheduler, One Coroutine (micros) | 205229/16116 | 656/ 56 | +| Scheduler, Two Coroutines (micros) | 205369/16148 | 796/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 205373/16124 | 800/ 64 | -| Scheduler, Two Coroutines (micros) | 205513/16156 | 940/ 96 | +| Scheduler, One Coroutine (seconds) | 205269/16116 | 696/ 56 | +| Scheduler, Two Coroutines (seconds) | 205425/16148 | 852/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 205413/16124 | 840/ 64 | -| Scheduler, Two Coroutines (seconds) | 205569/16156 | 996/ 96 | +| Scheduler, One Coroutine (setup) | 205281/16116 | 708/ 56 | +| Scheduler, Two Coroutines (setup) | 205453/16148 | 880/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 205425/16124 | 852/ 64 | -| Scheduler, Two Coroutines (setup) | 205597/16156 | 1024/ 96 | +| Scheduler, One Coroutine (man setup) | 205273/16116 | 700/ 56 | +| Scheduler, Two Coroutines (man setup) | 205453/16148 | 880/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 205417/16124 | 844/ 64 | -| Scheduler, Two Coroutines (man setup) | 205597/16156 | 1024/ 96 | +| Scheduler, LogBinProfiler | 205333/16188 | 760/ 128 | +| Scheduler, LogBinTableRenderer | 210913/16268 | 6340/ 208 | +| Scheduler, LogBinJsonRenderer | 210477/16268 | 5904/ 208 | |---------------------------------------+--------------+-------------| -| Blink Function | 205481/16100 | 908/ 40 | -| Blink Coroutine | 205593/16124 | 1020/ 64 | +| Blink Function | 205337/16092 | 764/ 32 | +| Blink Coroutine | 205449/16116 | 876/ 56 | +--------------------------------------------------------------------+ ``` @@ -478,6 +509,10 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 10588/ 4188 | 356/ 36 | | Scheduler, Two Coroutines (man setup) | 10736/ 4216 | 504/ 64 | |---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 10852/ 4256 | 620/ 104 | +| Scheduler, LogBinTableRenderer | 31108/ 4640 | 20876/ 488 | +| Scheduler, LogBinJsonRenderer | 13140/ 4276 | 2908/ 124 | +|---------------------------------------+--------------+-------------| | Blink Function | 10688/ 4160 | 456/ 8 | | Blink Coroutine | 10820/ 4184 | 588/ 32 | +--------------------------------------------------------------------+ diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index 970946b..e307ca5 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -17,5 +17,8 @@ 16 1202 8192 63 512 17 896 8192 39 512 18 1186 8192 63 512 -19 546 8192 14 512 -20 766 8192 37 512 +19 954 8192 111 512 +20 4092 8192 467 512 +21 2356 8192 197 512 +22 546 8192 14 512 +23 766 8192 37 512 diff --git a/examples/MemoryBenchmark/collect.sh b/examples/MemoryBenchmark/collect.sh index 5b57758..9e84de6 100755 --- a/examples/MemoryBenchmark/collect.sh +++ b/examples/MemoryBenchmark/collect.sh @@ -16,7 +16,7 @@ set -eu PROGRAM_NAME='MemoryBenchmark.ino' -NUM_FEATURES=20 # excluding FEATURE_BASELINE +NUM_FEATURES=23 # excluding FEATURE_BASELINE # Assume that https://github.com/bxparks/AUniter is installed as a # sibling project to AceRoutine. diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 9efefbc..a9a15bc 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -1,21 +1,24 @@ 0 204573 1310720 16060 327680 -1 205129 1310720 16092 327680 -2 205201 1310720 16092 327680 -3 205241 1310720 16124 327680 -4 205413 1310720 16148 327680 -5 205229 1310720 16124 327680 -6 205401 1310720 16148 327680 -7 205257 1310720 16124 327680 -8 205445 1310720 16148 327680 -9 205397 1310720 16124 327680 -10 205537 1310720 16156 327680 -11 205373 1310720 16124 327680 -12 205513 1310720 16156 327680 -13 205413 1310720 16124 327680 -14 205569 1310720 16156 327680 -15 205425 1310720 16124 327680 -16 205597 1310720 16156 327680 -17 205417 1310720 16124 327680 -18 205597 1310720 16156 327680 -19 205481 1310720 16100 327680 -20 205593 1310720 16124 327680 +1 204985 1310720 16084 327680 +2 205057 1310720 16084 327680 +3 205097 1310720 16116 327680 +4 205269 1310720 16140 327680 +5 205085 1310720 16116 327680 +6 205257 1310720 16140 327680 +7 205113 1310720 16116 327680 +8 205301 1310720 16140 327680 +9 205253 1310720 16116 327680 +10 205393 1310720 16148 327680 +11 205229 1310720 16116 327680 +12 205369 1310720 16148 327680 +13 205269 1310720 16116 327680 +14 205425 1310720 16148 327680 +15 205281 1310720 16116 327680 +16 205453 1310720 16148 327680 +17 205273 1310720 16116 327680 +18 205453 1310720 16148 327680 +19 205333 1310720 16188 327680 +20 210913 1310720 16268 327680 +21 210477 1310720 16268 327680 +22 205337 1310720 16092 327680 +23 205449 1310720 16116 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 5add629..cc6530c 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -17,5 +17,8 @@ 16 260877 1044464 27984 81920 17 260685 1044464 27952 81920 18 260861 1044464 27984 81920 -19 261001 1044464 27988 81920 -20 261149 1044464 28016 81920 +19 260765 1044464 28024 81920 +20 265057 1044464 28440 81920 +21 264785 1044464 28104 81920 +22 261001 1044464 27988 81920 +23 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/generate_table.awk b/examples/MemoryBenchmark/generate_table.awk index 18cadbd..59c439f 100755 --- a/examples/MemoryBenchmark/generate_table.awk +++ b/examples/MemoryBenchmark/generate_table.awk @@ -25,8 +25,11 @@ BEGIN { labels[16] = "Scheduler, Two Coroutines (setup)" labels[17] = "Scheduler, One Coroutine (man setup)" labels[18] = "Scheduler, Two Coroutines (man setup)" - labels[19] = "Blink Function" - labels[20] = "Blink Coroutine" + labels[19] = "Scheduler, LogBinProfiler" + labels[20] = "Scheduler, LogBinTableRenderer" + labels[21] = "Scheduler, LogBinJsonRenderer" + labels[22] = "Blink Function" + labels[23] = "Blink Coroutine" record_index = 0 } { @@ -57,6 +60,7 @@ END { || labels[i] ~ /^Scheduler, One Coroutine \(seconds\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(setup\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(man setup\)$/ \ + || labels[i] ~ /^Scheduler, LogBinProfiler$/ \ || labels[i] ~ /^Blink Function$/ \ ) { printf("|---------------------------------------+--------------+-------------|\n") diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index e99f5b5..17cdec5 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -17,5 +17,8 @@ 16 4302 28672 203 2560 17 3994 28672 179 2560 18 4288 28672 203 2560 -19 3994 28672 154 2560 -20 4164 28672 177 2560 +19 4054 28672 251 2560 +20 6760 28672 543 2560 +21 4980 28672 273 2560 +22 3994 28672 154 2560 +23 4164 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 209e4a1..3801c53 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -17,5 +17,8 @@ 16 1414 30720 63 2048 17 1106 30720 39 2048 18 1400 30720 63 2048 -19 938 30720 14 2048 -20 1168 30720 37 2048 +19 1166 30720 111 2048 +20 4702 30720 578 2048 +21 2924 30720 308 2048 +22 938 30720 14 2048 +23 1168 30720 37 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index 2fdf69c..1a5d623 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -17,5 +17,8 @@ 16 22364 131072 3604 20480 17 22224 131072 3576 20480 18 22360 131072 3604 20480 -19 22120 131072 3540 20480 -20 22232 131072 3568 20480 +19 22284 131072 3644 20480 +20 25164 131072 3644 20480 +21 22956 131072 3644 20480 +22 22120 131072 3540 20480 +23 22232 131072 3568 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 8b02774..325aa29 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -17,5 +17,8 @@ 16 10748 262144 4216 65536 17 10588 262144 4188 65536 18 10736 262144 4216 65536 -19 10688 262144 4160 65536 -20 10820 262144 4184 65536 +19 10852 262144 4256 65536 +20 31108 262144 4640 65536 +21 13140 262144 4276 65536 +22 10688 262144 4160 65536 +23 10820 262144 4184 65536 diff --git a/examples/MemoryBenchmark/validate_using_epoxy_duino.sh b/examples/MemoryBenchmark/validate_using_epoxy_duino.sh index 34b8899..1841ffd 100755 --- a/examples/MemoryBenchmark/validate_using_epoxy_duino.sh +++ b/examples/MemoryBenchmark/validate_using_epoxy_duino.sh @@ -8,7 +8,7 @@ set -eu PROGRAM_NAME='MemoryBenchmark.ino' -NUM_FEATURES=20 # excluding FEATURE_BASELINE +NUM_FEATURES=23 # excluding FEATURE_BASELINE temp_out_file= function cleanup() { From 826378e44703196a419998e8a3f133305c48422d Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 15:54:18 -0700 Subject: [PATCH 29/59] LogBinTableRenderer.h: Replace vsnprintf() with ace_common::printPad5To(); reduces flash size ~0 byte (ESP32), ~400 bytes (ESP8266), ~1200 bytes (AVR), ~17kB! (Teensy 3.2) --- examples/MemoryBenchmark/README.md | 20 ++++++++++---------- examples/MemoryBenchmark/attiny.txt | 2 +- examples/MemoryBenchmark/esp32.txt | 2 +- examples/MemoryBenchmark/esp8266.txt | 2 +- examples/MemoryBenchmark/generate_readme.py | 7 +++++++ examples/MemoryBenchmark/micro.txt | 2 +- examples/MemoryBenchmark/nano.txt | 2 +- examples/MemoryBenchmark/stm32.txt | 2 +- examples/MemoryBenchmark/teensy32.txt | 2 +- src/ace_routine/LogBinTableRenderer.h | 15 ++++++++++----- 10 files changed, 34 insertions(+), 22 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 65f70ca..ce44f95 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -115,10 +115,10 @@ calculated flash size can jump around in unexpected ways. * Add `LogBinProfiler` * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. * Add `LogBinTableRenderer` - * Adds about 3500 bytes of flash (probably due to `vsnprintf()`) and 450 - bytes of RAM on AVR. + * Adds about 2200 bytes of flash and 450 bytes of RAM on AVR. * Add `LogBinJsonRenderer` - * Adds about 1800 bytes of flash and 200 bytes of RAM. + * Adds about 1800 bytes of flash and 200 bytes of RAM on AVR. + ## How to Generate @@ -215,7 +215,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 1186/ 63 | 786/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 954/ 111 | 554/ 100 | -| Scheduler, LogBinTableRenderer | 4092/ 467 | 3692/ 456 | +| Scheduler, LogBinTableRenderer | 2776/ 439 | 2376/ 428 | | Scheduler, LogBinJsonRenderer | 2356/ 197 | 1956/ 186 | |---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | @@ -264,7 +264,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 1400/ 63 | 794/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 1166/ 111 | 560/ 100 | -| Scheduler, LogBinTableRenderer | 4702/ 578 | 4096/ 567 | +| Scheduler, LogBinTableRenderer | 3348/ 552 | 2742/ 541 | | Scheduler, LogBinJsonRenderer | 2924/ 308 | 2318/ 297 | |---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | @@ -313,7 +313,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 4288/ 203 | 734/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 4054/ 251 | 500/ 100 | -| Scheduler, LogBinTableRenderer | 6760/ 543 | 3206/ 392 | +| Scheduler, LogBinTableRenderer | 5404/ 515 | 1850/ 364 | | Scheduler, LogBinJsonRenderer | 4980/ 273 | 1426/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | @@ -362,7 +362,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 22360/ 3604 | 476/ 64 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 22284/ 3644 | 400/ 104 | -| Scheduler, LogBinTableRenderer | 25164/ 3644 | 3280/ 104 | +| Scheduler, LogBinTableRenderer | 23636/ 3644 | 1752/ 104 | | Scheduler, LogBinJsonRenderer | 22956/ 3644 | 1072/ 104 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | @@ -411,7 +411,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 260765/28024 | 436/ 108 | -| Scheduler, LogBinTableRenderer | 265057/28440 | 4728/ 524 | +| Scheduler, LogBinTableRenderer | 265465/28420 | 5136/ 504 | | Scheduler, LogBinJsonRenderer | 264785/28104 | 4456/ 188 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | @@ -460,7 +460,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 205453/16148 | 880/ 88 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 205333/16188 | 760/ 128 | -| Scheduler, LogBinTableRenderer | 210913/16268 | 6340/ 208 | +| Scheduler, LogBinTableRenderer | 210941/16268 | 6368/ 208 | | Scheduler, LogBinJsonRenderer | 210477/16268 | 5904/ 208 | |---------------------------------------+--------------+-------------| | Blink Function | 205337/16092 | 764/ 32 | @@ -510,7 +510,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 10736/ 4216 | 504/ 64 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 10852/ 4256 | 620/ 104 | -| Scheduler, LogBinTableRenderer | 31108/ 4640 | 20876/ 488 | +| Scheduler, LogBinTableRenderer | 13720/ 4276 | 3488/ 124 | | Scheduler, LogBinJsonRenderer | 13140/ 4276 | 2908/ 124 | |---------------------------------------+--------------+-------------| | Blink Function | 10688/ 4160 | 456/ 8 | diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index e307ca5..f7e8e1d 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -18,7 +18,7 @@ 17 896 8192 39 512 18 1186 8192 63 512 19 954 8192 111 512 -20 4092 8192 467 512 +20 2776 8192 439 512 21 2356 8192 197 512 22 546 8192 14 512 23 766 8192 37 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index a9a15bc..b5a4203 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -18,7 +18,7 @@ 17 205273 1310720 16116 327680 18 205453 1310720 16148 327680 19 205333 1310720 16188 327680 -20 210913 1310720 16268 327680 +20 210941 1310720 16268 327680 21 210477 1310720 16268 327680 22 205337 1310720 16092 327680 23 205449 1310720 16116 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index cc6530c..22fd3f2 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -18,7 +18,7 @@ 17 260685 1044464 27952 81920 18 260861 1044464 27984 81920 19 260765 1044464 28024 81920 -20 265057 1044464 28440 81920 +20 265465 1044464 28420 81920 21 264785 1044464 28104 81920 22 261001 1044464 27988 81920 23 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index f4176fd..8dd752f 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -136,6 +136,13 @@ * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. + * Add `LogBinProfiler` + * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. + * Add `LogBinTableRenderer` + * Adds about 2200 bytes of flash and 450 bytes of RAM on AVR. + * Add `LogBinJsonRenderer` + * Adds about 1800 bytes of flash and 200 bytes of RAM on AVR. + ## How to Generate diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index 17cdec5..141dd28 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -18,7 +18,7 @@ 17 3994 28672 179 2560 18 4288 28672 203 2560 19 4054 28672 251 2560 -20 6760 28672 543 2560 +20 5404 28672 515 2560 21 4980 28672 273 2560 22 3994 28672 154 2560 23 4164 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 3801c53..e42236c 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -18,7 +18,7 @@ 17 1106 30720 39 2048 18 1400 30720 63 2048 19 1166 30720 111 2048 -20 4702 30720 578 2048 +20 3348 30720 552 2048 21 2924 30720 308 2048 22 938 30720 14 2048 23 1168 30720 37 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index 1a5d623..a22c6b1 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -18,7 +18,7 @@ 17 22224 131072 3576 20480 18 22360 131072 3604 20480 19 22284 131072 3644 20480 -20 25164 131072 3644 20480 +20 23636 131072 3644 20480 21 22956 131072 3644 20480 22 22120 131072 3540 20480 23 22232 131072 3568 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 325aa29..94cbfe7 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -18,7 +18,7 @@ 17 10588 262144 4188 65536 18 10736 262144 4216 65536 19 10852 262144 4256 65536 -20 31108 262144 4640 65536 +20 13720 262144 4276 65536 21 13140 262144 4276 65536 22 10688 262144 4160 65536 23 10820 262144 4184 65536 diff --git a/src/ace_routine/LogBinTableRenderer.h b/src/ace_routine/LogBinTableRenderer.h index 9183d5b..9b9d223 100644 --- a/src/ace_routine/LogBinTableRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -27,7 +27,7 @@ SOFTWARE. #include // uint8_t, uint32_t #include // Print -#include // printfTo() +#include // printPad5To() #include "Coroutine.h" // Coroutine #include "CoroutineProfiler.h" @@ -101,7 +101,7 @@ class LogBinRendererTemplate { // Print header if needed. if (! isHeaderPrinted) { - ace_common::printfTo(printer, "%-12.12s", "name"); + printer.print(F("name ")); printHeaderTo(printer, startBin, endBin); printer.println(); isHeaderPrinted = true; @@ -149,9 +149,13 @@ class LogBinRendererTemplate { if (endBin <= startBin) return; // needed if startBin = endBin = 0 for (uint8_t i = startBin; i < endBin - 1; i++) { - ace_common::printfTo(printer, "%6.6s", kBinLabels[i]); + uint8_t labelLength = strlen(kBinLabels[i]); + for (uint8_t i = 0; i < (6 - labelLength); i++) { + printer.print(' '); + } + printer.print(kBinLabels[i]); } - ace_common::printfTo(printer, "%6.6s", ">>"); + printer.print(F(" >>")); } /** @@ -175,7 +179,8 @@ class LogBinRendererTemplate { endBin = (endBin > numBins) ? numBins : endBin; for (uint8_t i = startBin; i < endBin; i++) { uint16_t count = bins[i]; - ace_common::printfTo(printer, "%6u", count); + printer.print(' '); + ace_common::printPad5To(printer, count); } } From 6cffcac98c9b0080736d564a5b83b0136e590a97 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 16:49:06 -0700 Subject: [PATCH 30/59] LogBinTableRenderer.cpp: Move column labels into PROGMEM, saving ~250 bytes of RAM on AVR, ~350 bytes of RAM on ESP8266 --- examples/MemoryBenchmark/README.md | 66 ++++++------- examples/MemoryBenchmark/attiny.txt | 2 +- examples/MemoryBenchmark/esp32.txt | 46 ++++----- examples/MemoryBenchmark/esp8266.txt | 2 +- examples/MemoryBenchmark/generate_readme.py | 12 +-- examples/MemoryBenchmark/micro.txt | 2 +- examples/MemoryBenchmark/nano.txt | 2 +- src/ace_routine/LogBinTableRenderer.cpp | 102 ++++++++++++++++++++ src/ace_routine/LogBinTableRenderer.h | 59 +++-------- 9 files changed, 184 insertions(+), 109 deletions(-) create mode 100644 src/ace_routine/LogBinTableRenderer.cpp diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index ce44f95..79d6132 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -115,7 +115,7 @@ calculated flash size can jump around in unexpected ways. * Add `LogBinProfiler` * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. * Add `LogBinTableRenderer` - * Adds about 2200 bytes of flash and 450 bytes of RAM on AVR. + * Adds about 2200 bytes of flash and 200 bytes of RAM on AVR. * Add `LogBinJsonRenderer` * Adds about 1800 bytes of flash and 200 bytes of RAM on AVR. @@ -215,7 +215,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 1186/ 63 | 786/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 954/ 111 | 554/ 100 | -| Scheduler, LogBinTableRenderer | 2776/ 439 | 2376/ 428 | +| Scheduler, LogBinTableRenderer | 2798/ 193 | 2398/ 182 | | Scheduler, LogBinJsonRenderer | 2356/ 197 | 1956/ 186 | |---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | @@ -228,7 +228,7 @@ $ make README.md * 16MHz ATmega328P * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* Arduino AVR Boards 1.8.3 +* Arduino AVR Boards 1.8.4 ``` +--------------------------------------------------------------------+ @@ -264,7 +264,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 1400/ 63 | 794/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 1166/ 111 | 560/ 100 | -| Scheduler, LogBinTableRenderer | 3348/ 552 | 2742/ 541 | +| Scheduler, LogBinTableRenderer | 3364/ 304 | 2758/ 293 | | Scheduler, LogBinJsonRenderer | 2924/ 308 | 2318/ 297 | |---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | @@ -313,7 +313,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 4288/ 203 | 734/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 4054/ 251 | 500/ 100 | -| Scheduler, LogBinTableRenderer | 5404/ 515 | 1850/ 364 | +| Scheduler, LogBinTableRenderer | 5422/ 269 | 1868/ 118 | | Scheduler, LogBinJsonRenderer | 4980/ 273 | 1426/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | @@ -326,7 +326,7 @@ $ make README.md * STM32F103C8, 72 MHz ARM Cortex-M3 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* STM32duino 2.0.0 +* STM32duino 2.2.0 ``` +--------------------------------------------------------------------+ @@ -375,7 +375,7 @@ $ make README.md * NodeMCU 1.0 clone, 80MHz ESP8266 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* ESP8266 Boards 2.7.4 +* ESP8266 Boards 3.0.2 ``` +--------------------------------------------------------------------+ @@ -411,7 +411,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 260765/28024 | 436/ 108 | -| Scheduler, LogBinTableRenderer | 265465/28420 | 5136/ 504 | +| Scheduler, LogBinTableRenderer | 265217/28100 | 4888/ 184 | | Scheduler, LogBinJsonRenderer | 264785/28104 | 4456/ 188 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | @@ -424,7 +424,7 @@ $ make README.md * ESP32-01 Dev Board, 240 MHz Tensilica LX6 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* ESP32 Boards 1.0.6 +* ESP32 Boards 2.0.2 ``` +--------------------------------------------------------------------+ @@ -432,39 +432,39 @@ $ make README.md |---------------------------------------+--------------+-------------| | Baseline | 204573/16060 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 204985/16084 | 412/ 24 | -| Two Delay Functions | 205057/16084 | 484/ 24 | +| One Delay Function | 205017/16092 | 444/ 32 | +| Two Delay Functions | 205089/16092 | 516/ 32 | |---------------------------------------+--------------+-------------| -| One Coroutine | 205097/16116 | 524/ 56 | -| Two Coroutines | 205269/16140 | 696/ 80 | +| One Coroutine | 205129/16124 | 556/ 64 | +| Two Coroutines | 205301/16148 | 728/ 88 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 205085/16116 | 512/ 56 | -| Two Coroutines (micros) | 205257/16140 | 684/ 80 | +| One Coroutine (micros) | 205117/16124 | 544/ 64 | +| Two Coroutines (micros) | 205289/16148 | 716/ 88 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 205113/16116 | 540/ 56 | -| Two Coroutines (seconds) | 205301/16140 | 728/ 80 | +| One Coroutine (seconds) | 205145/16124 | 572/ 64 | +| Two Coroutines (seconds) | 205333/16148 | 760/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 205253/16116 | 680/ 56 | -| Scheduler, Two Coroutines | 205393/16148 | 820/ 88 | +| Scheduler, One Coroutine | 205285/16124 | 712/ 64 | +| Scheduler, Two Coroutines | 205425/16156 | 852/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 205229/16116 | 656/ 56 | -| Scheduler, Two Coroutines (micros) | 205369/16148 | 796/ 88 | +| Scheduler, One Coroutine (micros) | 205261/16124 | 688/ 64 | +| Scheduler, Two Coroutines (micros) | 205401/16156 | 828/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 205269/16116 | 696/ 56 | -| Scheduler, Two Coroutines (seconds) | 205425/16148 | 852/ 88 | +| Scheduler, One Coroutine (seconds) | 205301/16124 | 728/ 64 | +| Scheduler, Two Coroutines (seconds) | 205457/16156 | 884/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 205281/16116 | 708/ 56 | -| Scheduler, Two Coroutines (setup) | 205453/16148 | 880/ 88 | +| Scheduler, One Coroutine (setup) | 205313/16124 | 740/ 64 | +| Scheduler, Two Coroutines (setup) | 205485/16156 | 912/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 205273/16116 | 700/ 56 | -| Scheduler, Two Coroutines (man setup) | 205453/16148 | 880/ 88 | +| Scheduler, One Coroutine (man setup) | 205305/16124 | 732/ 64 | +| Scheduler, Two Coroutines (man setup) | 205485/16156 | 912/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 205333/16188 | 760/ 128 | -| Scheduler, LogBinTableRenderer | 210941/16268 | 6368/ 208 | -| Scheduler, LogBinJsonRenderer | 210477/16268 | 5904/ 208 | +| Scheduler, LogBinProfiler | 205365/16196 | 792/ 136 | +| Scheduler, LogBinTableRenderer | 210973/16276 | 6400/ 216 | +| Scheduler, LogBinJsonRenderer | 210509/16276 | 5936/ 216 | |---------------------------------------+--------------+-------------| -| Blink Function | 205337/16092 | 764/ 32 | -| Blink Coroutine | 205449/16116 | 876/ 56 | +| Blink Function | 205369/16100 | 796/ 40 | +| Blink Coroutine | 205481/16124 | 908/ 64 | +--------------------------------------------------------------------+ ``` @@ -473,7 +473,7 @@ $ make README.md * 96 MHz ARM Cortex-M4 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* Teensyduino 1.53 +* Teensyduino 1.56 * Compiler options: "Faster" ``` diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index f7e8e1d..299b455 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -18,7 +18,7 @@ 17 896 8192 39 512 18 1186 8192 63 512 19 954 8192 111 512 -20 2776 8192 439 512 +20 2798 8192 193 512 21 2356 8192 197 512 22 546 8192 14 512 23 766 8192 37 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index b5a4203..0460485 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -1,24 +1,24 @@ 0 204573 1310720 16060 327680 -1 204985 1310720 16084 327680 -2 205057 1310720 16084 327680 -3 205097 1310720 16116 327680 -4 205269 1310720 16140 327680 -5 205085 1310720 16116 327680 -6 205257 1310720 16140 327680 -7 205113 1310720 16116 327680 -8 205301 1310720 16140 327680 -9 205253 1310720 16116 327680 -10 205393 1310720 16148 327680 -11 205229 1310720 16116 327680 -12 205369 1310720 16148 327680 -13 205269 1310720 16116 327680 -14 205425 1310720 16148 327680 -15 205281 1310720 16116 327680 -16 205453 1310720 16148 327680 -17 205273 1310720 16116 327680 -18 205453 1310720 16148 327680 -19 205333 1310720 16188 327680 -20 210941 1310720 16268 327680 -21 210477 1310720 16268 327680 -22 205337 1310720 16092 327680 -23 205449 1310720 16116 327680 +1 205017 1310720 16092 327680 +2 205089 1310720 16092 327680 +3 205129 1310720 16124 327680 +4 205301 1310720 16148 327680 +5 205117 1310720 16124 327680 +6 205289 1310720 16148 327680 +7 205145 1310720 16124 327680 +8 205333 1310720 16148 327680 +9 205285 1310720 16124 327680 +10 205425 1310720 16156 327680 +11 205261 1310720 16124 327680 +12 205401 1310720 16156 327680 +13 205301 1310720 16124 327680 +14 205457 1310720 16156 327680 +15 205313 1310720 16124 327680 +16 205485 1310720 16156 327680 +17 205305 1310720 16124 327680 +18 205485 1310720 16156 327680 +19 205365 1310720 16196 327680 +20 210973 1310720 16276 327680 +21 210509 1310720 16276 327680 +22 205369 1310720 16100 327680 +23 205481 1310720 16124 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 22fd3f2..b779234 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -18,7 +18,7 @@ 17 260685 1044464 27952 81920 18 260861 1044464 27984 81920 19 260765 1044464 28024 81920 -20 265465 1044464 28420 81920 +20 265217 1044464 28100 81920 21 264785 1044464 28104 81920 22 261001 1044464 27988 81920 23 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index 8dd752f..7d79a77 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -139,7 +139,7 @@ * Add `LogBinProfiler` * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. * Add `LogBinTableRenderer` - * Adds about 2200 bytes of flash and 450 bytes of RAM on AVR. + * Adds about 2200 bytes of flash and 200 bytes of RAM on AVR. * Add `LogBinJsonRenderer` * Adds about 1800 bytes of flash and 200 bytes of RAM on AVR. @@ -213,7 +213,7 @@ * 16MHz ATmega328P * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* Arduino AVR Boards 1.8.3 +* Arduino AVR Boards 1.8.4 ``` {nano_results} @@ -233,7 +233,7 @@ * STM32F103C8, 72 MHz ARM Cortex-M3 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* STM32duino 2.0.0 +* STM32duino 2.2.0 ``` {stm32_results} @@ -243,7 +243,7 @@ * NodeMCU 1.0 clone, 80MHz ESP8266 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* ESP8266 Boards 2.7.4 +* ESP8266 Boards 3.0.2 ``` {esp8266_results} @@ -253,7 +253,7 @@ * ESP32-01 Dev Board, 240 MHz Tensilica LX6 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* ESP32 Boards 1.0.6 +* ESP32 Boards 2.0.2 ``` {esp32_results} @@ -263,7 +263,7 @@ * 96 MHz ARM Cortex-M4 * Arduino IDE 1.8.19, Arduino CLI 0.19.2 -* Teensyduino 1.53 +* Teensyduino 1.56 * Compiler options: "Faster" ``` diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index 141dd28..dce71d8 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -18,7 +18,7 @@ 17 3994 28672 179 2560 18 4288 28672 203 2560 19 4054 28672 251 2560 -20 5404 28672 515 2560 +20 5422 28672 269 2560 21 4980 28672 273 2560 22 3994 28672 154 2560 23 4164 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index e42236c..ca091af 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -18,7 +18,7 @@ 17 1106 30720 39 2048 18 1400 30720 63 2048 19 1166 30720 111 2048 -20 3348 30720 552 2048 +20 3364 30720 304 2048 21 2924 30720 308 2048 22 938 30720 14 2048 23 1168 30720 37 2048 diff --git a/src/ace_routine/LogBinTableRenderer.cpp b/src/ace_routine/LogBinTableRenderer.cpp new file mode 100644 index 0000000..22f813c --- /dev/null +++ b/src/ace_routine/LogBinTableRenderer.cpp @@ -0,0 +1,102 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include +#include "LogBinTableRenderer.h" + +namespace ace_routine { +namespace internal { + +// The numbers for higher duration values deviate from powers of 2 because 2^10 +// = 1024, which is not exactly 1000. +static const char kBinLabel00[] PROGMEM = "<2us"; +static const char kBinLabel01[] PROGMEM = "<4us"; +static const char kBinLabel02[] PROGMEM = "<8us"; +static const char kBinLabel03[] PROGMEM = "<16us"; +static const char kBinLabel04[] PROGMEM = "<32us"; +static const char kBinLabel05[] PROGMEM = "<64us"; +static const char kBinLabel06[] PROGMEM = "<128us"; +static const char kBinLabel07[] PROGMEM = "<256us"; +static const char kBinLabel08[] PROGMEM = "<512us"; +static const char kBinLabel09[] PROGMEM = "<1ms"; +static const char kBinLabel10[] PROGMEM = "<2ms"; +static const char kBinLabel11[] PROGMEM = "<4ms"; +static const char kBinLabel12[] PROGMEM = "<8ms"; +static const char kBinLabel13[] PROGMEM = "<16ms"; +static const char kBinLabel14[] PROGMEM = "<33ms"; +static const char kBinLabel15[] PROGMEM = "<66ms"; +static const char kBinLabel16[] PROGMEM = "<131ms"; +static const char kBinLabel17[] PROGMEM = "<262ms"; +static const char kBinLabel18[] PROGMEM = "<524ms"; +static const char kBinLabel19[] PROGMEM = "<1s"; +static const char kBinLabel20[] PROGMEM = "<2s"; +static const char kBinLabel21[] PROGMEM = "<4s"; +static const char kBinLabel22[] PROGMEM = "<8s"; +static const char kBinLabel23[] PROGMEM = "<17s"; +static const char kBinLabel24[] PROGMEM = "<34s"; +static const char kBinLabel25[] PROGMEM = "<67s"; +static const char kBinLabel26[] PROGMEM = "<134s"; +static const char kBinLabel27[] PROGMEM = "<268s"; +static const char kBinLabel28[] PROGMEM = "<537s"; +static const char kBinLabel29[] PROGMEM = "<1074s"; +static const char kBinLabel30[] PROGMEM = "<2147s"; +static const char kBinLabel31[] PROGMEM = "<4295s"; + +const char* const kBinLabels[kNumBinLabels] PROGMEM = { + kBinLabel00, + kBinLabel01, + kBinLabel02, + kBinLabel03, + kBinLabel04, + kBinLabel05, + kBinLabel06, + kBinLabel07, + kBinLabel08, + kBinLabel09, + kBinLabel10, + kBinLabel11, + kBinLabel12, + kBinLabel13, + kBinLabel14, + kBinLabel15, + kBinLabel16, + kBinLabel17, + kBinLabel18, + kBinLabel19, + kBinLabel20, + kBinLabel21, + kBinLabel22, + kBinLabel23, + kBinLabel24, + kBinLabel25, + kBinLabel26, + kBinLabel27, + kBinLabel28, + kBinLabel29, + kBinLabel30, + kBinLabel31, +}; + +} +} diff --git a/src/ace_routine/LogBinTableRenderer.h b/src/ace_routine/LogBinTableRenderer.h index 9b9d223..f0fef95 100644 --- a/src/ace_routine/LogBinTableRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -29,10 +29,18 @@ SOFTWARE. #include // Print #include // printPad5To() #include "Coroutine.h" // Coroutine -#include "CoroutineProfiler.h" +#include "LogBinProfiler.h" namespace ace_routine { +namespace internal { + /** Number of bins in LogBinProfiler. */ + const uint8_t kNumBinLabels = 32; + + /** Labels for each bin in LogBinProfiler::mBins. */ + extern const char* const kBinLabels[kNumBinLabels] PROGMEM; +} + /** * Print the information in the LogBinProfiler for each Coroutine * in a human-readable table. Each bin is printed as a 5-digit number, since the @@ -149,11 +157,16 @@ class LogBinRendererTemplate { if (endBin <= startBin) return; // needed if startBin = endBin = 0 for (uint8_t i = startBin; i < endBin - 1; i++) { - uint8_t labelLength = strlen(kBinLabels[i]); + // These contortions are needed because the labels are stored in PROGMEM + // flash memory. + auto* label = (const char*) pgm_read_ptr(&internal::kBinLabels[i]); + uint8_t labelLength = strlen_P(label); + + // Print label right justified in a box of 6 characters. for (uint8_t i = 0; i < (6 - labelLength); i++) { printer.print(' '); } - printer.print(kBinLabels[i]); + printer.print((const __FlashStringHelper*) label); } printer.print(F(" >>")); } @@ -185,49 +198,9 @@ class LogBinRendererTemplate { } private: - /** Labels for each bin in LogBinProfiler::mBins. */ - static const char* const kBinLabels[Profiler::kNumBins]; - T_COROUTINE** mRoot; }; -template -const char* const LogBinRendererTemplate::kBinLabels[ - LogBinProfilerTemplate::kNumBins] = { - "<2us", - "<4us", - "<8us", - "<16us", - "<32us", - "<64us", - "<128us", - "<256us", - "<512us", - "<1ms", - "<2ms", - "<4ms", - "<8ms", - "<16ms", - "<33ms", - "<66ms", - "<131ms", - "<262ms", - "<524ms", - "<1s", - "<2s", - "<4s", - "<8s", - "<17s", - "<34s", - "<67s", - "<134s", - "<268s", - "<537s", - "<1074s", - "<2147s", - "<4295s", -}; - using LogBinTableRenderer = LogBinRendererTemplate; } From 70ff9031f462e0556430cbd0104e3e448851d3f4 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 17:32:57 -0700 Subject: [PATCH 31/59] CoroutineProfiler.h: Enable virtual destructor only on 32-bit processors, increasing flash usage by 50-150 bytes --- examples/MemoryBenchmark/README.md | 24 +++++++++---------- examples/MemoryBenchmark/esp32.txt | 6 ++--- examples/MemoryBenchmark/esp8266.txt | 6 ++--- examples/MemoryBenchmark/stm32.txt | 6 ++--- examples/MemoryBenchmark/teensy32.txt | 6 ++--- src/ace_routine/CoroutineProfiler.h | 32 +++++++++++++++++++++++++ src/ace_routine/LogBinTableRenderer.cpp | 3 ++- 7 files changed, 58 insertions(+), 25 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 79d6132..cde2d90 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -361,9 +361,9 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 22224/ 3576 | 340/ 36 | | Scheduler, Two Coroutines (man setup) | 22360/ 3604 | 476/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 22284/ 3644 | 400/ 104 | -| Scheduler, LogBinTableRenderer | 23636/ 3644 | 1752/ 104 | -| Scheduler, LogBinJsonRenderer | 22956/ 3644 | 1072/ 104 | +| Scheduler, LogBinProfiler | 22316/ 3644 | 432/ 104 | +| Scheduler, LogBinTableRenderer | 23664/ 3644 | 1780/ 104 | +| Scheduler, LogBinJsonRenderer | 22984/ 3644 | 1100/ 104 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | | Blink Coroutine | 22232/ 3568 | 348/ 28 | @@ -410,9 +410,9 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 260685/27952 | 356/ 36 | | Scheduler, Two Coroutines (man setup) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 260765/28024 | 436/ 108 | -| Scheduler, LogBinTableRenderer | 265217/28100 | 4888/ 184 | -| Scheduler, LogBinJsonRenderer | 264785/28104 | 4456/ 188 | +| Scheduler, LogBinProfiler | 260797/28024 | 468/ 108 | +| Scheduler, LogBinTableRenderer | 265249/28100 | 4920/ 184 | +| Scheduler, LogBinJsonRenderer | 264817/28104 | 4488/ 188 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | | Blink Coroutine | 261149/28016 | 820/ 100 | @@ -459,9 +459,9 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 205305/16124 | 732/ 64 | | Scheduler, Two Coroutines (man setup) | 205485/16156 | 912/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 205365/16196 | 792/ 136 | -| Scheduler, LogBinTableRenderer | 210973/16276 | 6400/ 216 | -| Scheduler, LogBinJsonRenderer | 210509/16276 | 5936/ 216 | +| Scheduler, LogBinProfiler | 205401/16196 | 828/ 136 | +| Scheduler, LogBinTableRenderer | 211005/16276 | 6432/ 216 | +| Scheduler, LogBinJsonRenderer | 210525/16276 | 5952/ 216 | |---------------------------------------+--------------+-------------| | Blink Function | 205369/16100 | 796/ 40 | | Blink Coroutine | 205481/16124 | 908/ 64 | @@ -509,9 +509,9 @@ $ make README.md | Scheduler, One Coroutine (man setup) | 10588/ 4188 | 356/ 36 | | Scheduler, Two Coroutines (man setup) | 10736/ 4216 | 504/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 10852/ 4256 | 620/ 104 | -| Scheduler, LogBinTableRenderer | 13720/ 4276 | 3488/ 124 | -| Scheduler, LogBinJsonRenderer | 13140/ 4276 | 2908/ 124 | +| Scheduler, LogBinProfiler | 10956/ 4264 | 724/ 112 | +| Scheduler, LogBinTableRenderer | 13800/ 4284 | 3568/ 132 | +| Scheduler, LogBinJsonRenderer | 13284/ 4284 | 3052/ 132 | |---------------------------------------+--------------+-------------| | Blink Function | 10688/ 4160 | 456/ 8 | | Blink Coroutine | 10820/ 4184 | 588/ 32 | diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 0460485..363f98c 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -17,8 +17,8 @@ 16 205485 1310720 16156 327680 17 205305 1310720 16124 327680 18 205485 1310720 16156 327680 -19 205365 1310720 16196 327680 -20 210973 1310720 16276 327680 -21 210509 1310720 16276 327680 +19 205401 1310720 16196 327680 +20 211005 1310720 16276 327680 +21 210525 1310720 16276 327680 22 205369 1310720 16100 327680 23 205481 1310720 16124 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index b779234..e801b07 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -17,8 +17,8 @@ 16 260877 1044464 27984 81920 17 260685 1044464 27952 81920 18 260861 1044464 27984 81920 -19 260765 1044464 28024 81920 -20 265217 1044464 28100 81920 -21 264785 1044464 28104 81920 +19 260797 1044464 28024 81920 +20 265249 1044464 28100 81920 +21 264817 1044464 28104 81920 22 261001 1044464 27988 81920 23 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index a22c6b1..5594ba6 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -17,8 +17,8 @@ 16 22364 131072 3604 20480 17 22224 131072 3576 20480 18 22360 131072 3604 20480 -19 22284 131072 3644 20480 -20 23636 131072 3644 20480 -21 22956 131072 3644 20480 +19 22316 131072 3644 20480 +20 23664 131072 3644 20480 +21 22984 131072 3644 20480 22 22120 131072 3540 20480 23 22232 131072 3568 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 94cbfe7..bfe9041 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -17,8 +17,8 @@ 16 10748 262144 4216 65536 17 10588 262144 4188 65536 18 10736 262144 4216 65536 -19 10852 262144 4256 65536 -20 13720 262144 4276 65536 -21 13140 262144 4276 65536 +19 10956 262144 4264 65536 +20 13800 262144 4284 65536 +21 13284 262144 4284 65536 22 10688 262144 4160 65536 23 10820 262144 4184 65536 diff --git a/src/ace_routine/CoroutineProfiler.h b/src/ace_routine/CoroutineProfiler.h index da09c71..14bf99f 100644 --- a/src/ace_routine/CoroutineProfiler.h +++ b/src/ace_routine/CoroutineProfiler.h @@ -31,6 +31,38 @@ namespace ace_routine { class CoroutineProfiler { public: + /** Use default constructor. */ + CoroutineProfiler() = default; + + /** + * The destructor is NON-virtual on AVR processors because adding a virtual + * destructor causes flash consumption to increase by 600 bytes, even if the + * profiler is never used. If profiling is enabled on 8-bit processors, I + * expect the number of coroutines in the system to be relatively small, so + * it seems reasonable to create instances of the CoroutineProfiler + * statically at the global scope, and attach them to the Coroutines using + * the `Coroutine::setProfiler()` method. This means that this destructor + * will never be called polymorphically. + * + * On 32-bit processors, the destructor is virtual because I expect that the + * application will use a larger number of coroutines, so it will be much + * easier to use to the `LogBinProfiler::createProfilers()` and + * `LogBinProfiler::deleteProfilers()` helper methods to create the + * profilers on the heap. This means that the destructor may be called + * polymorphically and a virtual destructor is needed for correctness. + * It is expected that 32-bit processors will have far more flash memory and + * static RAM than 8-bit processors, so the additional resource consumption + * will hopefully not be too burdensome. If it is, then 32-bit processors + * have the option of using the same technique as 8-bit processors, and use + * the `Coroutine::setProfiler()` to attach statically created instances + * instead. + */ + #if defined(ARDUINO_ARCH_AVR) + ~CoroutineProfiler() = default; + #else + virtual ~CoroutineProfiler() = default; + #endif + /** * Process the completion of the runCoroutine() method which took * `micros` microseconds. diff --git a/src/ace_routine/LogBinTableRenderer.cpp b/src/ace_routine/LogBinTableRenderer.cpp index 22f813c..0f85b18 100644 --- a/src/ace_routine/LogBinTableRenderer.cpp +++ b/src/ace_routine/LogBinTableRenderer.cpp @@ -29,7 +29,8 @@ namespace ace_routine { namespace internal { // The numbers for higher duration values deviate from powers of 2 because 2^10 -// = 1024, which is not exactly 1000. +// = 1024, which is not exactly 1000. The length of each string *must* be 6 or +// smaller, otherwise a bit of code in LogBinTableRenderer.h must be updated. static const char kBinLabel00[] PROGMEM = "<2us"; static const char kBinLabel01[] PROGMEM = "<4us"; static const char kBinLabel02[] PROGMEM = "<8us"; From 9842d89e827998446cd1746a478610c13fa6a93f Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 17:34:13 -0700 Subject: [PATCH 32/59] LogBinProfiler.h: Remove 'delete' of existing profiler pointer in createProfilers(), to prevent accidental delete of statically defined profiler --- src/ace_routine/LogBinProfiler.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ace_routine/LogBinProfiler.h b/src/ace_routine/LogBinProfiler.h index e40f6ca..71cdc03 100644 --- a/src/ace_routine/LogBinProfiler.h +++ b/src/ace_routine/LogBinProfiler.h @@ -88,19 +88,19 @@ class LogBinProfilerTemplate : public CoroutineProfiler { /** * Create a new profiler on the heap and attach it to each coroutine in the - * singly-linked list of coroutines defined by `root`. + * singly-linked list of coroutines defined by `root`. If the coroutine has + * an existing profiler attached to it, the previous profiler is simply + * replaced, but *not* deleted. The reason is that the previous profiler + * could have been created statically, instead of on the heap, and we + * would crash the program if we tried to call `delete` on that pointer. + * + * If createProfilers() is called twice within the same application, (which + * should rarely happen), the program must ensure that deleteProfilers() is + * called before the second call to createProfilers(). Otherwise, heap + * memory will be leaked. */ static void createProfilers(T_COROUTINE** root) { for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { - - // Delete any existing profiler. - auto* currentProfiler = - (LogBinProfilerTemplate*) (*p)->getProfiler(); - if (currentProfiler) { - delete currentProfiler; - } - - // Attach new profiler. auto* profiler = new LogBinProfilerTemplate(); (*p)->setProfiler(profiler); } From 3078fc3ec030248cc143641599f026c11411d95e Mon Sep 17 00:00:00 2001 From: Brian Park Date: Wed, 16 Mar 2022 18:26:06 -0700 Subject: [PATCH 33/59] Coroutine.h: Extract 'run with profiler' code from CoroutineScheduler to Coroutine::runCoroutineWithProfiler(), saving 10-40 bytes of flash --- examples/MemoryBenchmark/README.md | 178 +++++++++++++------------- examples/MemoryBenchmark/attiny.txt | 26 ++-- examples/MemoryBenchmark/esp32.txt | 26 ++-- examples/MemoryBenchmark/esp8266.txt | 26 ++-- examples/MemoryBenchmark/micro.txt | 26 ++-- examples/MemoryBenchmark/nano.txt | 26 ++-- examples/MemoryBenchmark/stm32.txt | 26 ++-- examples/MemoryBenchmark/teensy32.txt | 22 ++-- src/ace_routine/Coroutine.h | 26 +++- src/ace_routine/CoroutineScheduler.h | 17 +-- 10 files changed, 209 insertions(+), 190 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index cde2d90..df115b7 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -199,24 +199,24 @@ $ make README.md | One Coroutine (seconds) | 738/ 37 | 338/ 26 | | Two Coroutines (seconds) | 958/ 61 | 558/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 866/ 39 | 466/ 28 | -| Scheduler, Two Coroutines | 1052/ 63 | 652/ 52 | +| Scheduler, One Coroutine | 830/ 39 | 430/ 28 | +| Scheduler, Two Coroutines | 1016/ 63 | 616/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 834/ 39 | 434/ 28 | -| Scheduler, Two Coroutines (micros) | 988/ 63 | 588/ 52 | +| Scheduler, One Coroutine (micros) | 798/ 39 | 398/ 28 | +| Scheduler, Two Coroutines (micros) | 952/ 63 | 552/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 962/ 39 | 562/ 28 | -| Scheduler, Two Coroutines (seconds) | 1176/ 63 | 776/ 52 | +| Scheduler, One Coroutine (seconds) | 926/ 39 | 526/ 28 | +| Scheduler, Two Coroutines (seconds) | 1140/ 63 | 740/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 920/ 39 | 520/ 28 | -| Scheduler, Two Coroutines (setup) | 1202/ 63 | 802/ 52 | +| Scheduler, One Coroutine (setup) | 880/ 39 | 480/ 28 | +| Scheduler, Two Coroutines (setup) | 1162/ 63 | 762/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 896/ 39 | 496/ 28 | -| Scheduler, Two Coroutines (man setup) | 1186/ 63 | 786/ 52 | +| Scheduler, One Coroutine (man setup) | 860/ 39 | 460/ 28 | +| Scheduler, Two Coroutines (man setup) | 1150/ 63 | 750/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 954/ 111 | 554/ 100 | -| Scheduler, LogBinTableRenderer | 2798/ 193 | 2398/ 182 | -| Scheduler, LogBinJsonRenderer | 2356/ 197 | 1956/ 186 | +| Scheduler, LogBinProfiler | 918/ 111 | 518/ 100 | +| Scheduler, LogBinTableRenderer | 2766/ 193 | 2366/ 182 | +| Scheduler, LogBinJsonRenderer | 2326/ 197 | 1926/ 186 | |---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | | Blink Coroutine | 766/ 37 | 366/ 26 | @@ -248,24 +248,24 @@ $ make README.md | One Coroutine (seconds) | 954/ 37 | 348/ 26 | | Two Coroutines (seconds) | 1180/ 61 | 574/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 1078/ 39 | 472/ 28 | -| Scheduler, Two Coroutines | 1264/ 63 | 658/ 52 | +| Scheduler, One Coroutine | 1042/ 39 | 436/ 28 | +| Scheduler, Two Coroutines | 1228/ 63 | 622/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 1050/ 39 | 444/ 28 | -| Scheduler, Two Coroutines (micros) | 1208/ 63 | 602/ 52 | +| Scheduler, One Coroutine (micros) | 1014/ 39 | 408/ 28 | +| Scheduler, Two Coroutines (micros) | 1172/ 63 | 566/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 1178/ 39 | 572/ 28 | -| Scheduler, Two Coroutines (seconds) | 1396/ 63 | 790/ 52 | +| Scheduler, One Coroutine (seconds) | 1142/ 39 | 536/ 28 | +| Scheduler, Two Coroutines (seconds) | 1360/ 63 | 754/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 1128/ 39 | 522/ 28 | -| Scheduler, Two Coroutines (setup) | 1414/ 63 | 808/ 52 | +| Scheduler, One Coroutine (setup) | 1096/ 39 | 490/ 28 | +| Scheduler, Two Coroutines (setup) | 1382/ 63 | 776/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 1106/ 39 | 500/ 28 | -| Scheduler, Two Coroutines (man setup) | 1400/ 63 | 794/ 52 | +| Scheduler, One Coroutine (man setup) | 1074/ 39 | 468/ 28 | +| Scheduler, Two Coroutines (man setup) | 1368/ 63 | 762/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 1166/ 111 | 560/ 100 | -| Scheduler, LogBinTableRenderer | 3364/ 304 | 2758/ 293 | -| Scheduler, LogBinJsonRenderer | 2924/ 308 | 2318/ 297 | +| Scheduler, LogBinProfiler | 1134/ 111 | 528/ 100 | +| Scheduler, LogBinTableRenderer | 3340/ 304 | 2734/ 293 | +| Scheduler, LogBinJsonRenderer | 2900/ 308 | 2294/ 297 | |---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | | Blink Coroutine | 1168/ 37 | 562/ 26 | @@ -297,24 +297,24 @@ $ make README.md | One Coroutine (seconds) | 3842/ 177 | 288/ 26 | | Two Coroutines (seconds) | 4068/ 201 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 3966/ 179 | 412/ 28 | -| Scheduler, Two Coroutines | 4152/ 203 | 598/ 52 | +| Scheduler, One Coroutine | 3930/ 179 | 376/ 28 | +| Scheduler, Two Coroutines | 4116/ 203 | 562/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 3938/ 179 | 384/ 28 | -| Scheduler, Two Coroutines (micros) | 4096/ 203 | 542/ 52 | +| Scheduler, One Coroutine (micros) | 3902/ 179 | 348/ 28 | +| Scheduler, Two Coroutines (micros) | 4060/ 203 | 506/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 4066/ 179 | 512/ 28 | -| Scheduler, Two Coroutines (seconds) | 4284/ 203 | 730/ 52 | +| Scheduler, One Coroutine (seconds) | 4030/ 179 | 476/ 28 | +| Scheduler, Two Coroutines (seconds) | 4248/ 203 | 694/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 4016/ 179 | 462/ 28 | -| Scheduler, Two Coroutines (setup) | 4302/ 203 | 748/ 52 | +| Scheduler, One Coroutine (setup) | 3984/ 179 | 430/ 28 | +| Scheduler, Two Coroutines (setup) | 4270/ 203 | 716/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 3994/ 179 | 440/ 28 | -| Scheduler, Two Coroutines (man setup) | 4288/ 203 | 734/ 52 | +| Scheduler, One Coroutine (man setup) | 3962/ 179 | 408/ 28 | +| Scheduler, Two Coroutines (man setup) | 4256/ 203 | 702/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 4054/ 251 | 500/ 100 | -| Scheduler, LogBinTableRenderer | 5422/ 269 | 1868/ 118 | -| Scheduler, LogBinJsonRenderer | 4980/ 273 | 1426/ 122 | +| Scheduler, LogBinProfiler | 4022/ 251 | 468/ 100 | +| Scheduler, LogBinTableRenderer | 5398/ 269 | 1844/ 118 | +| Scheduler, LogBinJsonRenderer | 4958/ 273 | 1404/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | | Blink Coroutine | 4164/ 177 | 610/ 26 | @@ -346,24 +346,24 @@ $ make README.md | One Coroutine (seconds) | 22032/ 3572 | 148/ 32 | | Two Coroutines (seconds) | 22196/ 3600 | 312/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 22208/ 3576 | 324/ 36 | -| Scheduler, Two Coroutines | 22312/ 3604 | 428/ 64 | +| Scheduler, One Coroutine | 22192/ 3576 | 308/ 36 | +| Scheduler, Two Coroutines | 22296/ 3604 | 412/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 22208/ 3576 | 324/ 36 | -| Scheduler, Two Coroutines (micros) | 22312/ 3604 | 428/ 64 | +| Scheduler, One Coroutine (micros) | 22192/ 3576 | 308/ 36 | +| Scheduler, Two Coroutines (micros) | 22296/ 3604 | 412/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 22224/ 3576 | 340/ 36 | -| Scheduler, Two Coroutines (seconds) | 22344/ 3604 | 460/ 64 | +| Scheduler, One Coroutine (seconds) | 22208/ 3576 | 324/ 36 | +| Scheduler, Two Coroutines (seconds) | 22328/ 3604 | 444/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 22232/ 3576 | 348/ 36 | -| Scheduler, Two Coroutines (setup) | 22364/ 3604 | 480/ 64 | +| Scheduler, One Coroutine (setup) | 22216/ 3576 | 332/ 36 | +| Scheduler, Two Coroutines (setup) | 22348/ 3604 | 464/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 22224/ 3576 | 340/ 36 | -| Scheduler, Two Coroutines (man setup) | 22360/ 3604 | 476/ 64 | +| Scheduler, One Coroutine (man setup) | 22208/ 3576 | 324/ 36 | +| Scheduler, Two Coroutines (man setup) | 22344/ 3604 | 460/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 22316/ 3644 | 432/ 104 | -| Scheduler, LogBinTableRenderer | 23664/ 3644 | 1780/ 104 | -| Scheduler, LogBinJsonRenderer | 22984/ 3644 | 1100/ 104 | +| Scheduler, LogBinProfiler | 22300/ 3644 | 416/ 104 | +| Scheduler, LogBinTableRenderer | 23644/ 3644 | 1760/ 104 | +| Scheduler, LogBinJsonRenderer | 22968/ 3644 | 1084/ 104 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | | Blink Coroutine | 22232/ 3568 | 348/ 28 | @@ -395,24 +395,24 @@ $ make README.md | One Coroutine (seconds) | 260541/27952 | 212/ 36 | | Two Coroutines (seconds) | 260717/27976 | 388/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 260669/27952 | 340/ 36 | -| Scheduler, Two Coroutines | 260813/27984 | 484/ 68 | +| Scheduler, One Coroutine | 260653/27952 | 324/ 36 | +| Scheduler, Two Coroutines | 260797/27984 | 468/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 260669/27952 | 340/ 36 | -| Scheduler, Two Coroutines (micros) | 260813/27984 | 484/ 68 | +| Scheduler, One Coroutine (micros) | 260653/27952 | 324/ 36 | +| Scheduler, Two Coroutines (micros) | 260797/27984 | 468/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 260701/27952 | 372/ 36 | -| Scheduler, Two Coroutines (seconds) | 260861/27984 | 532/ 68 | +| Scheduler, One Coroutine (seconds) | 260669/27952 | 340/ 36 | +| Scheduler, Two Coroutines (seconds) | 260829/27984 | 500/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 260701/27952 | 372/ 36 | -| Scheduler, Two Coroutines (setup) | 260877/27984 | 548/ 68 | +| Scheduler, One Coroutine (setup) | 260685/27952 | 356/ 36 | +| Scheduler, Two Coroutines (setup) | 260861/27984 | 532/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 260685/27952 | 356/ 36 | -| Scheduler, Two Coroutines (man setup) | 260861/27984 | 532/ 68 | +| Scheduler, One Coroutine (man setup) | 260669/27952 | 340/ 36 | +| Scheduler, Two Coroutines (man setup) | 260845/27984 | 516/ 68 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 260797/28024 | 468/ 108 | -| Scheduler, LogBinTableRenderer | 265249/28100 | 4920/ 184 | -| Scheduler, LogBinJsonRenderer | 264817/28104 | 4488/ 188 | +| Scheduler, LogBinProfiler | 260781/28024 | 452/ 108 | +| Scheduler, LogBinTableRenderer | 265489/28100 | 5160/ 184 | +| Scheduler, LogBinJsonRenderer | 265057/28104 | 4728/ 188 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | | Blink Coroutine | 261149/28016 | 820/ 100 | @@ -444,24 +444,24 @@ $ make README.md | One Coroutine (seconds) | 205145/16124 | 572/ 64 | | Two Coroutines (seconds) | 205333/16148 | 760/ 88 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 205285/16124 | 712/ 64 | -| Scheduler, Two Coroutines | 205425/16156 | 852/ 96 | +| Scheduler, One Coroutine | 205245/16124 | 672/ 64 | +| Scheduler, Two Coroutines | 205385/16156 | 812/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 205261/16124 | 688/ 64 | -| Scheduler, Two Coroutines (micros) | 205401/16156 | 828/ 96 | +| Scheduler, One Coroutine (micros) | 205221/16124 | 648/ 64 | +| Scheduler, Two Coroutines (micros) | 205361/16156 | 788/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 205301/16124 | 728/ 64 | -| Scheduler, Two Coroutines (seconds) | 205457/16156 | 884/ 96 | +| Scheduler, One Coroutine (seconds) | 205261/16124 | 688/ 64 | +| Scheduler, Two Coroutines (seconds) | 205417/16156 | 844/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 205313/16124 | 740/ 64 | -| Scheduler, Two Coroutines (setup) | 205485/16156 | 912/ 96 | +| Scheduler, One Coroutine (setup) | 205273/16124 | 700/ 64 | +| Scheduler, Two Coroutines (setup) | 205445/16156 | 872/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 205305/16124 | 732/ 64 | -| Scheduler, Two Coroutines (man setup) | 205485/16156 | 912/ 96 | +| Scheduler, One Coroutine (man setup) | 205265/16124 | 692/ 64 | +| Scheduler, Two Coroutines (man setup) | 205445/16156 | 872/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 205401/16196 | 828/ 136 | -| Scheduler, LogBinTableRenderer | 211005/16276 | 6432/ 216 | -| Scheduler, LogBinJsonRenderer | 210525/16276 | 5952/ 216 | +| Scheduler, LogBinProfiler | 205361/16196 | 788/ 136 | +| Scheduler, LogBinTableRenderer | 210969/16276 | 6396/ 216 | +| Scheduler, LogBinJsonRenderer | 210489/16276 | 5916/ 216 | |---------------------------------------+--------------+-------------| | Blink Function | 205369/16100 | 796/ 40 | | Blink Coroutine | 205481/16124 | 908/ 64 | @@ -494,22 +494,22 @@ $ make README.md | One Coroutine (seconds) | 10408/ 4184 | 176/ 32 | | Two Coroutines (seconds) | 10548/ 4212 | 316/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 10568/ 4188 | 336/ 36 | -| Scheduler, Two Coroutines | 10684/ 4216 | 452/ 64 | +| Scheduler, One Coroutine | 10560/ 4188 | 328/ 36 | +| Scheduler, Two Coroutines | 10676/ 4216 | 444/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 10556/ 4188 | 324/ 36 | -| Scheduler, Two Coroutines (micros) | 10660/ 4216 | 428/ 64 | +| Scheduler, One Coroutine (micros) | 10548/ 4188 | 316/ 36 | +| Scheduler, Two Coroutines (micros) | 10652/ 4216 | 420/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 10588/ 4188 | 356/ 36 | -| Scheduler, Two Coroutines (seconds) | 10724/ 4216 | 492/ 64 | +| Scheduler, One Coroutine (seconds) | 10580/ 4188 | 348/ 36 | +| Scheduler, Two Coroutines (seconds) | 10716/ 4216 | 484/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 10600/ 4188 | 368/ 36 | -| Scheduler, Two Coroutines (setup) | 10748/ 4216 | 516/ 64 | +| Scheduler, One Coroutine (setup) | 10592/ 4188 | 360/ 36 | +| Scheduler, Two Coroutines (setup) | 10740/ 4216 | 508/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 10588/ 4188 | 356/ 36 | -| Scheduler, Two Coroutines (man setup) | 10736/ 4216 | 504/ 64 | +| Scheduler, One Coroutine (man setup) | 10580/ 4188 | 348/ 36 | +| Scheduler, Two Coroutines (man setup) | 10728/ 4216 | 496/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 10956/ 4264 | 724/ 112 | +| Scheduler, LogBinProfiler | 10952/ 4264 | 720/ 112 | | Scheduler, LogBinTableRenderer | 13800/ 4284 | 3568/ 132 | | Scheduler, LogBinJsonRenderer | 13284/ 4284 | 3052/ 132 | |---------------------------------------+--------------+-------------| diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index 299b455..cab6c18 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -7,18 +7,18 @@ 6 770 8192 61 512 7 738 8192 37 512 8 958 8192 61 512 -9 866 8192 39 512 -10 1052 8192 63 512 -11 834 8192 39 512 -12 988 8192 63 512 -13 962 8192 39 512 -14 1176 8192 63 512 -15 920 8192 39 512 -16 1202 8192 63 512 -17 896 8192 39 512 -18 1186 8192 63 512 -19 954 8192 111 512 -20 2798 8192 193 512 -21 2356 8192 197 512 +9 830 8192 39 512 +10 1016 8192 63 512 +11 798 8192 39 512 +12 952 8192 63 512 +13 926 8192 39 512 +14 1140 8192 63 512 +15 880 8192 39 512 +16 1162 8192 63 512 +17 860 8192 39 512 +18 1150 8192 63 512 +19 918 8192 111 512 +20 2766 8192 193 512 +21 2326 8192 197 512 22 546 8192 14 512 23 766 8192 37 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 363f98c..c4972f8 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -7,18 +7,18 @@ 6 205289 1310720 16148 327680 7 205145 1310720 16124 327680 8 205333 1310720 16148 327680 -9 205285 1310720 16124 327680 -10 205425 1310720 16156 327680 -11 205261 1310720 16124 327680 -12 205401 1310720 16156 327680 -13 205301 1310720 16124 327680 -14 205457 1310720 16156 327680 -15 205313 1310720 16124 327680 -16 205485 1310720 16156 327680 -17 205305 1310720 16124 327680 -18 205485 1310720 16156 327680 -19 205401 1310720 16196 327680 -20 211005 1310720 16276 327680 -21 210525 1310720 16276 327680 +9 205245 1310720 16124 327680 +10 205385 1310720 16156 327680 +11 205221 1310720 16124 327680 +12 205361 1310720 16156 327680 +13 205261 1310720 16124 327680 +14 205417 1310720 16156 327680 +15 205273 1310720 16124 327680 +16 205445 1310720 16156 327680 +17 205265 1310720 16124 327680 +18 205445 1310720 16156 327680 +19 205361 1310720 16196 327680 +20 210969 1310720 16276 327680 +21 210489 1310720 16276 327680 22 205369 1310720 16100 327680 23 205481 1310720 16124 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index e801b07..44e3525 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -7,18 +7,18 @@ 6 260701 1044464 27976 81920 7 260541 1044464 27952 81920 8 260717 1044464 27976 81920 -9 260669 1044464 27952 81920 -10 260813 1044464 27984 81920 -11 260669 1044464 27952 81920 -12 260813 1044464 27984 81920 -13 260701 1044464 27952 81920 -14 260861 1044464 27984 81920 -15 260701 1044464 27952 81920 -16 260877 1044464 27984 81920 -17 260685 1044464 27952 81920 -18 260861 1044464 27984 81920 -19 260797 1044464 28024 81920 -20 265249 1044464 28100 81920 -21 264817 1044464 28104 81920 +9 260653 1044464 27952 81920 +10 260797 1044464 27984 81920 +11 260653 1044464 27952 81920 +12 260797 1044464 27984 81920 +13 260669 1044464 27952 81920 +14 260829 1044464 27984 81920 +15 260685 1044464 27952 81920 +16 260861 1044464 27984 81920 +17 260669 1044464 27952 81920 +18 260845 1044464 27984 81920 +19 260781 1044464 28024 81920 +20 265489 1044464 28100 81920 +21 265057 1044464 28104 81920 22 261001 1044464 27988 81920 23 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index dce71d8..b745eb9 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -7,18 +7,18 @@ 6 3880 28672 201 2560 7 3842 28672 177 2560 8 4068 28672 201 2560 -9 3966 28672 179 2560 -10 4152 28672 203 2560 -11 3938 28672 179 2560 -12 4096 28672 203 2560 -13 4066 28672 179 2560 -14 4284 28672 203 2560 -15 4016 28672 179 2560 -16 4302 28672 203 2560 -17 3994 28672 179 2560 -18 4288 28672 203 2560 -19 4054 28672 251 2560 -20 5422 28672 269 2560 -21 4980 28672 273 2560 +9 3930 28672 179 2560 +10 4116 28672 203 2560 +11 3902 28672 179 2560 +12 4060 28672 203 2560 +13 4030 28672 179 2560 +14 4248 28672 203 2560 +15 3984 28672 179 2560 +16 4270 28672 203 2560 +17 3962 28672 179 2560 +18 4256 28672 203 2560 +19 4022 28672 251 2560 +20 5398 28672 269 2560 +21 4958 28672 273 2560 22 3994 28672 154 2560 23 4164 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index ca091af..7e84a36 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -7,18 +7,18 @@ 6 992 30720 61 2048 7 954 30720 37 2048 8 1180 30720 61 2048 -9 1078 30720 39 2048 -10 1264 30720 63 2048 -11 1050 30720 39 2048 -12 1208 30720 63 2048 -13 1178 30720 39 2048 -14 1396 30720 63 2048 -15 1128 30720 39 2048 -16 1414 30720 63 2048 -17 1106 30720 39 2048 -18 1400 30720 63 2048 -19 1166 30720 111 2048 -20 3364 30720 304 2048 -21 2924 30720 308 2048 +9 1042 30720 39 2048 +10 1228 30720 63 2048 +11 1014 30720 39 2048 +12 1172 30720 63 2048 +13 1142 30720 39 2048 +14 1360 30720 63 2048 +15 1096 30720 39 2048 +16 1382 30720 63 2048 +17 1074 30720 39 2048 +18 1368 30720 63 2048 +19 1134 30720 111 2048 +20 3340 30720 304 2048 +21 2900 30720 308 2048 22 938 30720 14 2048 23 1168 30720 37 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index 5594ba6..fafbe4e 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -7,18 +7,18 @@ 6 22228 131072 3600 20480 7 22032 131072 3572 20480 8 22196 131072 3600 20480 -9 22208 131072 3576 20480 -10 22312 131072 3604 20480 -11 22208 131072 3576 20480 -12 22312 131072 3604 20480 -13 22224 131072 3576 20480 -14 22344 131072 3604 20480 -15 22232 131072 3576 20480 -16 22364 131072 3604 20480 -17 22224 131072 3576 20480 -18 22360 131072 3604 20480 -19 22316 131072 3644 20480 -20 23664 131072 3644 20480 -21 22984 131072 3644 20480 +9 22192 131072 3576 20480 +10 22296 131072 3604 20480 +11 22192 131072 3576 20480 +12 22296 131072 3604 20480 +13 22208 131072 3576 20480 +14 22328 131072 3604 20480 +15 22216 131072 3576 20480 +16 22348 131072 3604 20480 +17 22208 131072 3576 20480 +18 22344 131072 3604 20480 +19 22300 131072 3644 20480 +20 23644 131072 3644 20480 +21 22968 131072 3644 20480 22 22120 131072 3540 20480 23 22232 131072 3568 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index bfe9041..7e26fa4 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -7,17 +7,17 @@ 6 10552 262144 4212 65536 7 10408 262144 4184 65536 8 10548 262144 4212 65536 -9 10568 262144 4188 65536 -10 10684 262144 4216 65536 -11 10556 262144 4188 65536 -12 10660 262144 4216 65536 -13 10588 262144 4188 65536 -14 10724 262144 4216 65536 -15 10600 262144 4188 65536 -16 10748 262144 4216 65536 -17 10588 262144 4188 65536 -18 10736 262144 4216 65536 -19 10956 262144 4264 65536 +9 10560 262144 4188 65536 +10 10676 262144 4216 65536 +11 10548 262144 4188 65536 +12 10652 262144 4216 65536 +13 10580 262144 4188 65536 +14 10716 262144 4216 65536 +15 10592 262144 4188 65536 +16 10740 262144 4216 65536 +17 10580 262144 4188 65536 +18 10728 262144 4216 65536 +19 10952 262144 4264 65536 20 13800 262144 4284 65536 21 13284 262144 4284 65536 22 10688 262144 4160 65536 diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index e681853..3b0e0fd 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -28,6 +28,7 @@ SOFTWARE. #include // UINT16_MAX #include // Print #include // PrintStr<> +#include "CoroutineProfiler.h" #include "ClockInterface.h" class __FlashStringHelper; @@ -265,8 +266,6 @@ extern className##_##name name namespace ace_routine { -class CoroutineProfiler; - /** A lookup table from Status integer to human-readable strings. */ extern const __FlashStringHelper* const sStatusStrings[]; @@ -319,6 +318,29 @@ class CoroutineTemplate { */ virtual void setupCoroutine() {} + /** + * This is a variant of runCoroutine() which measures the execution time of + * runCoroutine() and updates the attached profiler if it exists. + * + * On 8-bit processors, memory consumption can be reduced by calling the + * `Coroutine::runCoroutine()` method directly in the global `loop()` + * function, instead of using the `CoroutineScheduler`. In such an + * environment, the end-user can enable profiling by manually changing the + * calls to `Coroutine::runCoroutine()` to + * `Coroutine::runCoroutineWithProfiler()`, and recompiling the program. + */ + int runCoroutineWithProfiler() { + if (mProfiler) { + uint32_t startMicros = coroutineMicros(); + runCoroutine(); + uint32_t elapsedMicros = coroutineMicros() - startMicros; + mProfiler->updateElapsedMicros(elapsedMicros); + return 0; + } else { + return runCoroutine(); + } + } + /** * Return the type of the name string, either kNameTypeCString or * kNameTypeFString. diff --git a/src/ace_routine/CoroutineScheduler.h b/src/ace_routine/CoroutineScheduler.h index 59a5c3f..71e7043 100644 --- a/src/ace_routine/CoroutineScheduler.h +++ b/src/ace_routine/CoroutineScheduler.h @@ -173,15 +173,13 @@ class CoroutineSchedulerTemplate { // its continuation context determines whether to call // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or // Coroutine::isDelaySecondsExpired(). - if ((*mCurrent)->mProfiler) { - uint32_t startMicros = T_COROUTINE::coroutineMicros(); - (*mCurrent)->runCoroutine(); - uint32_t elapsedMicros = T_COROUTINE::coroutineMicros() - - startMicros; - (*mCurrent)->mProfiler->updateElapsedMicros(elapsedMicros); - } else { - (*mCurrent)->runCoroutine(); - } + // + // The `CoroutineScheduler` always enables the profiler by calling + // `Coroutine::runCoroutineWithProfiler()`. If memory usage is a + // problem, then consider calling the `Coroutine::runCoroutine()` + // directly in the global `loop()` function, instead of going through + // the `CoroutineScheduler`. + (*mCurrent)->runCoroutineWithProfiler(); break; case T_COROUTINE::kStatusEnding: @@ -198,7 +196,6 @@ class CoroutineSchedulerTemplate { mCurrent = (*mCurrent)->getNext(); } - /** List all the routines in the linked list to the printer. */ void listCoroutines(Print& printer) { for (T_COROUTINE** p = T_COROUTINE::getRoot(); (*p) != nullptr; From 7850d49b2259a719eea2cf4d2817493963048af2 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 08:21:22 -0700 Subject: [PATCH 34/59] LogBinProfiler.h: Move rollupExteriorBins() into ace_common::internal namespace, and into LogBinProfiler.cpp file --- src/ace_routine/LogBinJsonRenderer.h | 5 +- src/ace_routine/LogBinProfiler.cpp | 63 +++++++++++++++++++ src/ace_routine/LogBinProfiler.h | 42 ++++--------- src/ace_routine/LogBinTableRenderer.h | 6 +- .../LogBinProfilerTest/LogBinProfilerTest.ino | 2 +- 5 files changed, 81 insertions(+), 37 deletions(-) create mode 100644 src/ace_routine/LogBinProfiler.cpp diff --git a/src/ace_routine/LogBinJsonRenderer.h b/src/ace_routine/LogBinJsonRenderer.h index 0d31356..3a81ff4 100644 --- a/src/ace_routine/LogBinJsonRenderer.h +++ b/src/ace_routine/LogBinJsonRenderer.h @@ -29,6 +29,7 @@ SOFTWARE. #include // Print #include "Coroutine.h" // Coroutine #include "CoroutineProfiler.h" +#include "LogBinProfiler.h" // rollupExteriorBins() namespace ace_routine { @@ -83,8 +84,8 @@ class LogBinJsonRendererTemplate { // Roll up the exterior bins in to the first and last bins if requested. const uint16_t* bins; if (rollup) { - rollupExteriorBins(bufBins, profiler->mBins, Profiler::kNumBins, - startBin, endBin); + internal::rollupExteriorBins( + bufBins, profiler->mBins, Profiler::kNumBins, startBin, endBin); bins = bufBins; } else { bins = profiler->mBins; diff --git a/src/ace_routine/LogBinProfiler.cpp b/src/ace_routine/LogBinProfiler.cpp new file mode 100644 index 0000000..ffe63f6 --- /dev/null +++ b/src/ace_routine/LogBinProfiler.cpp @@ -0,0 +1,63 @@ +/* +MIT License + +Copyright (c) 2022 Brian T. Park + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "LogBinProfiler.h" + +namespace ace_routine { +namespace internal { + +void rollupExteriorBins( + uint16_t dst[], + const uint16_t src[], + uint8_t numBins, + uint8_t startBin, + uint8_t endBin +) { + endBin = (endBin > numBins) ? numBins : endBin; + if (endBin <= startBin) return; + + // Rollup all bins at or below startBin into the startBin. + uint32_t leftRollup = 0; + for (uint8_t i = 0; i <= startBin; i++) { + leftRollup += src[i]; + } + if (leftRollup > UINT16_MAX) leftRollup = UINT16_MAX; + dst[startBin] = leftRollup; + + // Copy the interior bins. + for (uint8_t i = startBin + 1; i < endBin - 1; i++) { + dst[i] = src[i]; + } + + // Rollup all bins at or above the last bin into the last bin. + uint32_t rightRollup = (endBin - 1 == startBin) ? leftRollup : 0; + for (uint8_t i = endBin - 1; i < numBins; i++) { + rightRollup += src[i]; + } + if (rightRollup > UINT16_MAX) rightRollup = UINT16_MAX; + dst[endBin - 1] = rightRollup; +} + +} +} diff --git a/src/ace_routine/LogBinProfiler.h b/src/ace_routine/LogBinProfiler.h index 71cdc03..568f60f 100644 --- a/src/ace_routine/LogBinProfiler.h +++ b/src/ace_routine/LogBinProfiler.h @@ -133,45 +133,25 @@ class LogBinProfilerTemplate : public CoroutineProfiler { using LogBinProfiler = LogBinProfilerTemplate; +namespace internal { + /** - * Rollup bins before `startBin` into `startBin` and bins at or after - * `endBin` into the last bin (at `endBin - 1`). This is useful to preserve - * count information when printing only a subset of the `mBins[]` array. If - * `endBin <= startBin`, this function does nothing. If `endBin < startBin - - * 1`, there is only single interior bin, so everything gets rolled up into - * the single bin. This is probably not useful, but at least it's + * Rollup bins before `startBin` into the first bin (at `startBin`) and bins at + * or after `endBin` into the last bin (at `endBin - 1`). This is useful to + * preserve count information when printing only a subset of the `mBins[]` + * array. If `endBin <= startBin`, this function does nothing. If `endBin == + * startBin + 1`, there is only single interior bin, so everything gets rolled + * up into the single bin. This is probably not useful, but at least it's * mathematically correct. */ -inline void rollupExteriorBins( +void rollupExteriorBins( uint16_t dst[], const uint16_t src[], uint8_t numBins, uint8_t startBin, uint8_t endBin -) { - endBin = (endBin > numBins) ? numBins : endBin; - if (endBin <= startBin) return; - - // Rollup all bins at or below startBin into the startBin. - uint32_t leftRollup = 0; - for (uint8_t i = 0; i <= startBin; i++) { - leftRollup += src[i]; - } - if (leftRollup > UINT16_MAX) leftRollup = UINT16_MAX; - dst[startBin] = leftRollup; - - // Copy the interior bins. - for (uint8_t i = startBin + 1; i < endBin - 1; i++) { - dst[i] = src[i]; - } - - // Rollup all bins at or above the last bin into the last bin. - uint32_t rightRollup = (endBin - 1 == startBin) ? leftRollup : 0; - for (uint8_t i = endBin - 1; i < numBins; i++) { - rightRollup += src[i]; - } - if (rightRollup > UINT16_MAX) rightRollup = UINT16_MAX; - dst[endBin - 1] = rightRollup; +); + } } diff --git a/src/ace_routine/LogBinTableRenderer.h b/src/ace_routine/LogBinTableRenderer.h index f0fef95..289b5a7 100644 --- a/src/ace_routine/LogBinTableRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -29,7 +29,7 @@ SOFTWARE. #include // Print #include // printPad5To() #include "Coroutine.h" // Coroutine -#include "LogBinProfiler.h" +#include "LogBinProfiler.h" // rollupExteriorBins() namespace ace_routine { @@ -123,8 +123,8 @@ class LogBinRendererTemplate { // Roll up the exterior bins in to the first and last bins if requested. const uint16_t* bins; if (rollup) { - rollupExteriorBins(bufBins, profiler->mBins, Profiler::kNumBins, - startBin, endBin); + internal::rollupExteriorBins( + bufBins, profiler->mBins, Profiler::kNumBins, startBin, endBin); bins = bufBins; } else { bins = profiler->mBins; diff --git a/tests/LogBinProfilerTest/LogBinProfilerTest.ino b/tests/LogBinProfilerTest/LogBinProfilerTest.ino index a69120a..0a0cd3c 100644 --- a/tests/LogBinProfilerTest/LogBinProfilerTest.ino +++ b/tests/LogBinProfilerTest/LogBinProfilerTest.ino @@ -4,7 +4,7 @@ #include using ace_routine::LogBinProfiler; -using ace_routine::rollupExteriorBins; +using ace_routine::internal::rollupExteriorBins; using aunit::TestRunner; // --------------------------------------------------------------------------- From eff2a990b087f570f36b66a531ed15bb7b8e5a47 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 08:46:06 -0700 Subject: [PATCH 35/59] LogBinTableRenderer.cpp: Create printPStringTo() helper to pad or truncate bin-labels properly --- src/ace_routine/LogBinTableRenderer.cpp | 49 +++++++++- src/ace_routine/LogBinTableRenderer.h | 115 ++++++++++-------------- 2 files changed, 95 insertions(+), 69 deletions(-) diff --git a/src/ace_routine/LogBinTableRenderer.cpp b/src/ace_routine/LogBinTableRenderer.cpp index 0f85b18..afc619b 100644 --- a/src/ace_routine/LogBinTableRenderer.cpp +++ b/src/ace_routine/LogBinTableRenderer.cpp @@ -23,14 +23,16 @@ SOFTWARE. */ #include +#include // printPad5To() #include "LogBinTableRenderer.h" namespace ace_routine { namespace internal { // The numbers for higher duration values deviate from powers of 2 because 2^10 -// = 1024, which is not exactly 1000. The length of each string *must* be 6 or -// smaller, otherwise a bit of code in LogBinTableRenderer.h must be updated. +// = 1024, which is not exactly 1000. The length of each string should be 6 or +// smaller, otherwise it will be truncated by +// LogBinTableRenderer::printHeaderTo(). static const char kBinLabel00[] PROGMEM = "<2us"; static const char kBinLabel01[] PROGMEM = "<4us"; static const char kBinLabel02[] PROGMEM = "<8us"; @@ -99,5 +101,48 @@ const char* const kBinLabels[kNumBinLabels] PROGMEM = { kBinLabel31, }; +void printHeaderTo(Print& printer, uint8_t startBin, uint8_t endBin) { + endBin = (endBin > kNumBinLabels) ? kNumBinLabels : endBin; + if (endBin <= startBin) return; // needed if startBin = endBin = 0 + + for (uint8_t i = startBin; i < endBin - 1; i++) { + auto* label = (const char*) pgm_read_ptr(&internal::kBinLabels[i]); + printPStringTo(printer, label, 6); + } + printer.print(F(" >>")); +} + +void printPStringTo(Print& printer, const char* s, uint8_t boxSize) { + uint8_t length = strlen_P(s); + uint8_t printLength; + if (length < boxSize) { + for (uint8_t i = 0; i < (boxSize - length); i++) { + printer.print(' '); + } + printLength = length; + } else { + printLength = boxSize; + } + + for (uint8_t i = 0; i < printLength; i++) { + printer.print((char) pgm_read_byte(&s[i])); + } +} + +void printBinsTo( + Print& printer, + const uint16_t bins[], + uint8_t numBins, + uint8_t startBin, + uint8_t endBin) { + + endBin = (endBin > numBins) ? numBins : endBin; + for (uint8_t i = startBin; i < endBin; i++) { + uint16_t count = bins[i]; + printer.print(' '); + ace_common::printPad5To(printer, count); + } +} + } } diff --git a/src/ace_routine/LogBinTableRenderer.h b/src/ace_routine/LogBinTableRenderer.h index 289b5a7..2b804f7 100644 --- a/src/ace_routine/LogBinTableRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -27,19 +27,54 @@ SOFTWARE. #include // uint8_t, uint32_t #include // Print -#include // printPad5To() #include "Coroutine.h" // Coroutine #include "LogBinProfiler.h" // rollupExteriorBins() namespace ace_routine { namespace internal { - /** Number of bins in LogBinProfiler. */ - const uint8_t kNumBinLabels = 32; - /** Labels for each bin in LogBinProfiler::mBins. */ - extern const char* const kBinLabels[kNumBinLabels] PROGMEM; -} +/** Number of bins in LogBinProfiler. */ +const uint8_t kNumBinLabels = 32; + +/** Labels for each bin in LogBinProfiler::mBins. */ +extern const char* const kBinLabels[kNumBinLabels] PROGMEM; + +/** + * Print the header related to this profiler. + * + * @param printer destination of output + * @param startBin start index of the bins (0-31) + * @param endBin end index (exclusive) of the bins (0-32) + */ +void printHeaderTo( Print& printer, uint8_t startBin, uint8_t endBin); + +/** + * Print string in PROGMEM into boxSize, right justified. The string is padded + * with spaces on the left if too short, and truncated on the right if too + * long. + */ +void printPStringTo(Print& printer, const char* s, uint8_t boxSize); + +/** + * Print the bins of this profiler as a single line of text with each bin + * printed as a 5-digit number in a 6-character box. If there are any remaining + * counts after the `endBin`, the cummulative sum of the remaining bins are + * printed in another 6-character box. + * + * @param printer usual `Serial` + * @param bins pointer to array of bins + * @param startBin start index of the bins (0-31) + * @param endBin end index (exclusive) of the bins (0-32) + */ +void printBinsTo( + Print& printer, + const uint16_t bins[], + uint8_t numBins, + uint8_t startBin, + uint8_t endBin); + +} // namespace internal /** * Print the information in the LogBinProfiler for each Coroutine @@ -59,9 +94,9 @@ namespace internal { * soundRoutine 1417 0 0 1 1 1 0 0 0 0 * @endverbatim * - * The bins below the startBin are rolled into the first bin. The bins above the - * (endBin-1) are rolled into the last bin with the label `>>`. There must be at - * least 2 rendering bins (endBin >= startBin + 2) otherwise nothing is printed. + * The bins below the first bin (at `startBin`) are rolled into the first bin. + * The bins above the last bin (at `endBin-1`) are rolled into the last bin and + * printed with the label `>>`. * * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, * usually `Coroutine` @@ -110,7 +145,7 @@ class LogBinRendererTemplate { // Print header if needed. if (! isHeaderPrinted) { printer.print(F("name ")); - printHeaderTo(printer, startBin, endBin); + internal::printHeaderTo(printer, startBin, endBin); printer.println(); isHeaderPrinted = true; } @@ -133,7 +168,8 @@ class LogBinRendererTemplate { // Print the bins. The number of digits is automatically a log10() of // the counts, so we should be able to visually scan the table and see // which coroutine is taking too long. - printBinsTo(printer, bins, Profiler::kNumBins, startBin, endBin); + internal::printBinsTo( + printer, bins, Profiler::kNumBins, startBin, endBin); printer.println(); if (clear) { @@ -142,67 +178,12 @@ class LogBinRendererTemplate { } } - private: - /** - * Print the header related to this profiler. - * - * @param printer destination of output - * @param startBin start index of the bins (0-31) - * @param endBin end index (exclusive) of the bins (0-32) - */ - static void printHeaderTo( - Print& printer, uint8_t startBin, uint8_t endBin) { - - endBin = (endBin > Profiler::kNumBins) ? Profiler::kNumBins : endBin; - if (endBin <= startBin) return; // needed if startBin = endBin = 0 - - for (uint8_t i = startBin; i < endBin - 1; i++) { - // These contortions are needed because the labels are stored in PROGMEM - // flash memory. - auto* label = (const char*) pgm_read_ptr(&internal::kBinLabels[i]); - uint8_t labelLength = strlen_P(label); - - // Print label right justified in a box of 6 characters. - for (uint8_t i = 0; i < (6 - labelLength); i++) { - printer.print(' '); - } - printer.print((const __FlashStringHelper*) label); - } - printer.print(F(" >>")); - } - - /** - * Print the bins of this profiler as a single line of text with each bin - * printed as a 5-digit number in a 6-character box. If there are any - * remaining counts after the `endBin`, the cummulative sum of the remaining - * bins are printed in another 6-character box. - * - * @param printer usual `Serial` - * @param bins pointer to array of bins - * @param startBin start index of the bins (0-31) - * @param endBin end index (exclusive) of the bins (0-32) - */ - static void printBinsTo( - Print& printer, - const uint16_t bins[], - uint8_t numBins, - uint8_t startBin, - uint8_t endBin) { - - endBin = (endBin > numBins) ? numBins : endBin; - for (uint8_t i = startBin; i < endBin; i++) { - uint16_t count = bins[i]; - printer.print(' '); - ace_common::printPad5To(printer, count); - } - } - private: T_COROUTINE** mRoot; }; using LogBinTableRenderer = LogBinRendererTemplate; -} +} // namespace ace_routine #endif From c4214bf191ac06883a76db138712e52e2ae164f7 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 09:05:54 -0700 Subject: [PATCH 36/59] MemoryBenchmark: Regenerate after printPStringTo(), virtual destructor on 32-bit processors, etc --- examples/MemoryBenchmark/README.md | 64 +++++++++++++-------------- examples/MemoryBenchmark/attiny.txt | 2 +- examples/MemoryBenchmark/esp32.txt | 46 +++++++++---------- examples/MemoryBenchmark/esp8266.txt | 4 +- examples/MemoryBenchmark/micro.txt | 2 +- examples/MemoryBenchmark/nano.txt | 2 +- examples/MemoryBenchmark/stm32.txt | 4 +- examples/MemoryBenchmark/teensy32.txt | 4 +- 8 files changed, 64 insertions(+), 64 deletions(-) diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index df115b7..0278c21 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -215,7 +215,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 1150/ 63 | 750/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 918/ 111 | 518/ 100 | -| Scheduler, LogBinTableRenderer | 2766/ 193 | 2366/ 182 | +| Scheduler, LogBinTableRenderer | 2792/ 193 | 2392/ 182 | | Scheduler, LogBinJsonRenderer | 2326/ 197 | 1926/ 186 | |---------------------------------------+--------------+-------------| | Blink Function | 546/ 14 | 146/ 3 | @@ -264,7 +264,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 1368/ 63 | 762/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 1134/ 111 | 528/ 100 | -| Scheduler, LogBinTableRenderer | 3340/ 304 | 2734/ 293 | +| Scheduler, LogBinTableRenderer | 3380/ 304 | 2774/ 293 | | Scheduler, LogBinJsonRenderer | 2900/ 308 | 2294/ 297 | |---------------------------------------+--------------+-------------| | Blink Function | 938/ 14 | 332/ 3 | @@ -313,7 +313,7 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 4256/ 203 | 702/ 52 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 4022/ 251 | 468/ 100 | -| Scheduler, LogBinTableRenderer | 5398/ 269 | 1844/ 118 | +| Scheduler, LogBinTableRenderer | 5438/ 269 | 1884/ 118 | | Scheduler, LogBinJsonRenderer | 4958/ 273 | 1404/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 3994/ 154 | 440/ 3 | @@ -362,8 +362,8 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 22344/ 3604 | 460/ 64 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 22300/ 3644 | 416/ 104 | -| Scheduler, LogBinTableRenderer | 23644/ 3644 | 1760/ 104 | -| Scheduler, LogBinJsonRenderer | 22968/ 3644 | 1084/ 104 | +| Scheduler, LogBinTableRenderer | 23708/ 3644 | 1824/ 104 | +| Scheduler, LogBinJsonRenderer | 23172/ 3644 | 1288/ 104 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | | Blink Coroutine | 22232/ 3568 | 348/ 28 | @@ -411,8 +411,8 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 260845/27984 | 516/ 68 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 260781/28024 | 452/ 108 | -| Scheduler, LogBinTableRenderer | 265489/28100 | 5160/ 184 | -| Scheduler, LogBinJsonRenderer | 265057/28104 | 4728/ 188 | +| Scheduler, LogBinTableRenderer | 265505/28100 | 5176/ 184 | +| Scheduler, LogBinJsonRenderer | 264913/28104 | 4584/ 188 | |---------------------------------------+--------------+-------------| | Blink Function | 261001/27988 | 672/ 72 | | Blink Coroutine | 261149/28016 | 820/ 100 | @@ -432,39 +432,39 @@ $ make README.md |---------------------------------------+--------------+-------------| | Baseline | 204573/16060 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 205017/16092 | 444/ 32 | -| Two Delay Functions | 205089/16092 | 516/ 32 | +| One Delay Function | 205137/16100 | 564/ 40 | +| Two Delay Functions | 205209/16100 | 636/ 40 | |---------------------------------------+--------------+-------------| -| One Coroutine | 205129/16124 | 556/ 64 | -| Two Coroutines | 205301/16148 | 728/ 88 | +| One Coroutine | 205249/16132 | 676/ 72 | +| Two Coroutines | 205421/16156 | 848/ 96 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 205117/16124 | 544/ 64 | -| Two Coroutines (micros) | 205289/16148 | 716/ 88 | +| One Coroutine (micros) | 205237/16132 | 664/ 72 | +| Two Coroutines (micros) | 205409/16156 | 836/ 96 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 205145/16124 | 572/ 64 | -| Two Coroutines (seconds) | 205333/16148 | 760/ 88 | +| One Coroutine (seconds) | 205265/16132 | 692/ 72 | +| Two Coroutines (seconds) | 205453/16156 | 880/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 205245/16124 | 672/ 64 | -| Scheduler, Two Coroutines | 205385/16156 | 812/ 96 | +| Scheduler, One Coroutine | 205365/16132 | 792/ 72 | +| Scheduler, Two Coroutines | 205505/16164 | 932/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 205221/16124 | 648/ 64 | -| Scheduler, Two Coroutines (micros) | 205361/16156 | 788/ 96 | +| Scheduler, One Coroutine (micros) | 205341/16132 | 768/ 72 | +| Scheduler, Two Coroutines (micros) | 205481/16164 | 908/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 205261/16124 | 688/ 64 | -| Scheduler, Two Coroutines (seconds) | 205417/16156 | 844/ 96 | +| Scheduler, One Coroutine (seconds) | 205381/16132 | 808/ 72 | +| Scheduler, Two Coroutines (seconds) | 205537/16164 | 964/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 205273/16124 | 700/ 64 | -| Scheduler, Two Coroutines (setup) | 205445/16156 | 872/ 96 | +| Scheduler, One Coroutine (setup) | 205393/16132 | 820/ 72 | +| Scheduler, Two Coroutines (setup) | 205565/16164 | 992/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 205265/16124 | 692/ 64 | -| Scheduler, Two Coroutines (man setup) | 205445/16156 | 872/ 96 | +| Scheduler, One Coroutine (man setup) | 205385/16132 | 812/ 72 | +| Scheduler, Two Coroutines (man setup) | 205565/16164 | 992/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 205361/16196 | 788/ 136 | -| Scheduler, LogBinTableRenderer | 210969/16276 | 6396/ 216 | -| Scheduler, LogBinJsonRenderer | 210489/16276 | 5916/ 216 | +| Scheduler, LogBinProfiler | 205481/16204 | 908/ 144 | +| Scheduler, LogBinTableRenderer | 210977/16284 | 6404/ 224 | +| Scheduler, LogBinJsonRenderer | 210425/16284 | 5852/ 224 | |---------------------------------------+--------------+-------------| -| Blink Function | 205369/16100 | 796/ 40 | -| Blink Coroutine | 205481/16124 | 908/ 64 | +| Blink Function | 205489/16108 | 916/ 48 | +| Blink Coroutine | 205601/16132 | 1028/ 72 | +--------------------------------------------------------------------+ ``` @@ -510,8 +510,8 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 10728/ 4216 | 496/ 64 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 10952/ 4264 | 720/ 112 | -| Scheduler, LogBinTableRenderer | 13800/ 4284 | 3568/ 132 | -| Scheduler, LogBinJsonRenderer | 13284/ 4284 | 3052/ 132 | +| Scheduler, LogBinTableRenderer | 14056/ 4284 | 3824/ 132 | +| Scheduler, LogBinJsonRenderer | 13348/ 4284 | 3116/ 132 | |---------------------------------------+--------------+-------------| | Blink Function | 10688/ 4160 | 456/ 8 | | Blink Coroutine | 10820/ 4184 | 588/ 32 | diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index cab6c18..a3e86a6 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -18,7 +18,7 @@ 17 860 8192 39 512 18 1150 8192 63 512 19 918 8192 111 512 -20 2766 8192 193 512 +20 2792 8192 193 512 21 2326 8192 197 512 22 546 8192 14 512 23 766 8192 37 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index c4972f8..0ac2a15 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -1,24 +1,24 @@ 0 204573 1310720 16060 327680 -1 205017 1310720 16092 327680 -2 205089 1310720 16092 327680 -3 205129 1310720 16124 327680 -4 205301 1310720 16148 327680 -5 205117 1310720 16124 327680 -6 205289 1310720 16148 327680 -7 205145 1310720 16124 327680 -8 205333 1310720 16148 327680 -9 205245 1310720 16124 327680 -10 205385 1310720 16156 327680 -11 205221 1310720 16124 327680 -12 205361 1310720 16156 327680 -13 205261 1310720 16124 327680 -14 205417 1310720 16156 327680 -15 205273 1310720 16124 327680 -16 205445 1310720 16156 327680 -17 205265 1310720 16124 327680 -18 205445 1310720 16156 327680 -19 205361 1310720 16196 327680 -20 210969 1310720 16276 327680 -21 210489 1310720 16276 327680 -22 205369 1310720 16100 327680 -23 205481 1310720 16124 327680 +1 205137 1310720 16100 327680 +2 205209 1310720 16100 327680 +3 205249 1310720 16132 327680 +4 205421 1310720 16156 327680 +5 205237 1310720 16132 327680 +6 205409 1310720 16156 327680 +7 205265 1310720 16132 327680 +8 205453 1310720 16156 327680 +9 205365 1310720 16132 327680 +10 205505 1310720 16164 327680 +11 205341 1310720 16132 327680 +12 205481 1310720 16164 327680 +13 205381 1310720 16132 327680 +14 205537 1310720 16164 327680 +15 205393 1310720 16132 327680 +16 205565 1310720 16164 327680 +17 205385 1310720 16132 327680 +18 205565 1310720 16164 327680 +19 205481 1310720 16204 327680 +20 210977 1310720 16284 327680 +21 210425 1310720 16284 327680 +22 205489 1310720 16108 327680 +23 205601 1310720 16132 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 44e3525..6a8ced2 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -18,7 +18,7 @@ 17 260669 1044464 27952 81920 18 260845 1044464 27984 81920 19 260781 1044464 28024 81920 -20 265489 1044464 28100 81920 -21 265057 1044464 28104 81920 +20 265505 1044464 28100 81920 +21 264913 1044464 28104 81920 22 261001 1044464 27988 81920 23 261149 1044464 28016 81920 diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index b745eb9..83e4a66 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -18,7 +18,7 @@ 17 3962 28672 179 2560 18 4256 28672 203 2560 19 4022 28672 251 2560 -20 5398 28672 269 2560 +20 5438 28672 269 2560 21 4958 28672 273 2560 22 3994 28672 154 2560 23 4164 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 7e84a36..6bb19c9 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -18,7 +18,7 @@ 17 1074 30720 39 2048 18 1368 30720 63 2048 19 1134 30720 111 2048 -20 3340 30720 304 2048 +20 3380 30720 304 2048 21 2900 30720 308 2048 22 938 30720 14 2048 23 1168 30720 37 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index fafbe4e..d213cdb 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -18,7 +18,7 @@ 17 22208 131072 3576 20480 18 22344 131072 3604 20480 19 22300 131072 3644 20480 -20 23644 131072 3644 20480 -21 22968 131072 3644 20480 +20 23708 131072 3644 20480 +21 23172 131072 3644 20480 22 22120 131072 3540 20480 23 22232 131072 3568 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 7e26fa4..30f1d54 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -18,7 +18,7 @@ 17 10580 262144 4188 65536 18 10728 262144 4216 65536 19 10952 262144 4264 65536 -20 13800 262144 4284 65536 -21 13284 262144 4284 65536 +20 14056 262144 4284 65536 +21 13348 262144 4284 65536 22 10688 262144 4160 65536 23 10820 262144 4184 65536 From f5c0fa3f1d63841da5ee2e6a1e8322c746e164ca Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 09:20:09 -0700 Subject: [PATCH 37/59] Coroutine.h: Merge setCName() and setFName() to overloaded setName() for easier usage --- CHANGELOG.md | 2 +- USER_GUIDE.md | 10 +++++----- examples/SoundManager/SoundManager.ino | 6 +++--- src/ace_routine/Coroutine.h | 17 ++++++++++------- tests/AceRoutineTest/AceRoutineTest.ino | 18 +++++++++++++++--- tests/SchedulerTest/SchedulerTest.ino | 4 ++-- 6 files changed, 36 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e32fd7e..b34fb80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ * Unreleased * (Re)add support for human-readable coroutine names by adding the following - methods to the `Coroutine` class: `setCName()`, `setFName()`, + methods to the `Coroutine` class: `setName()`, `setName()`, `getCName()`, `getFName()`, `getNameType()`, and `printNameTo()`. * This is an optional feature which helps debugging. Coroutines do not need to have human readable names. diff --git a/USER_GUIDE.md b/USER_GUIDE.md index bfc4c52..57672fc 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -263,8 +263,8 @@ class Coroutine { static const uint8_t kNameTypeFString = 1; public: - void Coroutine::setCName(const char* name); - void Coroutine::setFName(const __FlashStringHelper* name); + void Coroutine::setName(const char* name); + void Coroutine::setName(const __FlashStringHelper* name); const char* Coroutine::getCName() const; const __FlashStringHelper* Coroutine::getFName() const; @@ -274,8 +274,8 @@ class Coroutine { }; `` -It is expected that the `setCName()` or `setFName()` will be called in the -global `setup()` function. +It is expected that the `setName()` will be called in the global `setup()` +function. On most 32-bit processors, it makes little difference whether a C-string or an F-string is used. (The exception is the ESP8266.) On AVR processors, using the @@ -284,7 +284,7 @@ F-string will prevent those strings from consuming precious static RAM. The `printNameTo()` method prints the coroutine name to the given `Print` object, which will usually be the `Serial` object. If the name is not set (hence is the `nullptr`), `printNameTo()` will print the hexadecimal representation of -the pointer to the Coroutine (e.g. "0xe38a"). +the pointer to the Coroutine (e.g. "0xE38A"). The `CoroutineScheduler::list()` method will now print the coroutine name if it is defined. diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index 52e1e36..bf7f60f 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -89,12 +89,12 @@ void setup() { while (!Serial); // needed for Leonardo/Micro // Set names using both c-string and f-string for testing purposes. - soundRoutine.setCName("soundRoutine"); - soundManager.setFName(F("soundManager")); + soundRoutine.setName("soundRoutine"); + soundManager.setName(F("soundManager")); // Don't set the name of 'printProfiler' to verify that the name of the // coroutine becomes the pointer address in hexadecimal. - // printProfiler.setFName(F("printProfiler")); + // printProfiler.setName(F("printProfiler")); // Attach profilers to all coroutines. LogBinProfiler::createProfilers(Coroutine::getRoot()); diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index 3b0e0fd..8bf1443 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -348,19 +348,19 @@ class CoroutineTemplate { uint8_t getNameType() const { return mNameType; } /** Set the name of the coroutine to the given c-string. */ - void setCName(const char* name) { + void setName(const char* name) { mNameType = kNameTypeCString; mName = name; } /** Set the name of the coroutine to the given f-string. */ - void setFName(const __FlashStringHelper* name) { + void setName(const __FlashStringHelper* name) { mNameType = kNameTypeFString; - mName = (const char*) name; + mName = name; } /** Get name of the coroutine assuming it's a c-string. Nullable. */ - const char* getCName() const { return mName; } + const char* getCName() const { return (const char*) mName; } /** Get name of the coroutine assuming it's an f-string. Nullable. */ const __FlashStringHelper* getFName() const { @@ -384,7 +384,7 @@ class CoroutineTemplate { pname.print("0x"); pname.print((uintptr_t) this, 16); } else if (mNameType == kNameTypeCString) { - pname.print(mName); + pname.print((const char*) mName); } else { pname.print((const __FlashStringHelper*) mName); } @@ -772,8 +772,11 @@ class CoroutineTemplate { /** Address of the label used by the computed-goto. */ void* mJumpPoint = nullptr; - /** Name of the coroutine. (Optional) */ - const char* mName = nullptr; + /** + * Name of the coroutine, either (const char*) or (const + * __FlashStringHelper*). (Optional) + */ + const void* mName = nullptr; /** String type of the coroutine mName. */ uint8_t mNameType = kNameTypeCString; diff --git a/tests/AceRoutineTest/AceRoutineTest.ino b/tests/AceRoutineTest/AceRoutineTest.ino index 67e5b50..cf7c296 100644 --- a/tests/AceRoutineTest/AceRoutineTest.ino +++ b/tests/AceRoutineTest/AceRoutineTest.ino @@ -161,7 +161,7 @@ test(AceRoutineTest, macroCoroutine) { // --------------------------------------------------------------------------- test(AceRoutineTest, name_cstring) { - simpleCoroutine.setCName("simple"); + simpleCoroutine.setName("simple"); assertEqual(simpleCoroutine.getNameType(), Coroutine::kNameTypeCString); assertEqual(simpleCoroutine.getCName(), "simple"); @@ -171,7 +171,7 @@ test(AceRoutineTest, name_cstring) { } test(AceRoutineTest, name_fstring) { - simpleCoroutine.setFName(F("simple")); + simpleCoroutine.setName(F("simple")); assertEqual(simpleCoroutine.getNameType(), Coroutine::kNameTypeFString); assertEqual(simpleCoroutine.getFName(), F("simple")); @@ -181,7 +181,7 @@ test(AceRoutineTest, name_fstring) { } test(AceRoutineTest, name_nullptr) { - simpleCoroutine.setCName(nullptr); + simpleCoroutine.setName((const char*) nullptr); assertEqual(simpleCoroutine.getNameType(), Coroutine::kNameTypeCString); assertEqual(simpleCoroutine.getCName(), (const char*) nullptr); @@ -191,6 +191,18 @@ test(AceRoutineTest, name_nullptr) { assertEqual(strncmp(str.cstr(), "0x", 2), 0); } +test(AceRoutineTest, name_printTo_truncation_padding) { + simpleCoroutine.setName("simple"); + + PrintStr<16> str; + simpleCoroutine.printNameTo(str, 4); + assertEqual(str.cstr(), "simp"); + + str.flush(); + simpleCoroutine.printNameTo(str, 8); + assertEqual(str.cstr(), "simple "); +} + // --------------------------------------------------------------------------- void setup() { diff --git a/tests/SchedulerTest/SchedulerTest.ino b/tests/SchedulerTest/SchedulerTest.ino index 4b9fb57..62eb741 100644 --- a/tests/SchedulerTest/SchedulerTest.ino +++ b/tests/SchedulerTest/SchedulerTest.ino @@ -412,8 +412,8 @@ void setup() { extra.suspend(); // Set human-readable names to some coroutines. - a.setCName("coA"); - b.setFName(F("coB")); + a.setName("coA"); + b.setName(F("coB")); TestableCoroutineScheduler::setup(); } From e2eecedffe870cf69d0fd63eb2a0e7250c8ebc4e Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 10:21:39 -0700 Subject: [PATCH 38/59] examples: Add Hello{Coroutine,Scheduler}WithProfiler demo programs --- .../HelloCoroutineWithProfiler.ino | 123 ++++++++++++++++++ examples/HelloCoroutineWithProfiler/Makefile | 6 + .../HelloSchedulerWithProfiler.ino | 116 +++++++++++++++++ examples/HelloSchedulerWithProfiler/Makefile | 6 + 4 files changed, 251 insertions(+) create mode 100644 examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino create mode 100644 examples/HelloCoroutineWithProfiler/Makefile create mode 100644 examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino create mode 100644 examples/HelloSchedulerWithProfiler/Makefile diff --git a/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino b/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino new file mode 100644 index 0000000..1ccabd4 --- /dev/null +++ b/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino @@ -0,0 +1,123 @@ +/* +HelloCoroutineWithProfiler, a demo of the LogBinProfiler. This technique can be +used on resource constrained 8-bit environments which do not want to include the +overhead of the CoroutineScheduler. + +Every 5 seconds, the, following will be printed on the Serial monitor. + +**SparkFun Pro Micro** + +* flash/ram = 6840/457 + +``` +name <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms <8ms >> +0x1DB 16921 52650 0 0 0 0 0 0 0 0 1 +readPin 65535 1189 0 0 0 0 0 0 0 0 0 +blinkLed 65535 830 0 0 0 0 0 0 0 0 0 +{ +"0x1DB":[16921,52650,0,0,0,0,0,0,0,0,1], +"readPin":[65535,1189,0,0,0,0,0,0,0,0,0], +"blinkLed":[65535,830,0,0,0,0,0,0,0,0,0] +} +``` + +**ESP8266** + +``` +name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms >> +0x3FFEE4D0 65535 32 0 0 0 0 0 0 0 0 1 +readPin 65535 275 1 0 0 0 0 0 0 0 0 +blinkLed 65535 48 3 0 0 0 0 0 0 0 0 +{ +"0x3FFEE4D0":[65535,32,0,0,0,0,0,0,0,0,1], +"readPin":[65535,275,1,0,0,0,0,0,0,0,0], +"blinkLed":[65535,48,3,0,0,0,0,0,0,0,0] +} +``` +*/ + +#include +#include +using namespace ace_routine; + +#ifdef LED_BUILTIN + const int LED = LED_BUILTIN; +#else + // Some ESP32 boards do not define LED_BUILTIN. Sometimes they have more than + // 1. Replace this with the proper pin number. + const int LED = 5; +#endif + +const int PIN = 2; +const int LED_ON = HIGH; +const int LED_OFF = LOW; + +COROUTINE(blinkLed) { + COROUTINE_LOOP() { + digitalWrite(LED, LED_ON); + COROUTINE_DELAY(100); + digitalWrite(LED, LED_OFF); + COROUTINE_DELAY(500); + } +} + +COROUTINE(readPin) { + COROUTINE_LOOP() { + (void) digitalRead(PIN); + COROUTINE_DELAY(20); + } +} + +// A coroutine that prints the profiling information every 5 seconds. It will +// include information about itself. +COROUTINE(printProfiling) { + COROUTINE_LOOP() { + LogBinTableRenderer tableRenderer(Coroutine::getRoot()); + LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); + + #if defined(ARDUINO_ARCH_AVR) + tableRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); + jsonRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/); + #else + tableRenderer.printTo( + Serial, 2 /*startBin*/, 13 /*endBin*/, false /*clear*/); + jsonRenderer.printTo( + Serial, 2 /*startBin*/, 13 /*endBin*/); + #endif + + COROUTINE_DELAY(5000); + } +} + +LogBinProfiler profiler1; +LogBinProfiler profiler2; +LogBinProfiler profiler3; + +void setup() { +#if ! defined(EPOXY_DUINO) + delay(1000); +#endif + Serial.begin(115200); + while (!Serial); // Leonardo/Micro + + pinMode(LED, OUTPUT); + pinMode(PIN, INPUT); + + // Coroutine names can be either C-string or F-string. + blinkLed.setName("blinkLed"); + readPin.setName(F("readPin")); + + // Manually attach the profilers to the coroutines. Replaces + // LogBinProfilers::createProfilers(). + blinkLed.setProfiler(&profiler1); + readPin.setProfiler(&profiler2); + printProfiling.setProfiler(&profiler3); +} + +void loop() { + blinkLed.runCoroutineWithProfiler(); + readPin.runCoroutineWithProfiler(); + printProfiling.runCoroutineWithProfiler(); +} diff --git a/examples/HelloCoroutineWithProfiler/Makefile b/examples/HelloCoroutineWithProfiler/Makefile new file mode 100644 index 0000000..d817446 --- /dev/null +++ b/examples/HelloCoroutineWithProfiler/Makefile @@ -0,0 +1,6 @@ +# See https://github.com/bxparks/EpoxyDuino for documentation about this +# Makefile to compile and run Arduino programs natively on Linux or MacOS. + +APP_NAME := HelloCoroutineWithProfiler +ARDUINO_LIBS := AceCommon AceRoutine +include ../../../EpoxyDuino/EpoxyDuino.mk diff --git a/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino b/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino new file mode 100644 index 0000000..a7bb198 --- /dev/null +++ b/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino @@ -0,0 +1,116 @@ +/* +HelloSchedulerWithProfiler, a demo of the LogBinProfiler. The CoroutineScheduler +will automatically use the Profiler if it is defined on the Coroutine. + +Every 5 seconds, the following will be printed on the Serial monitor. + +**SparkFun Pro Micro** + +* flash/ram = 7454/271 + +``` +name <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms <8ms >> +0x1DB 16898 52688 0 0 0 0 0 0 0 0 1 +readPin 65535 1128 0 0 0 0 0 0 0 0 0 +blinkLed 65535 800 0 0 0 0 0 0 0 0 0 +{ +"0x1DB":[16898,52688,0,0,0,0,0,0,0,0,1], +"readPin":[65535,1128,0,0,0,0,0,0,0,0,0], +"blinkLed":[65535,800,0,0,0,0,0,0,0,0,0] +} +``` + +**ESP8266** + +``` +name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms >> +0x3FFEE4D0 65535 37 2 0 0 0 0 0 0 0 1 +readPin 65535 274 0 0 0 0 0 0 0 0 0 +blinkLed 65535 47 0 0 0 0 0 0 0 0 0 +{ +"0x3FFEE4D0":[65535,37,2,0,0,0,0,0,0,0,1], +"readPin":[65535,274,0,0,0,0,0,0,0,0,0], +"blinkLed":[65535,47,0,0,0,0,0,0,0,0,0] +} +``` +*/ + +#include +#include +using namespace ace_routine; + +#ifdef LED_BUILTIN + const int LED = LED_BUILTIN; +#else + // Some ESP32 boards do not define LED_BUILTIN. Sometimes they have more than + // 1. Replace this with the proper pin number. + const int LED = 5; +#endif + +const int PIN = 2; +const int LED_ON = HIGH; +const int LED_OFF = LOW; + +COROUTINE(blinkLed) { + COROUTINE_LOOP() { + digitalWrite(LED, LED_ON); + COROUTINE_DELAY(100); + digitalWrite(LED, LED_OFF); + COROUTINE_DELAY(500); + } +} + +COROUTINE(readPin) { + COROUTINE_LOOP() { + (void) digitalRead(PIN); + COROUTINE_DELAY(20); + } +} + +// A coroutine that prints the profiling information every 5 seconds. It will +// include information about itself. +COROUTINE(printProfiling) { + COROUTINE_LOOP() { + LogBinTableRenderer tableRenderer(Coroutine::getRoot()); + LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); + + #if defined(ARDUINO_ARCH_AVR) + tableRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); + jsonRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/); + #else + tableRenderer.printTo( + Serial, 2 /*startBin*/, 13 /*endBin*/, false /*clear*/); + jsonRenderer.printTo( + Serial, 2 /*startBin*/, 13 /*endBin*/); + #endif + + COROUTINE_DELAY(5000); + } +} + +void setup() { +#if ! defined(EPOXY_DUINO) + delay(1000); +#endif + Serial.begin(115200); + while (!Serial); // Leonardo/Micro + + pinMode(LED, OUTPUT); + pinMode(PIN, INPUT); + + // Coroutine names can be either C-string or F-string. + blinkLed.setName("blinkLed"); + readPin.setName(F("readPin")); + + // Create a profiler on the heap for every coroutine. + LogBinProfiler::createProfilers(Coroutine::getRoot()); + + // Setup the scheduler. + CoroutineScheduler::setup(); +} + +void loop() { + CoroutineScheduler::loop(); +} diff --git a/examples/HelloSchedulerWithProfiler/Makefile b/examples/HelloSchedulerWithProfiler/Makefile new file mode 100644 index 0000000..f4e7fbe --- /dev/null +++ b/examples/HelloSchedulerWithProfiler/Makefile @@ -0,0 +1,6 @@ +# See https://github.com/bxparks/EpoxyDuino for documentation about this +# Makefile to compile and run Arduino programs natively on Linux or MacOS. + +APP_NAME := HelloSchedulerWithProfiler +ARDUINO_LIBS := AceCommon AceRoutine +include ../../../EpoxyDuino/EpoxyDuino.mk From ad91f63ec805ec7ef48e6b49dad870749d851582 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 10:26:38 -0700 Subject: [PATCH 39/59] libraries.properties: (Re)add dependency to AceCommon library --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 5ad1c40..ece52b7 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,4 @@ paragraph=Supported macros include COROUTINE(), COROUTINE_BEGIN(), COROUTINE_YIE category=Other url=https://github.com/bxparks/AceRoutine architectures=* -depends= +depends=AceCommon From 6064073c1dac35ad2cb62e541b3fa28987baf46f Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 10:39:23 -0700 Subject: [PATCH 40/59] examples/SoundManager: Remove profiling code; demo code moved to Hello{Coroutine,Scheduler}WithProfiler instead --- examples/SoundManager/SoundManager.ino | 49 ++------------------------ 1 file changed, 3 insertions(+), 46 deletions(-) diff --git a/examples/SoundManager/SoundManager.ino b/examples/SoundManager/SoundManager.ino index bf7f60f..0e9ff8b 100644 --- a/examples/SoundManager/SoundManager.ino +++ b/examples/SoundManager/SoundManager.ino @@ -21,30 +21,12 @@ * Coroutine soundManager; status: Running * First BEEP * Second BEEP - * name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> - * soundManager 1440 0 1 0 0 0 0 0 1 0 - * 0x55C5AB3CE2 1438 1 2 0 0 0 0 0 0 1 - * soundRoutine 1440 0 0 0 2 0 0 0 0 0 - * { - * "soundManager":[1440,0,1,0,0,0,0,0,1,0], - * "0x55C5AB3CE240":[1438,1,2,0,0,0,0,0,0,1], - * "soundRoutine":[1440,0,0,0,2,0,0,0,0,0] - * } * * Request Boop and wait 5 seconds... * Coroutine soundRoutine; status: Yielding * Coroutine soundManager; status: Running * First BOOP * Second BOOP - * name <8us <16us <32us <64us<128us<256us<512us <1ms <2ms >> - * soundManager 1440 0 1 0 0 0 0 0 1 0 - * 0x55C5AB3CE2 1438 1 2 0 0 0 0 0 0 1 - * soundRoutine 1440 0 0 0 2 0 0 0 0 0 - * { - * "soundManager":[1440,0,1,0,0,0,0,0,1,0], - * "0x55C5AB3CE240":[1438,1,2,0,0,0,0,0,0,1], - * "soundRoutine":[1440,0,0,0,2,0,0,0,0,0] - * } * * Request Silence and wait 5 seconds... * Coroutine soundRoutine; status: Yielding @@ -60,45 +42,20 @@ #include #include "SoundRoutine.h" -using ace_routine::Coroutine;; using ace_routine::CoroutineScheduler; -using ace_routine::LogBinProfiler; -using ace_routine::LogBinTableRenderer; -using ace_routine::LogBinJsonRenderer; -SoundRoutine soundRoutine; EXTERN_COROUTINE(soundManager); - -// Every 5 seconds, print out the elapsed time frequency distribution from the -// LogBinProfiler. -COROUTINE(printProfiler) { - COROUTINE_LOOP() { - LogBinTableRenderer tableRenderer(getRoot()); - tableRenderer.printTo(Serial, 2, 12, false /*clear*/); - - LogBinJsonRenderer jsonRenderer(getRoot()); - jsonRenderer.printTo(Serial, 2, 12); - - COROUTINE_DELAY_SECONDS(5); - } -} +SoundRoutine soundRoutine; void setup() { delay(1000); Serial.begin(115200); while (!Serial); // needed for Leonardo/Micro - // Set names using both c-string and f-string for testing purposes. - soundRoutine.setName("soundRoutine"); + // Coroutine name can be ether C-string or F-string. + soundRoutine.setName("soundRoutine"); soundManager.setName(F("soundManager")); - // Don't set the name of 'printProfiler' to verify that the name of the - // coroutine becomes the pointer address in hexadecimal. - // printProfiler.setName(F("printProfiler")); - - // Attach profilers to all coroutines. - LogBinProfiler::createProfilers(Coroutine::getRoot()); - CoroutineScheduler::setup(); } From d7a4f80e36e97476af02ad8e7448a06236106a84 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 13:49:30 -0700 Subject: [PATCH 41/59] LogBinJsonRenderer,LogBinTableRenderer: Convert printTo() into static functions; implicitly assume T_COROUTINE::getRoot(), just like CoroutineScheduler --- .../HelloCoroutineWithProfiler.ino | 11 +++---- .../HelloSchedulerWithProfiler.ino | 13 ++++----- examples/MemoryBenchmark/MemoryBenchmark.ino | 6 ++-- examples/MemoryBenchmark/README.md | 4 +-- examples/MemoryBenchmark/stm32.txt | 4 +-- src/ace_routine/Coroutine.h | 1 + src/ace_routine/LogBinJsonRenderer.h | 13 ++------- src/ace_routine/LogBinProfiler.h | 29 ++++++++++--------- src/ace_routine/LogBinTableRenderer.h | 13 ++------- 9 files changed, 38 insertions(+), 56 deletions(-) diff --git a/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino b/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino index 1ccabd4..825d6b9 100644 --- a/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino +++ b/examples/HelloCoroutineWithProfiler/HelloCoroutineWithProfiler.ino @@ -72,18 +72,15 @@ COROUTINE(readPin) { // include information about itself. COROUTINE(printProfiling) { COROUTINE_LOOP() { - LogBinTableRenderer tableRenderer(Coroutine::getRoot()); - LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); - #if defined(ARDUINO_ARCH_AVR) - tableRenderer.printTo( + LogBinTableRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); - jsonRenderer.printTo( + LogBinJsonRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/); #else - tableRenderer.printTo( + LogBinTableRenderer::printTo( Serial, 2 /*startBin*/, 13 /*endBin*/, false /*clear*/); - jsonRenderer.printTo( + LogBinJsonRenderer::printTo( Serial, 2 /*startBin*/, 13 /*endBin*/); #endif diff --git a/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino b/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino index a7bb198..6bb4b56 100644 --- a/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino +++ b/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino @@ -71,18 +71,15 @@ COROUTINE(readPin) { // include information about itself. COROUTINE(printProfiling) { COROUTINE_LOOP() { - LogBinTableRenderer tableRenderer(Coroutine::getRoot()); - LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); - #if defined(ARDUINO_ARCH_AVR) - tableRenderer.printTo( + LogBinTableRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); - jsonRenderer.printTo( + LogBinJsonRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/); #else - tableRenderer.printTo( + LogBinTableRenderer::printTo( Serial, 2 /*startBin*/, 13 /*endBin*/, false /*clear*/); - jsonRenderer.printTo( + LogBinJsonRenderer::printTo( Serial, 2 /*startBin*/, 13 /*endBin*/); #endif @@ -105,7 +102,7 @@ void setup() { readPin.setName(F("readPin")); // Create a profiler on the heap for every coroutine. - LogBinProfiler::createProfilers(Coroutine::getRoot()); + LogBinProfiler::createProfilers(); // Setup the scheduler. CoroutineScheduler::setup(); diff --git a/examples/MemoryBenchmark/MemoryBenchmark.ino b/examples/MemoryBenchmark/MemoryBenchmark.ino index 1ac57e9..b426fbc 100644 --- a/examples/MemoryBenchmark/MemoryBenchmark.ino +++ b/examples/MemoryBenchmark/MemoryBenchmark.ino @@ -552,12 +552,10 @@ void loop() { CoroutineScheduler::loop(); #elif FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER CoroutineScheduler::loop(); - LogBinTableRenderer renderer(Coroutine::getRoot()); - renderer.printTo(Serial, 0, 32); + LogBinTableRenderer::printTo(Serial, 0, 32); #elif FEATURE == FEATURE_LOG_BIN_JSON_RENDERER CoroutineScheduler::loop(); - LogBinJsonRenderer renderer(Coroutine::getRoot()); - renderer.printTo(Serial, 0, 32); + LogBinJsonRenderer::printTo(Serial, 0, 32); #elif FEATURE == FEATURE_BLINK_COROUTINE blink.runCoroutine(); #elif FEATURE == FEATURE_BLINK_FUNCTION diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 0278c21..cbecacf 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -362,8 +362,8 @@ $ make README.md | Scheduler, Two Coroutines (man setup) | 22344/ 3604 | 460/ 64 | |---------------------------------------+--------------+-------------| | Scheduler, LogBinProfiler | 22300/ 3644 | 416/ 104 | -| Scheduler, LogBinTableRenderer | 23708/ 3644 | 1824/ 104 | -| Scheduler, LogBinJsonRenderer | 23172/ 3644 | 1288/ 104 | +| Scheduler, LogBinTableRenderer | 23704/ 3644 | 1820/ 104 | +| Scheduler, LogBinJsonRenderer | 23164/ 3644 | 1280/ 104 | |---------------------------------------+--------------+-------------| | Blink Function | 22120/ 3540 | 236/ 0 | | Blink Coroutine | 22232/ 3568 | 348/ 28 | diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index d213cdb..0cf52ec 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -18,7 +18,7 @@ 17 22208 131072 3576 20480 18 22344 131072 3604 20480 19 22300 131072 3644 20480 -20 23708 131072 3644 20480 -21 23172 131072 3644 20480 +20 23704 131072 3644 20480 +21 23164 131072 3644 20480 22 22120 131072 3540 20480 23 22232 131072 3568 20480 diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index 8bf1443..bdd00b7 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -534,6 +534,7 @@ class CoroutineTemplate { /** Set the profiler. */ void setProfiler(CoroutineProfiler* profiler) { mProfiler = profiler; } + /** Get the profiler. Nullable. */ CoroutineProfiler* getProfiler() const { return mProfiler; } /** diff --git a/src/ace_routine/LogBinJsonRenderer.h b/src/ace_routine/LogBinJsonRenderer.h index 3a81ff4..c39a14e 100644 --- a/src/ace_routine/LogBinJsonRenderer.h +++ b/src/ace_routine/LogBinJsonRenderer.h @@ -50,11 +50,6 @@ class LogBinJsonRendererTemplate { /** Typedef of the LogBinProfiler supported by this class. */ using Profiler = LogBinProfilerTemplate; - /** Constructor. */ - LogBinJsonRendererTemplate(T_COROUTINE** root) - : mRoot(root) - {} - /** * Loop over all coroutines and print the bin counts as JSON. * @@ -66,7 +61,7 @@ class LogBinJsonRendererTemplate { * @param rollup roll-up exterior bins into the first and last bins * (default true) */ - void printTo( + static void printTo( Print& printer, uint8_t startBin, uint8_t endBin, @@ -77,7 +72,8 @@ class LogBinJsonRendererTemplate { printer.println('{'); bool lineNeedsTrailingComma = false; - for (Coroutine** p = mRoot; (*p) != nullptr; p = (*p)->getNext()) { + T_COROUTINE** root = T_COROUTINE::getRoot(); + for (T_COROUTINE** p = root; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = (Profiler*) (*p)->getProfiler(); if (! profiler) continue; @@ -113,9 +109,6 @@ class LogBinJsonRendererTemplate { printer.println(); printer.println('}'); } - - public: - T_COROUTINE** mRoot; }; using LogBinJsonRenderer = LogBinJsonRendererTemplate; diff --git a/src/ace_routine/LogBinProfiler.h b/src/ace_routine/LogBinProfiler.h index 568f60f..f78aa54 100644 --- a/src/ace_routine/LogBinProfiler.h +++ b/src/ace_routine/LogBinProfiler.h @@ -87,28 +87,30 @@ class LogBinProfilerTemplate : public CoroutineProfiler { } /** - * Create a new profiler on the heap and attach it to each coroutine in the - * singly-linked list of coroutines defined by `root`. If the coroutine has - * an existing profiler attached to it, the previous profiler is simply - * replaced, but *not* deleted. The reason is that the previous profiler - * could have been created statically, instead of on the heap, and we - * would crash the program if we tried to call `delete` on that pointer. + * Create a new profiler on the heap and attach it to each coroutine. + * If the coroutine has an existing profiler attached to it, the previous + * profiler is simply replaced, but *not* deleted. The reason is that the + * previous profiler could have been created statically, instead of on the + * heap, and we would crash the program if we tried to call `delete` on that + * pointer. * * If createProfilers() is called twice within the same application, (which * should rarely happen), the program must ensure that deleteProfilers() is * called before the second call to createProfilers(). Otherwise, heap * memory will be leaked. */ - static void createProfilers(T_COROUTINE** root) { - for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + static void createProfilers() { + T_COROUTINE** root = T_COROUTINE::getRoot(); + for (T_COROUTINE** p = root; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = new LogBinProfilerTemplate(); (*p)->setProfiler(profiler); } } /** Delete the profilers created by createProfilers(). */ - static void deleteProfilers(T_COROUTINE** root) { - for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + static void deleteProfilers() { + T_COROUTINE** root = T_COROUTINE::getRoot(); + for (T_COROUTINE** p = root; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = (LogBinProfilerTemplate*) (*p)->getProfiler(); if (profiler) { delete profiler; @@ -117,9 +119,10 @@ class LogBinProfilerTemplate : public CoroutineProfiler { } } - /** Clear counters for all profilers in the coroutines defined by `root`. */ - static void clearProfilers(T_COROUTINE** root) { - for (Coroutine** p = root; (*p) != nullptr; p = (*p)->getNext()) { + /** Clear counters for all profilers. */ + static void clearProfilers() { + T_COROUTINE** root = T_COROUTINE::getRoot(); + for (T_COROUTINE** p = root; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = (LogBinProfilerTemplate*) (*p)->getProfiler(); if (profiler) { profiler->clear(); diff --git a/src/ace_routine/LogBinTableRenderer.h b/src/ace_routine/LogBinTableRenderer.h index 2b804f7..3f6d394 100644 --- a/src/ace_routine/LogBinTableRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -107,11 +107,6 @@ class LogBinRendererTemplate { /** Typedef of the LogBinProfiler supported by this class. */ using Profiler = LogBinProfilerTemplate; - /** Constructor. */ - LogBinRendererTemplate(T_COROUTINE** root) - : mRoot(root) - {} - /** * Loop over all coroutines and print the ASCII version of the frequency * distribution. This assumes that all the coroutines are using the same @@ -126,7 +121,7 @@ class LogBinRendererTemplate { * @param rollup roll-up exterior bins into the first and last bins * (default true) */ - void printTo( + static void printTo( Print& printer, uint8_t startBin, uint8_t endBin, @@ -138,7 +133,8 @@ class LogBinRendererTemplate { uint16_t bufBins[Profiler::kNumBins]; bool isHeaderPrinted = false; - for (Coroutine** p = mRoot; (*p) != nullptr; p = (*p)->getNext()) { + T_COROUTINE** root = T_COROUTINE::getRoot(); + for (T_COROUTINE** p = root; (*p) != nullptr; p = (*p)->getNext()) { auto* profiler = (Profiler*) (*p)->getProfiler(); if (! profiler) continue; @@ -177,9 +173,6 @@ class LogBinRendererTemplate { } } } - - private: - T_COROUTINE** mRoot; }; using LogBinTableRenderer = LogBinRendererTemplate; From d16204e11adf08133b417549296ae85d76c7da6b Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 14:41:06 -0700 Subject: [PATCH 42/59] LogBinTableRenderer.h: Rename straggers from LogBinRenderer to LogBinTableRenderer --- src/ace_routine/LogBinProfiler.h | 9 ++++++--- src/ace_routine/LogBinTableRenderer.h | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ace_routine/LogBinProfiler.h b/src/ace_routine/LogBinProfiler.h index f78aa54..6b3deed 100644 --- a/src/ace_routine/LogBinProfiler.h +++ b/src/ace_routine/LogBinProfiler.h @@ -40,9 +40,12 @@ namespace ace_routine { * to a given coroutine through the `Coroutine::setProfiler()` method. * * After sufficient number of samples are collected, the frequency distribution - * of all profilers for all coroutines can be printed by a renderer. An - * implementation of such a render is `LogBinRendererTemplate` - * which prints the frequency distribution as a formatted table. + * of all profilers for all coroutines can be printed by a renderer. Two + * renderer are provided: + * + * * `LogBinTableRenderer` which prints the frequency distribution as a + * formatted table. + * * `LogBinJsonRenderer` which prints the info as a JSON object * * @tparam T_COROUTINE class of the specific CoroutineTemplate instantiation, * usually `Coroutine` diff --git a/src/ace_routine/LogBinTableRenderer.h b/src/ace_routine/LogBinTableRenderer.h index 3f6d394..274691b 100644 --- a/src/ace_routine/LogBinTableRenderer.h +++ b/src/ace_routine/LogBinTableRenderer.h @@ -102,7 +102,7 @@ void printBinsTo( * usually `Coroutine` */ template -class LogBinRendererTemplate { +class LogBinTableRendererTemplate { public: /** Typedef of the LogBinProfiler supported by this class. */ using Profiler = LogBinProfilerTemplate; @@ -175,7 +175,7 @@ class LogBinRendererTemplate { } }; -using LogBinTableRenderer = LogBinRendererTemplate; +using LogBinTableRenderer = LogBinTableRendererTemplate; } // namespace ace_routine From 819cb328fd437a278a64c1cdaa5742eabfb14ab5 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 15:13:36 -0700 Subject: [PATCH 43/59] MemoryBenchmark: Subtract overhead of 'Serial' object from LogBin*Renderer numbers --- examples/MemoryBenchmark/MemoryBenchmark.ino | 33 +- examples/MemoryBenchmark/README.md | 345 ++++++++++--------- examples/MemoryBenchmark/attiny.txt | 48 +-- examples/MemoryBenchmark/esp32.txt | 48 +-- examples/MemoryBenchmark/esp8266.txt | 48 +-- examples/MemoryBenchmark/generate_readme.py | 9 +- examples/MemoryBenchmark/generate_table.awk | 12 +- examples/MemoryBenchmark/micro.txt | 48 +-- examples/MemoryBenchmark/nano.txt | 48 +-- examples/MemoryBenchmark/stm32.txt | 48 +-- examples/MemoryBenchmark/teensy32.txt | 48 +-- 11 files changed, 374 insertions(+), 361 deletions(-) diff --git a/examples/MemoryBenchmark/MemoryBenchmark.ino b/examples/MemoryBenchmark/MemoryBenchmark.ino index b426fbc..d114c1a 100644 --- a/examples/MemoryBenchmark/MemoryBenchmark.ino +++ b/examples/MemoryBenchmark/MemoryBenchmark.ino @@ -18,14 +18,14 @@ #define FEATURE_BASELINE 0 #define FEATURE_ONE_DELAY_FUNCTION 1 #define FEATURE_TWO_DELAY_FUNCTIONS 2 -#define FEATURE_ONE_COROUTINE 3 -#define FEATURE_TWO_COROUTINES 4 +#define FEATURE_ONE_COROUTINE_MILLIS 3 +#define FEATURE_TWO_COROUTINES_MILLIS 4 #define FEATURE_ONE_COROUTINE_MICROS 5 #define FEATURE_TWO_COROUTINES_MICROS 6 #define FEATURE_ONE_COROUTINE_SECONDS 7 #define FEATURE_TWO_COROUTINES_SECONDS 8 -#define FEATURE_SCHEDULER_ONE_COROUTINE 9 -#define FEATURE_SCHEDULER_TWO_COROUTINES 10 +#define FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS 9 +#define FEATURE_SCHEDULER_TWO_COROUTINES_MILLIS 10 #define FEATURE_SCHEDULER_ONE_COROUTINE_MICROS 11 #define FEATURE_SCHEDULER_TWO_COROUTINES_MICROS 12 #define FEATURE_SCHEDULER_ONE_COROUTINE_SECONDS 13 @@ -90,7 +90,7 @@ volatile int disableCompilerOptimization = 0; } } -#elif FEATURE == FEATURE_ONE_COROUTINE +#elif FEATURE == FEATURE_ONE_COROUTINE_MILLIS COROUTINE(a) { COROUTINE_LOOP() { @@ -99,7 +99,7 @@ volatile int disableCompilerOptimization = 0; } } -#elif FEATURE == FEATURE_TWO_COROUTINES +#elif FEATURE == FEATURE_TWO_COROUTINES_MILLIS COROUTINE(a) { COROUTINE_LOOP() { @@ -165,7 +165,7 @@ volatile int disableCompilerOptimization = 0; } } -#elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE +#elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS class MyCoroutine : public Coroutine { public: @@ -179,7 +179,7 @@ volatile int disableCompilerOptimization = 0; MyCoroutine a; -#elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES +#elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES_MILLIS class MyCoroutineA : public Coroutine { public: @@ -472,13 +472,19 @@ volatile int disableCompilerOptimization = 0; void setup() { delay(1000); + // Include the `Serial` in the baseline, so that it will be subtracted out + // for LogBinTableRenderer and LogBinJsonRenderer. Otherwise, those numbers + // include the overhead of the `Serial` object. + Serial.begin(115200); + Serial.write(disableCompilerOptimization); + #if defined(TEENSYDUINO) // Force Teensy to bring in malloc(), free() and other things for virtual // dispatch. foo = new FooClass(); #endif -#if FEATURE >= FEATURE_SCHEDULER_ONE_COROUTINE \ +#if FEATURE >= FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS \ && FEATURE <= FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES CoroutineScheduler::setup(); @@ -513,9 +519,9 @@ void loop() { #elif FEATURE == FEATURE_TWO_DELAY_FUNCTIONS delayFunctionA(); delayFunctionB(); -#elif FEATURE == FEATURE_ONE_COROUTINE +#elif FEATURE == FEATURE_ONE_COROUTINE_MILLIS a.runCoroutine(); -#elif FEATURE == FEATURE_TWO_COROUTINES +#elif FEATURE == FEATURE_TWO_COROUTINES_MILLIS a.runCoroutine(); b.runCoroutine(); #elif FEATURE == FEATURE_ONE_COROUTINE_MICROS @@ -528,9 +534,9 @@ void loop() { #elif FEATURE == FEATURE_TWO_COROUTINES_SECONDS a.runCoroutine(); b.runCoroutine(); -#elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE +#elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS CoroutineScheduler::loop(); -#elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES +#elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES_MILLIS CoroutineScheduler::loop(); #elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_MICROS CoroutineScheduler::loop(); @@ -550,6 +556,7 @@ void loop() { CoroutineScheduler::loop(); #elif FEATURE == FEATURE_LOG_BIN_PROFILER CoroutineScheduler::loop(); + disableCompilerOptimization = profiler.mBins[3]; #elif FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER CoroutineScheduler::loop(); LogBinTableRenderer::printTo(Serial, 0, 32); diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index cbecacf..588e716 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -109,15 +109,18 @@ calculated flash size can jump around in unexpected ways. * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per coroutine. * Support `CoroutineProfiler` in the `CoroutineScheduler`. - * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes + * Increases the flash size of the `CoroutineScheduler` by 90-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. * Add `LogBinProfiler` * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. + * Adds about 140 bytes of flash and 70 bytes of RAM on ESP8266. * Add `LogBinTableRenderer` - * Adds about 2200 bytes of flash and 200 bytes of RAM on AVR. + * Adds about 1400 bytes of flash and ~20 bytes of RAM on AVR. + * Adds about 1900 bytes of flash and ~0 bytes of RAM on ESP8266. * Add `LogBinJsonRenderer` - * Adds about 1800 bytes of flash and 200 bytes of RAM on AVR. + * Adds about 900 bytes of flash and ~20 bytes of RAM on AVR. + * Adds about 1300 bytes of flash and ~0 bytes of RAM on ESP8266. ## How to Generate @@ -185,41 +188,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 400/ 11 | 0/ 0 | +| Baseline | 1026/ 81 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 450/ 13 | 50/ 2 | -| Two Delay Functions | 508/ 15 | 108/ 4 | +| One Delay Function | 1080/ 83 | 54/ 2 | +| Two Delay Functions | 1134/ 85 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 642/ 37 | 242/ 26 | -| Two Coroutines | 834/ 61 | 434/ 50 | +| One Coroutine (millis) | 1206/ 107 | 180/ 26 | +| Two Coroutines (millis) | 1400/ 131 | 374/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 610/ 37 | 210/ 26 | -| Two Coroutines (micros) | 770/ 61 | 370/ 50 | +| One Coroutine (micros) | 1174/ 107 | 148/ 26 | +| Two Coroutines (micros) | 1336/ 131 | 310/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 738/ 37 | 338/ 26 | -| Two Coroutines (seconds) | 958/ 61 | 558/ 50 | +| One Coroutine (seconds) | 1302/ 107 | 276/ 26 | +| Two Coroutines (seconds) | 1524/ 131 | 498/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 830/ 39 | 430/ 28 | -| Scheduler, Two Coroutines | 1016/ 63 | 616/ 52 | +| Scheduler, One Coroutine (millis) | 1396/ 109 | 370/ 28 | +| Scheduler, Two Coroutines (millis) | 1582/ 133 | 556/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 798/ 39 | 398/ 28 | -| Scheduler, Two Coroutines (micros) | 952/ 63 | 552/ 52 | +| Scheduler, One Coroutine (micros) | 1364/ 109 | 338/ 28 | +| Scheduler, Two Coroutines (micros) | 1518/ 133 | 492/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 926/ 39 | 526/ 28 | -| Scheduler, Two Coroutines (seconds) | 1140/ 63 | 740/ 52 | +| Scheduler, One Coroutine (seconds) | 1492/ 109 | 466/ 28 | +| Scheduler, Two Coroutines (seconds) | 1706/ 133 | 680/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 880/ 39 | 480/ 28 | -| Scheduler, Two Coroutines (setup) | 1162/ 63 | 762/ 52 | +| Scheduler, One Coroutine (setup) | 1446/ 109 | 420/ 28 | +| Scheduler, Two Coroutines (setup) | 1728/ 133 | 702/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 860/ 39 | 460/ 28 | -| Scheduler, Two Coroutines (man setup) | 1150/ 63 | 750/ 52 | +| Scheduler, One Coroutine (man setup) | 1424/ 109 | 398/ 28 | +| Scheduler, Two Coroutines (man setup) | 1714/ 133 | 688/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 918/ 111 | 518/ 100 | -| Scheduler, LogBinTableRenderer | 2792/ 193 | 2392/ 182 | -| Scheduler, LogBinJsonRenderer | 2326/ 197 | 1926/ 186 | +| Scheduler, LogBinProfiler | 1500/ 181 | 474/ 100 | +| Scheduler, LogBinTableRenderer | 2864/ 193 | 1838/ 112 | +| Scheduler, LogBinJsonRenderer | 2398/ 197 | 1372/ 116 | |---------------------------------------+--------------+-------------| -| Blink Function | 546/ 14 | 146/ 3 | -| Blink Coroutine | 766/ 37 | 366/ 26 | +| Blink Function | 1176/ 84 | 150/ 3 | +| Blink Coroutine | 1330/ 107 | 304/ 26 | +--------------------------------------------------------------------+ ``` @@ -234,41 +237,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 606/ 11 | 0/ 0 | +| Baseline | 1616/ 186 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 654/ 13 | 48/ 2 | -| Two Delay Functions | 714/ 15 | 108/ 4 | +| One Delay Function | 1664/ 188 | 48/ 2 | +| Two Delay Functions | 1726/ 190 | 110/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 854/ 37 | 248/ 26 | -| Two Coroutines | 1048/ 61 | 442/ 50 | +| One Coroutine (millis) | 1804/ 212 | 188/ 26 | +| Two Coroutines (millis) | 1998/ 236 | 382/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 826/ 37 | 220/ 26 | -| Two Coroutines (micros) | 992/ 61 | 386/ 50 | +| One Coroutine (micros) | 1776/ 212 | 160/ 26 | +| Two Coroutines (micros) | 1942/ 236 | 326/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 954/ 37 | 348/ 26 | -| Two Coroutines (seconds) | 1180/ 61 | 574/ 50 | +| One Coroutine (seconds) | 1904/ 212 | 288/ 26 | +| Two Coroutines (seconds) | 2130/ 236 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 1042/ 39 | 436/ 28 | -| Scheduler, Two Coroutines | 1228/ 63 | 622/ 52 | +| Scheduler, One Coroutine (millis) | 1992/ 214 | 376/ 28 | +| Scheduler, Two Coroutines (millis) | 2178/ 238 | 562/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 1014/ 39 | 408/ 28 | -| Scheduler, Two Coroutines (micros) | 1172/ 63 | 566/ 52 | +| Scheduler, One Coroutine (micros) | 1964/ 214 | 348/ 28 | +| Scheduler, Two Coroutines (micros) | 2122/ 238 | 506/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 1142/ 39 | 536/ 28 | -| Scheduler, Two Coroutines (seconds) | 1360/ 63 | 754/ 52 | +| Scheduler, One Coroutine (seconds) | 2092/ 214 | 476/ 28 | +| Scheduler, Two Coroutines (seconds) | 2310/ 238 | 694/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 1096/ 39 | 490/ 28 | -| Scheduler, Two Coroutines (setup) | 1382/ 63 | 776/ 52 | +| Scheduler, One Coroutine (setup) | 2046/ 214 | 430/ 28 | +| Scheduler, Two Coroutines (setup) | 2332/ 238 | 716/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 1074/ 39 | 468/ 28 | -| Scheduler, Two Coroutines (man setup) | 1368/ 63 | 762/ 52 | +| Scheduler, One Coroutine (man setup) | 2024/ 214 | 408/ 28 | +| Scheduler, Two Coroutines (man setup) | 2318/ 238 | 702/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 1134/ 111 | 528/ 100 | -| Scheduler, LogBinTableRenderer | 3380/ 304 | 2774/ 293 | -| Scheduler, LogBinJsonRenderer | 2900/ 308 | 2294/ 297 | +| Scheduler, LogBinProfiler | 2100/ 286 | 484/ 100 | +| Scheduler, LogBinTableRenderer | 3502/ 304 | 1886/ 118 | +| Scheduler, LogBinJsonRenderer | 3022/ 308 | 1406/ 122 | |---------------------------------------+--------------+-------------| -| Blink Function | 938/ 14 | 332/ 3 | -| Blink Coroutine | 1168/ 37 | 562/ 26 | +| Blink Function | 1948/ 189 | 332/ 3 | +| Blink Coroutine | 2118/ 212 | 502/ 26 | +--------------------------------------------------------------------+ ``` @@ -283,41 +286,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 3554/ 151 | 0/ 0 | +| Baseline | 3582/ 151 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 3602/ 153 | 48/ 2 | -| Two Delay Functions | 3662/ 155 | 108/ 4 | +| One Delay Function | 3630/ 153 | 48/ 2 | +| Two Delay Functions | 3690/ 155 | 108/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 3742/ 177 | 188/ 26 | -| Two Coroutines | 3936/ 201 | 382/ 50 | +| One Coroutine (millis) | 3770/ 177 | 188/ 26 | +| Two Coroutines (millis) | 3964/ 201 | 382/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 3714/ 177 | 160/ 26 | -| Two Coroutines (micros) | 3880/ 201 | 326/ 50 | +| One Coroutine (micros) | 3742/ 177 | 160/ 26 | +| Two Coroutines (micros) | 3908/ 201 | 326/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 3842/ 177 | 288/ 26 | -| Two Coroutines (seconds) | 4068/ 201 | 514/ 50 | +| One Coroutine (seconds) | 3870/ 177 | 288/ 26 | +| Two Coroutines (seconds) | 4096/ 201 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 3930/ 179 | 376/ 28 | -| Scheduler, Two Coroutines | 4116/ 203 | 562/ 52 | +| Scheduler, One Coroutine (millis) | 3958/ 179 | 376/ 28 | +| Scheduler, Two Coroutines (millis) | 4144/ 203 | 562/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 3902/ 179 | 348/ 28 | -| Scheduler, Two Coroutines (micros) | 4060/ 203 | 506/ 52 | +| Scheduler, One Coroutine (micros) | 3930/ 179 | 348/ 28 | +| Scheduler, Two Coroutines (micros) | 4088/ 203 | 506/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 4030/ 179 | 476/ 28 | -| Scheduler, Two Coroutines (seconds) | 4248/ 203 | 694/ 52 | +| Scheduler, One Coroutine (seconds) | 4058/ 179 | 476/ 28 | +| Scheduler, Two Coroutines (seconds) | 4276/ 203 | 694/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 3984/ 179 | 430/ 28 | -| Scheduler, Two Coroutines (setup) | 4270/ 203 | 716/ 52 | +| Scheduler, One Coroutine (setup) | 4012/ 179 | 430/ 28 | +| Scheduler, Two Coroutines (setup) | 4298/ 203 | 716/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 3962/ 179 | 408/ 28 | -| Scheduler, Two Coroutines (man setup) | 4256/ 203 | 702/ 52 | +| Scheduler, One Coroutine (man setup) | 3990/ 179 | 408/ 28 | +| Scheduler, Two Coroutines (man setup) | 4284/ 203 | 702/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 4022/ 251 | 468/ 100 | -| Scheduler, LogBinTableRenderer | 5438/ 269 | 1884/ 118 | -| Scheduler, LogBinJsonRenderer | 4958/ 273 | 1404/ 122 | +| Scheduler, LogBinProfiler | 4066/ 251 | 484/ 100 | +| Scheduler, LogBinTableRenderer | 5466/ 269 | 1884/ 118 | +| Scheduler, LogBinJsonRenderer | 4986/ 273 | 1404/ 122 | |---------------------------------------+--------------+-------------| -| Blink Function | 3994/ 154 | 440/ 3 | -| Blink Coroutine | 4164/ 177 | 610/ 26 | +| Blink Function | 4022/ 154 | 440/ 3 | +| Blink Coroutine | 4192/ 177 | 610/ 26 | +--------------------------------------------------------------------+ ``` @@ -332,41 +335,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 21884/ 3540 | 0/ 0 | +| Baseline | 21932/ 3540 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 21912/ 3544 | 28/ 4 | -| Two Delay Functions | 21960/ 3544 | 76/ 4 | +| One Delay Function | 21960/ 3544 | 28/ 4 | +| Two Delay Functions | 22008/ 3544 | 76/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 22016/ 3572 | 132/ 32 | -| Two Coroutines | 22164/ 3600 | 280/ 60 | +| One Coroutine (millis) | 22064/ 3572 | 132/ 32 | +| Two Coroutines (millis) | 22212/ 3600 | 280/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 22080/ 3572 | 196/ 32 | -| Two Coroutines (micros) | 22228/ 3600 | 344/ 60 | +| One Coroutine (micros) | 22128/ 3572 | 196/ 32 | +| Two Coroutines (micros) | 22276/ 3600 | 344/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 22032/ 3572 | 148/ 32 | -| Two Coroutines (seconds) | 22196/ 3600 | 312/ 60 | +| One Coroutine (seconds) | 22080/ 3572 | 148/ 32 | +| Two Coroutines (seconds) | 22244/ 3600 | 312/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 22192/ 3576 | 308/ 36 | -| Scheduler, Two Coroutines | 22296/ 3604 | 412/ 64 | +| Scheduler, One Coroutine (millis) | 22232/ 3576 | 300/ 36 | +| Scheduler, Two Coroutines (millis) | 22336/ 3604 | 404/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 22192/ 3576 | 308/ 36 | -| Scheduler, Two Coroutines (micros) | 22296/ 3604 | 412/ 64 | +| Scheduler, One Coroutine (micros) | 22232/ 3576 | 300/ 36 | +| Scheduler, Two Coroutines (micros) | 22336/ 3604 | 404/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 22208/ 3576 | 324/ 36 | -| Scheduler, Two Coroutines (seconds) | 22328/ 3604 | 444/ 64 | +| Scheduler, One Coroutine (seconds) | 22248/ 3576 | 316/ 36 | +| Scheduler, Two Coroutines (seconds) | 22368/ 3604 | 436/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 22216/ 3576 | 332/ 36 | -| Scheduler, Two Coroutines (setup) | 22348/ 3604 | 464/ 64 | +| Scheduler, One Coroutine (setup) | 22252/ 3576 | 320/ 36 | +| Scheduler, Two Coroutines (setup) | 22384/ 3604 | 452/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 22208/ 3576 | 324/ 36 | -| Scheduler, Two Coroutines (man setup) | 22344/ 3604 | 460/ 64 | +| Scheduler, One Coroutine (man setup) | 22244/ 3576 | 312/ 36 | +| Scheduler, Two Coroutines (man setup) | 22376/ 3604 | 444/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 22300/ 3644 | 416/ 104 | -| Scheduler, LogBinTableRenderer | 23704/ 3644 | 1820/ 104 | -| Scheduler, LogBinJsonRenderer | 23164/ 3644 | 1280/ 104 | +| Scheduler, LogBinProfiler | 22356/ 3644 | 424/ 104 | +| Scheduler, LogBinTableRenderer | 23740/ 3644 | 1808/ 104 | +| Scheduler, LogBinJsonRenderer | 23200/ 3644 | 1268/ 104 | |---------------------------------------+--------------+-------------| -| Blink Function | 22120/ 3540 | 236/ 0 | -| Blink Coroutine | 22232/ 3568 | 348/ 28 | +| Blink Function | 22168/ 3544 | 236/ 4 | +| Blink Coroutine | 22280/ 3572 | 348/ 32 | +--------------------------------------------------------------------+ ``` @@ -381,41 +384,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 260329/27916 | 0/ 0 | +| Baseline | 264981/27984 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 260377/27916 | 48/ 0 | -| Two Delay Functions | 260441/27916 | 112/ 0 | +| One Delay Function | 265045/27992 | 64/ 8 | +| Two Delay Functions | 265109/27992 | 128/ 8 | |---------------------------------------+--------------+-------------| -| One Coroutine | 260525/27952 | 196/ 36 | -| Two Coroutines | 260685/27976 | 356/ 60 | +| One Coroutine (millis) | 265177/28028 | 196/ 44 | +| Two Coroutines (millis) | 265337/28060 | 356/ 76 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 260541/27952 | 212/ 36 | -| Two Coroutines (micros) | 260701/27976 | 372/ 60 | +| One Coroutine (micros) | 265209/28028 | 228/ 44 | +| Two Coroutines (micros) | 265369/28060 | 388/ 76 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 260541/27952 | 212/ 36 | -| Two Coroutines (seconds) | 260717/27976 | 388/ 60 | +| One Coroutine (seconds) | 265209/28028 | 228/ 44 | +| Two Coroutines (seconds) | 265385/28060 | 404/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 260653/27952 | 324/ 36 | -| Scheduler, Two Coroutines | 260797/27984 | 468/ 68 | +| Scheduler, One Coroutine (millis) | 265321/28036 | 340/ 52 | +| Scheduler, Two Coroutines (millis) | 265449/28060 | 468/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 260653/27952 | 324/ 36 | -| Scheduler, Two Coroutines (micros) | 260797/27984 | 468/ 68 | +| Scheduler, One Coroutine (micros) | 265321/28036 | 340/ 52 | +| Scheduler, Two Coroutines (micros) | 265449/28060 | 468/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 260669/27952 | 340/ 36 | -| Scheduler, Two Coroutines (seconds) | 260829/27984 | 500/ 68 | +| Scheduler, One Coroutine (seconds) | 265337/28036 | 356/ 52 | +| Scheduler, Two Coroutines (seconds) | 265497/28060 | 516/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 260685/27952 | 356/ 36 | -| Scheduler, Two Coroutines (setup) | 260861/27984 | 532/ 68 | +| Scheduler, One Coroutine (setup) | 265337/28036 | 356/ 52 | +| Scheduler, Two Coroutines (setup) | 265513/28060 | 532/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 260669/27952 | 340/ 36 | -| Scheduler, Two Coroutines (man setup) | 260845/27984 | 516/ 68 | +| Scheduler, One Coroutine (man setup) | 265337/28036 | 356/ 52 | +| Scheduler, Two Coroutines (man setup) | 265513/28060 | 532/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 260781/28024 | 452/ 108 | -| Scheduler, LogBinTableRenderer | 265505/28100 | 5176/ 184 | -| Scheduler, LogBinJsonRenderer | 264913/28104 | 4584/ 188 | +| Scheduler, LogBinProfiler | 265449/28100 | 468/ 116 | +| Scheduler, LogBinTableRenderer | 267381/28100 | 2400/ 116 | +| Scheduler, LogBinJsonRenderer | 266773/28104 | 1792/ 120 | |---------------------------------------+--------------+-------------| -| Blink Function | 261001/27988 | 672/ 72 | -| Blink Coroutine | 261149/28016 | 820/ 100 | +| Blink Function | 265669/28064 | 688/ 80 | +| Blink Coroutine | 265801/28100 | 820/ 116 | +--------------------------------------------------------------------+ ``` @@ -430,41 +433,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 204573/16060 | 0/ 0 | +| Baseline | 230413/16220 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 205137/16100 | 564/ 40 | -| Two Delay Functions | 205209/16100 | 636/ 40 | +| One Delay Function | 230953/16260 | 540/ 40 | +| Two Delay Functions | 231025/16260 | 612/ 40 | |---------------------------------------+--------------+-------------| -| One Coroutine | 205249/16132 | 676/ 72 | -| Two Coroutines | 205421/16156 | 848/ 96 | +| One Coroutine (millis) | 231065/16292 | 652/ 72 | +| Two Coroutines (millis) | 231237/16316 | 824/ 96 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 205237/16132 | 664/ 72 | -| Two Coroutines (micros) | 205409/16156 | 836/ 96 | +| One Coroutine (micros) | 231077/16292 | 664/ 72 | +| Two Coroutines (micros) | 231249/16316 | 836/ 96 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 205265/16132 | 692/ 72 | -| Two Coroutines (seconds) | 205453/16156 | 880/ 96 | +| One Coroutine (seconds) | 231081/16292 | 668/ 72 | +| Two Coroutines (seconds) | 231269/16316 | 856/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 205365/16132 | 792/ 72 | -| Scheduler, Two Coroutines | 205505/16164 | 932/ 104 | +| Scheduler, One Coroutine (millis) | 231181/16292 | 768/ 72 | +| Scheduler, Two Coroutines (millis) | 231321/16324 | 908/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 205341/16132 | 768/ 72 | -| Scheduler, Two Coroutines (micros) | 205481/16164 | 908/ 104 | +| Scheduler, One Coroutine (micros) | 231181/16292 | 768/ 72 | +| Scheduler, Two Coroutines (micros) | 231321/16324 | 908/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 205381/16132 | 808/ 72 | -| Scheduler, Two Coroutines (seconds) | 205537/16164 | 964/ 104 | +| Scheduler, One Coroutine (seconds) | 231197/16292 | 784/ 72 | +| Scheduler, Two Coroutines (seconds) | 231353/16324 | 940/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 205393/16132 | 820/ 72 | -| Scheduler, Two Coroutines (setup) | 205565/16164 | 992/ 104 | +| Scheduler, One Coroutine (setup) | 231209/16292 | 796/ 72 | +| Scheduler, Two Coroutines (setup) | 231381/16324 | 968/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 205385/16132 | 812/ 72 | -| Scheduler, Two Coroutines (man setup) | 205565/16164 | 992/ 104 | +| Scheduler, One Coroutine (man setup) | 231197/16292 | 784/ 72 | +| Scheduler, Two Coroutines (man setup) | 231373/16324 | 960/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 205481/16204 | 908/ 144 | -| Scheduler, LogBinTableRenderer | 210977/16284 | 6404/ 224 | -| Scheduler, LogBinJsonRenderer | 210425/16284 | 5852/ 224 | +| Scheduler, LogBinProfiler | 231313/16364 | 900/ 144 | +| Scheduler, LogBinTableRenderer | 232645/16364 | 2232/ 144 | +| Scheduler, LogBinJsonRenderer | 232093/16364 | 1680/ 144 | |---------------------------------------+--------------+-------------| -| Blink Function | 205489/16108 | 916/ 48 | -| Blink Coroutine | 205601/16132 | 1028/ 72 | +| Blink Function | 231301/16268 | 888/ 48 | +| Blink Coroutine | 231413/16300 | 1000/ 80 | +--------------------------------------------------------------------+ ``` @@ -480,41 +483,41 @@ $ make README.md +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 10232/ 4152 | 0/ 0 | +| Baseline | 10648/ 4156 | 0/ 0 | |---------------------------------------+--------------+-------------| -| One Delay Function | 10264/ 4156 | 32/ 4 | -| Two Delay Functions | 10292/ 4156 | 60/ 4 | +| One Delay Function | 10680/ 4160 | 32/ 4 | +| Two Delay Functions | 10708/ 4160 | 60/ 4 | |---------------------------------------+--------------+-------------| -| One Coroutine | 10388/ 4184 | 156/ 32 | -| Two Coroutines | 10508/ 4212 | 276/ 60 | +| One Coroutine (millis) | 10804/ 4188 | 156/ 32 | +| Two Coroutines (millis) | 10924/ 4216 | 276/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 10444/ 4184 | 212/ 32 | -| Two Coroutines (micros) | 10552/ 4212 | 320/ 60 | +| One Coroutine (micros) | 10860/ 4188 | 212/ 32 | +| Two Coroutines (micros) | 10968/ 4216 | 320/ 60 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 10408/ 4184 | 176/ 32 | -| Two Coroutines (seconds) | 10548/ 4212 | 316/ 60 | +| One Coroutine (seconds) | 10824/ 4188 | 176/ 32 | +| Two Coroutines (seconds) | 10964/ 4216 | 316/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 10560/ 4188 | 328/ 36 | -| Scheduler, Two Coroutines | 10676/ 4216 | 444/ 64 | +| Scheduler, One Coroutine (millis) | 10976/ 4192 | 328/ 36 | +| Scheduler, Two Coroutines (millis) | 11092/ 4220 | 444/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 10548/ 4188 | 316/ 36 | -| Scheduler, Two Coroutines (micros) | 10652/ 4216 | 420/ 64 | +| Scheduler, One Coroutine (micros) | 10964/ 4192 | 316/ 36 | +| Scheduler, Two Coroutines (micros) | 11068/ 4220 | 420/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 10580/ 4188 | 348/ 36 | -| Scheduler, Two Coroutines (seconds) | 10716/ 4216 | 484/ 64 | +| Scheduler, One Coroutine (seconds) | 10996/ 4192 | 348/ 36 | +| Scheduler, Two Coroutines (seconds) | 11132/ 4220 | 484/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 10592/ 4188 | 360/ 36 | -| Scheduler, Two Coroutines (setup) | 10740/ 4216 | 508/ 64 | +| Scheduler, One Coroutine (setup) | 11012/ 4192 | 364/ 36 | +| Scheduler, Two Coroutines (setup) | 11160/ 4220 | 512/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 10580/ 4188 | 348/ 36 | -| Scheduler, Two Coroutines (man setup) | 10728/ 4216 | 496/ 64 | +| Scheduler, One Coroutine (man setup) | 10988/ 4192 | 340/ 36 | +| Scheduler, Two Coroutines (man setup) | 11140/ 4220 | 492/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 10952/ 4264 | 720/ 112 | -| Scheduler, LogBinTableRenderer | 14056/ 4284 | 3824/ 132 | -| Scheduler, LogBinJsonRenderer | 13348/ 4284 | 3116/ 132 | +| Scheduler, LogBinProfiler | 11380/ 4268 | 732/ 112 | +| Scheduler, LogBinTableRenderer | 14120/ 4284 | 3472/ 128 | +| Scheduler, LogBinJsonRenderer | 13412/ 4284 | 2764/ 128 | |---------------------------------------+--------------+-------------| -| Blink Function | 10688/ 4160 | 456/ 8 | -| Blink Coroutine | 10820/ 4184 | 588/ 32 | +| Blink Function | 11104/ 4164 | 456/ 8 | +| Blink Coroutine | 11236/ 4188 | 588/ 32 | +--------------------------------------------------------------------+ ``` diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index a3e86a6..a51bca5 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -1,24 +1,24 @@ -0 400 8192 11 512 -1 450 8192 13 512 -2 508 8192 15 512 -3 642 8192 37 512 -4 834 8192 61 512 -5 610 8192 37 512 -6 770 8192 61 512 -7 738 8192 37 512 -8 958 8192 61 512 -9 830 8192 39 512 -10 1016 8192 63 512 -11 798 8192 39 512 -12 952 8192 63 512 -13 926 8192 39 512 -14 1140 8192 63 512 -15 880 8192 39 512 -16 1162 8192 63 512 -17 860 8192 39 512 -18 1150 8192 63 512 -19 918 8192 111 512 -20 2792 8192 193 512 -21 2326 8192 197 512 -22 546 8192 14 512 -23 766 8192 37 512 +0 1026 8192 81 512 +1 1080 8192 83 512 +2 1134 8192 85 512 +3 1206 8192 107 512 +4 1400 8192 131 512 +5 1174 8192 107 512 +6 1336 8192 131 512 +7 1302 8192 107 512 +8 1524 8192 131 512 +9 1396 8192 109 512 +10 1582 8192 133 512 +11 1364 8192 109 512 +12 1518 8192 133 512 +13 1492 8192 109 512 +14 1706 8192 133 512 +15 1446 8192 109 512 +16 1728 8192 133 512 +17 1424 8192 109 512 +18 1714 8192 133 512 +19 1500 8192 181 512 +20 2864 8192 193 512 +21 2398 8192 197 512 +22 1176 8192 84 512 +23 1330 8192 107 512 diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 0ac2a15..70415fa 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -1,24 +1,24 @@ -0 204573 1310720 16060 327680 -1 205137 1310720 16100 327680 -2 205209 1310720 16100 327680 -3 205249 1310720 16132 327680 -4 205421 1310720 16156 327680 -5 205237 1310720 16132 327680 -6 205409 1310720 16156 327680 -7 205265 1310720 16132 327680 -8 205453 1310720 16156 327680 -9 205365 1310720 16132 327680 -10 205505 1310720 16164 327680 -11 205341 1310720 16132 327680 -12 205481 1310720 16164 327680 -13 205381 1310720 16132 327680 -14 205537 1310720 16164 327680 -15 205393 1310720 16132 327680 -16 205565 1310720 16164 327680 -17 205385 1310720 16132 327680 -18 205565 1310720 16164 327680 -19 205481 1310720 16204 327680 -20 210977 1310720 16284 327680 -21 210425 1310720 16284 327680 -22 205489 1310720 16108 327680 -23 205601 1310720 16132 327680 +0 230413 1310720 16220 327680 +1 230953 1310720 16260 327680 +2 231025 1310720 16260 327680 +3 231065 1310720 16292 327680 +4 231237 1310720 16316 327680 +5 231077 1310720 16292 327680 +6 231249 1310720 16316 327680 +7 231081 1310720 16292 327680 +8 231269 1310720 16316 327680 +9 231181 1310720 16292 327680 +10 231321 1310720 16324 327680 +11 231181 1310720 16292 327680 +12 231321 1310720 16324 327680 +13 231197 1310720 16292 327680 +14 231353 1310720 16324 327680 +15 231209 1310720 16292 327680 +16 231381 1310720 16324 327680 +17 231197 1310720 16292 327680 +18 231373 1310720 16324 327680 +19 231313 1310720 16364 327680 +20 232645 1310720 16364 327680 +21 232093 1310720 16364 327680 +22 231301 1310720 16268 327680 +23 231413 1310720 16300 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 6a8ced2..8b241fe 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -1,24 +1,24 @@ -0 260329 1044464 27916 81920 -1 260377 1044464 27916 81920 -2 260441 1044464 27916 81920 -3 260525 1044464 27952 81920 -4 260685 1044464 27976 81920 -5 260541 1044464 27952 81920 -6 260701 1044464 27976 81920 -7 260541 1044464 27952 81920 -8 260717 1044464 27976 81920 -9 260653 1044464 27952 81920 -10 260797 1044464 27984 81920 -11 260653 1044464 27952 81920 -12 260797 1044464 27984 81920 -13 260669 1044464 27952 81920 -14 260829 1044464 27984 81920 -15 260685 1044464 27952 81920 -16 260861 1044464 27984 81920 -17 260669 1044464 27952 81920 -18 260845 1044464 27984 81920 -19 260781 1044464 28024 81920 -20 265505 1044464 28100 81920 -21 264913 1044464 28104 81920 -22 261001 1044464 27988 81920 -23 261149 1044464 28016 81920 +0 264981 1044464 27984 81920 +1 265045 1044464 27992 81920 +2 265109 1044464 27992 81920 +3 265177 1044464 28028 81920 +4 265337 1044464 28060 81920 +5 265209 1044464 28028 81920 +6 265369 1044464 28060 81920 +7 265209 1044464 28028 81920 +8 265385 1044464 28060 81920 +9 265321 1044464 28036 81920 +10 265449 1044464 28060 81920 +11 265321 1044464 28036 81920 +12 265449 1044464 28060 81920 +13 265337 1044464 28036 81920 +14 265497 1044464 28060 81920 +15 265337 1044464 28036 81920 +16 265513 1044464 28060 81920 +17 265337 1044464 28036 81920 +18 265513 1044464 28060 81920 +19 265449 1044464 28100 81920 +20 267381 1044464 28100 81920 +21 266773 1044464 28104 81920 +22 265669 1044464 28064 81920 +23 265801 1044464 28100 81920 diff --git a/examples/MemoryBenchmark/generate_readme.py b/examples/MemoryBenchmark/generate_readme.py index 7d79a77..f7d7d20 100755 --- a/examples/MemoryBenchmark/generate_readme.py +++ b/examples/MemoryBenchmark/generate_readme.py @@ -133,15 +133,18 @@ * Increases static ram by 3 bytes (AVR) and 4 bytes (32-bits) per coroutine. * Support `CoroutineProfiler` in the `CoroutineScheduler`. - * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes + * Increases the flash size of the `CoroutineScheduler` by 90-140 bytes for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is not used. This is a one-time hit. * Add `LogBinProfiler` * Adds about 90 bytes of flash and 70 bytes of RAM on AVR. + * Adds about 140 bytes of flash and 70 bytes of RAM on ESP8266. * Add `LogBinTableRenderer` - * Adds about 2200 bytes of flash and 200 bytes of RAM on AVR. + * Adds about 1400 bytes of flash and ~20 bytes of RAM on AVR. + * Adds about 1900 bytes of flash and ~0 bytes of RAM on ESP8266. * Add `LogBinJsonRenderer` - * Adds about 1800 bytes of flash and 200 bytes of RAM on AVR. + * Adds about 900 bytes of flash and ~20 bytes of RAM on AVR. + * Adds about 1300 bytes of flash and ~0 bytes of RAM on ESP8266. ## How to Generate diff --git a/examples/MemoryBenchmark/generate_table.awk b/examples/MemoryBenchmark/generate_table.awk index 59c439f..50c4037 100755 --- a/examples/MemoryBenchmark/generate_table.awk +++ b/examples/MemoryBenchmark/generate_table.awk @@ -9,14 +9,14 @@ BEGIN { labels[0] = "Baseline" labels[1] = "One Delay Function" labels[2] = "Two Delay Functions" - labels[3] = "One Coroutine" - labels[4] = "Two Coroutines" + labels[3] = "One Coroutine (millis)" + labels[4] = "Two Coroutines (millis)" labels[5] = "One Coroutine (micros)" labels[6] = "Two Coroutines (micros)" labels[7] = "One Coroutine (seconds)" labels[8] = "Two Coroutines (seconds)" - labels[9] = "Scheduler, One Coroutine" - labels[10] = "Scheduler, Two Coroutines" + labels[9] = "Scheduler, One Coroutine (millis)" + labels[10] = "Scheduler, Two Coroutines (millis)" labels[11] = "Scheduler, One Coroutine (micros)" labels[12] = "Scheduler, Two Coroutines (micros)" labels[13] = "Scheduler, One Coroutine (seconds)" @@ -52,10 +52,10 @@ END { for (i = 0; i < NUM_ENTRIES; i++) { if (labels[i] ~ /^Baseline$/ \ || labels[i] ~ /^One Delay Function$/ \ - || labels[i] ~ /^One Coroutine$/ \ + || labels[i] ~ /^One Coroutine \(millis\)$/ \ || labels[i] ~ /^One Coroutine \(micros\)$/ \ || labels[i] ~ /^One Coroutine \(seconds\)$/ \ - || labels[i] ~ /^Scheduler, One Coroutine$/ \ + || labels[i] ~ /^Scheduler, One Coroutine \(millis\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(micros\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(seconds\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(setup\)$/ \ diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index 83e4a66..0cec484 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -1,24 +1,24 @@ -0 3554 28672 151 2560 -1 3602 28672 153 2560 -2 3662 28672 155 2560 -3 3742 28672 177 2560 -4 3936 28672 201 2560 -5 3714 28672 177 2560 -6 3880 28672 201 2560 -7 3842 28672 177 2560 -8 4068 28672 201 2560 -9 3930 28672 179 2560 -10 4116 28672 203 2560 -11 3902 28672 179 2560 -12 4060 28672 203 2560 -13 4030 28672 179 2560 -14 4248 28672 203 2560 -15 3984 28672 179 2560 -16 4270 28672 203 2560 -17 3962 28672 179 2560 -18 4256 28672 203 2560 -19 4022 28672 251 2560 -20 5438 28672 269 2560 -21 4958 28672 273 2560 -22 3994 28672 154 2560 -23 4164 28672 177 2560 +0 3582 28672 151 2560 +1 3630 28672 153 2560 +2 3690 28672 155 2560 +3 3770 28672 177 2560 +4 3964 28672 201 2560 +5 3742 28672 177 2560 +6 3908 28672 201 2560 +7 3870 28672 177 2560 +8 4096 28672 201 2560 +9 3958 28672 179 2560 +10 4144 28672 203 2560 +11 3930 28672 179 2560 +12 4088 28672 203 2560 +13 4058 28672 179 2560 +14 4276 28672 203 2560 +15 4012 28672 179 2560 +16 4298 28672 203 2560 +17 3990 28672 179 2560 +18 4284 28672 203 2560 +19 4066 28672 251 2560 +20 5466 28672 269 2560 +21 4986 28672 273 2560 +22 4022 28672 154 2560 +23 4192 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 6bb19c9..8bf4fc5 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -1,24 +1,24 @@ -0 606 30720 11 2048 -1 654 30720 13 2048 -2 714 30720 15 2048 -3 854 30720 37 2048 -4 1048 30720 61 2048 -5 826 30720 37 2048 -6 992 30720 61 2048 -7 954 30720 37 2048 -8 1180 30720 61 2048 -9 1042 30720 39 2048 -10 1228 30720 63 2048 -11 1014 30720 39 2048 -12 1172 30720 63 2048 -13 1142 30720 39 2048 -14 1360 30720 63 2048 -15 1096 30720 39 2048 -16 1382 30720 63 2048 -17 1074 30720 39 2048 -18 1368 30720 63 2048 -19 1134 30720 111 2048 -20 3380 30720 304 2048 -21 2900 30720 308 2048 -22 938 30720 14 2048 -23 1168 30720 37 2048 +0 1616 30720 186 2048 +1 1664 30720 188 2048 +2 1726 30720 190 2048 +3 1804 30720 212 2048 +4 1998 30720 236 2048 +5 1776 30720 212 2048 +6 1942 30720 236 2048 +7 1904 30720 212 2048 +8 2130 30720 236 2048 +9 1992 30720 214 2048 +10 2178 30720 238 2048 +11 1964 30720 214 2048 +12 2122 30720 238 2048 +13 2092 30720 214 2048 +14 2310 30720 238 2048 +15 2046 30720 214 2048 +16 2332 30720 238 2048 +17 2024 30720 214 2048 +18 2318 30720 238 2048 +19 2100 30720 286 2048 +20 3502 30720 304 2048 +21 3022 30720 308 2048 +22 1948 30720 189 2048 +23 2118 30720 212 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index 0cf52ec..5822dd1 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -1,24 +1,24 @@ -0 21884 131072 3540 20480 -1 21912 131072 3544 20480 -2 21960 131072 3544 20480 -3 22016 131072 3572 20480 -4 22164 131072 3600 20480 -5 22080 131072 3572 20480 -6 22228 131072 3600 20480 -7 22032 131072 3572 20480 -8 22196 131072 3600 20480 -9 22192 131072 3576 20480 -10 22296 131072 3604 20480 -11 22192 131072 3576 20480 -12 22296 131072 3604 20480 -13 22208 131072 3576 20480 -14 22328 131072 3604 20480 -15 22216 131072 3576 20480 -16 22348 131072 3604 20480 -17 22208 131072 3576 20480 -18 22344 131072 3604 20480 -19 22300 131072 3644 20480 -20 23704 131072 3644 20480 -21 23164 131072 3644 20480 -22 22120 131072 3540 20480 -23 22232 131072 3568 20480 +0 21932 131072 3540 20480 +1 21960 131072 3544 20480 +2 22008 131072 3544 20480 +3 22064 131072 3572 20480 +4 22212 131072 3600 20480 +5 22128 131072 3572 20480 +6 22276 131072 3600 20480 +7 22080 131072 3572 20480 +8 22244 131072 3600 20480 +9 22232 131072 3576 20480 +10 22336 131072 3604 20480 +11 22232 131072 3576 20480 +12 22336 131072 3604 20480 +13 22248 131072 3576 20480 +14 22368 131072 3604 20480 +15 22252 131072 3576 20480 +16 22384 131072 3604 20480 +17 22244 131072 3576 20480 +18 22376 131072 3604 20480 +19 22356 131072 3644 20480 +20 23740 131072 3644 20480 +21 23200 131072 3644 20480 +22 22168 131072 3544 20480 +23 22280 131072 3572 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index 30f1d54..cf905b3 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -1,24 +1,24 @@ -0 10232 262144 4152 65536 -1 10264 262144 4156 65536 -2 10292 262144 4156 65536 -3 10388 262144 4184 65536 -4 10508 262144 4212 65536 -5 10444 262144 4184 65536 -6 10552 262144 4212 65536 -7 10408 262144 4184 65536 -8 10548 262144 4212 65536 -9 10560 262144 4188 65536 -10 10676 262144 4216 65536 -11 10548 262144 4188 65536 -12 10652 262144 4216 65536 -13 10580 262144 4188 65536 -14 10716 262144 4216 65536 -15 10592 262144 4188 65536 -16 10740 262144 4216 65536 -17 10580 262144 4188 65536 -18 10728 262144 4216 65536 -19 10952 262144 4264 65536 -20 14056 262144 4284 65536 -21 13348 262144 4284 65536 -22 10688 262144 4160 65536 -23 10820 262144 4184 65536 +0 10648 262144 4156 65536 +1 10680 262144 4160 65536 +2 10708 262144 4160 65536 +3 10804 262144 4188 65536 +4 10924 262144 4216 65536 +5 10860 262144 4188 65536 +6 10968 262144 4216 65536 +7 10824 262144 4188 65536 +8 10964 262144 4216 65536 +9 10976 262144 4192 65536 +10 11092 262144 4220 65536 +11 10964 262144 4192 65536 +12 11068 262144 4220 65536 +13 10996 262144 4192 65536 +14 11132 262144 4220 65536 +15 11012 262144 4192 65536 +16 11160 262144 4220 65536 +17 10988 262144 4192 65536 +18 11140 262144 4220 65536 +19 11380 262144 4268 65536 +20 14120 262144 4284 65536 +21 13412 262144 4284 65536 +22 11104 262144 4164 65536 +23 11236 262144 4188 65536 From 110b6d68b8d137735e79ae4db3e3e6d4c8b6df0d Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 15:28:14 -0700 Subject: [PATCH 44/59] AutoBenchmark: Faster CoroutineScheduler::runCoroutine() by delegating to Coroutine::runCoroutineWithProfiler() --- examples/AutoBenchmark/README.md | 30 +++++++++++------------ examples/AutoBenchmark/esp32.txt | 4 +-- examples/AutoBenchmark/esp8266.txt | 4 +-- examples/AutoBenchmark/generate_readme.py | 10 ++++---- examples/AutoBenchmark/micro.txt | 6 ++--- examples/AutoBenchmark/nano.txt | 2 +- examples/AutoBenchmark/stm32.txt | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/examples/AutoBenchmark/README.md b/examples/AutoBenchmark/README.md index 1dda3d9..01b8a00 100644 --- a/examples/AutoBenchmark/README.md +++ b/examples/AutoBenchmark/README.md @@ -124,11 +124,11 @@ $ make README.md * v1.5.0 * Add `CoroutineProfiler` to `CoroutineScheduler`. * `CoroutineScheduler::runCoroutine()` becomes slightly slower: - * 0.7 microseconds (AVR) - * 0.5 microseconds (STM32) - * 0.2 microseconds (ESP8266) - * 0.07 microseconds (ESP32) - * 0.15 microseconds (Teensy 3.2) + * 0.100 microseconds (AVR) + * 0.133 microseconds (STM32) + * 0.100 microseconds (ESP8266) + * 0.033 microseconds (ESP32) + * 0.133 microseconds (Teensy 3.2) ## Arduino Nano @@ -149,7 +149,7 @@ CPU: |---------------------+--------+-------------+--------| | EmptyLoop | 10000 | 1.700 | 0.000 | | DirectScheduling | 10000 | 2.900 | 1.200 | -| CoroutineScheduling | 10000 | 7.900 | 6.200 | +| CoroutineScheduling | 10000 | 7.200 | 5.500 | +---------------------+--------+-------------+--------+ ``` @@ -171,9 +171,9 @@ CPU: +---------------------+--------+-------------+--------+ | Functionality | iters | micros/iter | diff | |---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 1.700 | 0.000 | -| DirectScheduling | 10000 | 2.900 | 1.200 | -| CoroutineScheduling | 10000 | 7.900 | 6.200 | +| EmptyLoop | 10000 | 1.800 | 0.000 | +| DirectScheduling | 10000 | 2.800 | 1.000 | +| CoroutineScheduling | 10000 | 7.200 | 5.400 | +---------------------+--------+-------------+--------+ ``` @@ -196,7 +196,7 @@ CPU: |---------------------+--------+-------------+--------| | EmptyLoop | 30000 | 0.133 | 0.000 | | DirectScheduling | 30000 | 0.533 | 0.400 | -| CoroutineScheduling | 30000 | 1.600 | 1.467 | +| CoroutineScheduling | 30000 | 1.266 | 1.133 | +---------------------+--------+-------------+--------+ ``` @@ -217,9 +217,9 @@ CPU: +---------------------+--------+-------------+--------+ | Functionality | iters | micros/iter | diff | |---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 0.200 | 0.000 | -| DirectScheduling | 10000 | 0.500 | 0.300 | -| CoroutineScheduling | 10000 | 1.200 | 1.000 | +| EmptyLoop | 10000 | 0.100 | 0.000 | +| DirectScheduling | 10000 | 0.500 | 0.400 | +| CoroutineScheduling | 10000 | 1.000 | 0.900 | +---------------------+--------+-------------+--------+ ``` @@ -241,8 +241,8 @@ CPU: | Functionality | iters | micros/iter | diff | |---------------------+--------+-------------+--------| | EmptyLoop | 30000 | 0.066 | 0.000 | -| DirectScheduling | 30000 | 0.100 | 0.034 | -| CoroutineScheduling | 30000 | 0.400 | 0.334 | +| DirectScheduling | 30000 | 0.133 | 0.067 | +| CoroutineScheduling | 30000 | 0.366 | 0.300 | +---------------------+--------+-------------+--------+ ``` diff --git a/examples/AutoBenchmark/esp32.txt b/examples/AutoBenchmark/esp32.txt index 489da42..08a0c39 100644 --- a/examples/AutoBenchmark/esp32.txt +++ b/examples/AutoBenchmark/esp32.txt @@ -4,6 +4,6 @@ sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 BENCHMARKS EmptyLoop 0.066 30000 -DirectScheduling 0.100 30000 -CoroutineScheduling 0.400 30000 +DirectScheduling 0.133 30000 +CoroutineScheduling 0.366 30000 END diff --git a/examples/AutoBenchmark/esp8266.txt b/examples/AutoBenchmark/esp8266.txt index f6ee050..c256052 100644 --- a/examples/AutoBenchmark/esp8266.txt +++ b/examples/AutoBenchmark/esp8266.txt @@ -3,7 +3,7 @@ sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 BENCHMARKS -EmptyLoop 0.200 10000 +EmptyLoop 0.100 10000 DirectScheduling 0.500 10000 -CoroutineScheduling 1.200 10000 +CoroutineScheduling 1.000 10000 END diff --git a/examples/AutoBenchmark/generate_readme.py b/examples/AutoBenchmark/generate_readme.py index 15e394c..37d862b 100755 --- a/examples/AutoBenchmark/generate_readme.py +++ b/examples/AutoBenchmark/generate_readme.py @@ -148,11 +148,11 @@ * v1.5.0 * Add `CoroutineProfiler` to `CoroutineScheduler`. * `CoroutineScheduler::runCoroutine()` becomes slightly slower: - * 0.7 microseconds (AVR) - * 0.5 microseconds (STM32) - * 0.2 microseconds (ESP8266) - * 0.07 microseconds (ESP32) - * 0.15 microseconds (Teensy 3.2) + * 0.100 microseconds (AVR) + * 0.133 microseconds (STM32) + * 0.100 microseconds (ESP8266) + * 0.033 microseconds (ESP32) + * 0.133 microseconds (Teensy 3.2) ## Arduino Nano diff --git a/examples/AutoBenchmark/micro.txt b/examples/AutoBenchmark/micro.txt index 12320ef..55c853a 100644 --- a/examples/AutoBenchmark/micro.txt +++ b/examples/AutoBenchmark/micro.txt @@ -3,7 +3,7 @@ sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 BENCHMARKS -EmptyLoop 1.700 10000 -DirectScheduling 2.900 10000 -CoroutineScheduling 7.900 10000 +EmptyLoop 1.800 10000 +DirectScheduling 2.800 10000 +CoroutineScheduling 7.200 10000 END diff --git a/examples/AutoBenchmark/nano.txt b/examples/AutoBenchmark/nano.txt index 12320ef..bd6e659 100644 --- a/examples/AutoBenchmark/nano.txt +++ b/examples/AutoBenchmark/nano.txt @@ -5,5 +5,5 @@ sizeof(Channel): 5 BENCHMARKS EmptyLoop 1.700 10000 DirectScheduling 2.900 10000 -CoroutineScheduling 7.900 10000 +CoroutineScheduling 7.200 10000 END diff --git a/examples/AutoBenchmark/stm32.txt b/examples/AutoBenchmark/stm32.txt index d3caab3..dcfb5c7 100644 --- a/examples/AutoBenchmark/stm32.txt +++ b/examples/AutoBenchmark/stm32.txt @@ -5,5 +5,5 @@ sizeof(Channel): 12 BENCHMARKS EmptyLoop 0.133 30000 DirectScheduling 0.533 30000 -CoroutineScheduling 1.600 30000 +CoroutineScheduling 1.266 30000 END From 15ed3ecf1bd4530a8dad1b9344e29244d3fdd5a9 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 15:31:43 -0700 Subject: [PATCH 45/59] README.md,USER_GUIDE.md: Add coroutine name, coroutine profiling --- CHANGELOG.md | 57 ++++++---- README.md | 294 ++++++++++++++++++++++++++++++++++++++++++-------- USER_GUIDE.md | 270 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 550 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b34fb80..0467399 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,33 +1,48 @@ # Changelog * Unreleased - * (Re)add support for human-readable coroutine names by adding the following - methods to the `Coroutine` class: `setName()`, `setName()`, - `getCName()`, `getFName()`, `getNameType()`, and `printNameTo()`. - * This is an optional feature which helps debugging. Coroutines do not - need to have human readable names. - * Increases flash usage by 6-10 bytes per coroutine. - * Increases static ram usage by 3 bytes (AVR) or 4 bytes (32-bit) per - coroutine. - * Support `CoroutineProfiler` in `CoroutineScheduler`. - * If a coroutine contains a valid pointer to a `CoroutineProfiler`, then - `CoroutineScheduler::runCoroutine()` will measure the elapsed - microseconds for the `Coroutine::runCoroutine()` to run. - * It then calls `CoroutineProfiler::updateElapsedMicros()` to allow the - profiler to update its internal tracking. - * Provide `LogBinProfiler`, and specific subclass that collects - the frequency count of the elapsed microseconds using 32 bins - representing the `log2()` function of the microseconds. + * (Re)add support for human-readable coroutine names. + * See [Coroutine Names](USER_GUIDE.md#CoroutineNames) in the + `USER_GUIDE.md`. + * Adds the following methods to the `Coroutine` class: `setName()`, + `setName()`, `getCName()`, `getFName()`, `getNameType()`, and + `printNameTo()`. + * Resource consumption + * Increases flash usage by 6-10 bytes per coroutine. + * Increases static ram usage by 3 bytes (AVR) or 4 bytes (32-bit) + per coroutine. + * Support profiling of `Coroutine::runCoroutine()` execution time. + * See [Coroutine Profiling](USER_GUIDE.md#CoroutineProfiling) in the + `USER_GUIDE.md`. + * API changes + * Add `CoroutineProfiler` interface with a `updateElapsedMicros()` + method. + * Add `Coroutine::setProfiler()`. + * Add `Coroutine::runCoroutineWithProfiler()` which measures the + elapsed time of `runCoroutine()`. + * Update `CoroutineScheduler::runCoroutine()` to call + `runCoroutineWithProfiler()`. + * Provide `LogBinProfiler` subclass of `CoroutineProfiler`. + * Keeps a frequency count of the elapsed microseconds using 32 bins + representing the `log2()` function of the elapsed microseconds. * Provide 2 renderers: * `LogBinTableRenderer::printTo()` prints a formatted table of the frequency count over all coroutines. This represents a poor-man's version of the log-log graph of the frequency count. * `LogBinJsonRenderer::printTo()` prints the frequency count in JSON format. - * Increases the flash size of the `CoroutineScheduler` by 100-140 bytes - for both 8-bit and 32-bit processors, even if `CoroutineProfiler` is - not used. This is a one-time hit. - * See [examples/SoundManager](examples/SoundManager) for an example. + * Resource consumption + * Increases static ram usage by 2 bytes (AVR) or 4 bytes (32-bit) + per coroutine. + * Increases latency of `CoroutineScheduler::runCoroutine()` by only + 100ns (AVR, ESP8266), 133ns (STM32, Teensy 3.2), and 33ns (ESP32). + * Increases the flash size of the `CoroutineScheduler` by 100-140 + bytes for both 8-bit and 32-bit processors, even if + `CoroutineProfiler` is not used. This is a one-time hit. + * See [HelloCoroutineWithProfiler](examples/HelloCoroutineWithProfiler) + and [HelloSchedulerWithProfiler](examples/HelloSchedulerWithProfiler). + * Thanks to peufeu2@ who provided the ideas and proof of concept in + [Discussion#50](https://github.com/bxparks/AceRoutine/discussions/50). * 1.4.2 (2022-02-04) * Remove dependency to AceCommon library in `libraries.properties`. * AceRoutine core no longer depends on AceCommon. diff --git a/README.md b/README.md index b6ed267..ec4f280 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,8 @@ additional macros that can reduce boilerplate code. * [Hello Coroutine](#HelloCoroutine) * [Hello Scheduler](#HelloScheduler) * [Hello Manual Coroutine](#HelloManualCoroutine) + * [Hello Coroutine with Profiler](#HelloCoroutineWithProfiler) + * [Hello Scheduler with Profiler](#HelloSchedulerWithProfiler) * [Installation](#Installation) * [Source Code](#SourceCode) * [Documentation](#Documentation) @@ -289,6 +291,197 @@ void loop() { } ``` +### HelloCoroutineWithProfiler + +Version 1.5 added support for profiling the execution time of +`Coroutine::runCoroutine()` through the `CoroutineProfiler` interface. Currently +only a single implementation (`LogBinProfiler`) is provided. + +The [HelloCoroutineWithProfiler.ino](examples/HelloCoroutineWithProfiler) +program shows how to setup the profilers and extract the profiling information. +This example is intended for resource constrained 8-bit processors which do not +want to pay for the cost of the `CoroutineScheduler`. + +```C++ +#include +using namespace ace_routine; + +const int PIN = 2; +const int LED = LED_BUILTIN; +const int LED_ON = HIGH; +const int LED_OFF = LOW; + +COROUTINE(blinkLed) { + COROUTINE_LOOP() { + digitalWrite(LED, LED_ON); + COROUTINE_DELAY(100); + digitalWrite(LED, LED_OFF); + COROUTINE_DELAY(500); + } +} + +COROUTINE(printHelloWorld) { + COROUTINE_LOOP() { + Serial.print(F("Hello, ")); + Serial.flush(); + COROUTINE_DELAY(1000); + Serial.println(F("World")); + COROUTINE_DELAY(4000); + } +} + +COROUTINE(printProfiling) { + COROUTINE_LOOP() { + LogBinTableRenderer tableRenderer(Coroutine::getRoot()); + LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); + + tableRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); + jsonRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/); + + COROUTINE_DELAY(5000); + } +} + +LogBinProfiler profiler1; +LogBinProfiler profiler2; +LogBinProfiler profiler3; + +void setup() { + delay(1000); + Serial.begin(115200); + while (!Serial); // Leonardo/Micro + + pinMode(LED, OUTPUT); + pinMode(PIN, INPUT); + + // Coroutine names can be either C-string or F-string. + blinkLed.setName("blinkLed"); + readPin.setName(F("readPin")); + + // Manually attach the profilers to the coroutines. + blinkLed.setProfiler(&profiler1); + readPin.setProfiler(&profiler2); + printProfiling.setProfiler(&profiler3); +} + +void loop() { + blinkLed.runCoroutineWithProfiling(); + printHelloWorld.runCoroutineWithProfiling(); + printProfiling.runCoroutineWithProfiler(); +} +``` + +Every 5 seconds, the `printProfiling` coroutine will print the profiling +information in 2 formats on the `Serial` port: + +* a formatted table through the `LogBinTableRenderer` +* a JSON object using the `LogBinJsonRenderer` + +``` +name <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms <8ms >> +0x1DB 16921 52650 0 0 0 0 0 0 0 0 1 +readPin 65535 1189 0 0 0 0 0 0 0 0 0 +blinkLed 65535 830 0 0 0 0 0 0 0 0 0 +{ +"0x1DB":[16921,52650,0,0,0,0,0,0,0,0,1], +"readPin":[65535,1189,0,0,0,0,0,0,0,0,0], +"blinkLed":[65535,830,0,0,0,0,0,0,0,0,0] +} +``` + + +### HelloSchedulerWithProfiler + +The [HelloSchedulerWithProfiler.ino](examples/HelloSchedulerWithProfiler) sketch +implements the same thing as `HelloCoroutineWithProfiler` using the +`CoroutineScheduler` which automatically supports the `CoroutineProfiler`. +The assumption was that if the environment has enough resources to support +a `CoroutineScheduler`, then it is probably not a large burden to include the +code to support `CoroutineProfiler` by default. Hence, this is intended for +32-bit environments where flash and static RAM resources are more plentiful. + +```C++ +#include +using namespace ace_routine; + +const int PIN = 2; +const int LED = LED_BUILTIN; +const int LED_ON = HIGH; +const int LED_OFF = LOW; + +COROUTINE(blinkLed) { + COROUTINE_LOOP() { + digitalWrite(LED, LED_ON); + COROUTINE_DELAY(100); + digitalWrite(LED, LED_OFF); + COROUTINE_DELAY(500); + } +} + +COROUTINE(printHelloWorld) { + COROUTINE_LOOP() { + Serial.print(F("Hello, ")); + Serial.flush(); + COROUTINE_DELAY(1000); + Serial.println(F("World")); + COROUTINE_DELAY(4000); + } +} + +COROUTINE(printProfiling) { + COROUTINE_LOOP() { + LogBinTableRenderer tableRenderer(Coroutine::getRoot()); + LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); + + tableRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); + jsonRenderer.printTo( + Serial, 3 /*startBin*/, 14 /*endBin*/); + + COROUTINE_DELAY(5000); + } +} + +void setup() { + delay(1000); + Serial.begin(115200); + while (!Serial); // Leonardo/Micro + + pinMode(LED, OUTPUT); + pinMode(PIN, INPUT); + + // Coroutine names can be either C-string or F-string. + blinkLed.setName("blinkLed"); + readPin.setName(F("readPin")); + + // Create profilers on the heap and attach them to all coroutines. + LogBinProfiler::createProfilers(Coroutine::getRoot()); + + CoroutineScheduler::setup(); +} + +void loop() { + CoroutineScheduler::loop(); +} +``` + +The `printProfiling` coroutine will print the same information as before every 5 +seconds: + +``` +name <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms <8ms >> +0x1DB 16921 52650 0 0 0 0 0 0 0 0 1 +readPin 65535 1189 0 0 0 0 0 0 0 0 0 +blinkLed 65535 830 0 0 0 0 0 0 0 0 0 +{ +"0x1DB":[16921,52650,0,0,0,0,0,0,0,0,1], +"readPin":[65535,1189,0,0,0,0,0,0,0,0,0], +"blinkLed":[65535,830,0,0,0,0,0,0,0,0,0] +} +``` + ## Installation @@ -344,6 +537,9 @@ The following programs are provided under the `examples` directory: * [HelloManualCoroutine.ino](examples/HelloManualCoroutine): same as `HelloCoroutine` except the `Coroutine` subclasses and instances are created and registered manually + * [HelloCoroutineWithProfiler.ino](examples/HelloCoroutineWithProfiler) + * [HelloSchedulerWithProfiler.ino](examples/HelloSchedulerWithProfiler): + same as `HelloCoroutineWithProfiler` using `CoroutineScheduler` * Intermediate Examples * [BlinkSlowFastRoutine.ino](examples/BlinkSlowFastRoutine): use coroutines to read a button and control how the LED blinks @@ -466,7 +662,7 @@ All objects are statically allocated (i.e. not heap or stack). On 8-bit processors (AVR Nano, Uno, etc): ``` -sizeof(Coroutine): 11 +sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 ``` @@ -474,7 +670,7 @@ sizeof(Channel): 5 On 32-bit processors (e.g. Teensy ARM, ESP8266, ESP32): ``` -sizeof(Coroutine): 20 +sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 ``` @@ -503,37 +699,41 @@ etc) for a handful of AceRoutine features. Here are some highlights: +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 606/ 11 | 0/ 0 | +| Baseline | 1616/ 186 | 0/ 0 | +|---------------------------------------+--------------+-------------| +| One Delay Function | 1664/ 188 | 48/ 2 | +| Two Delay Functions | 1726/ 190 | 110/ 4 | |---------------------------------------+--------------+-------------| -| One Delay Function | 654/ 13 | 48/ 2 | -| Two Delay Functions | 714/ 15 | 108/ 4 | +| One Coroutine (millis) | 1804/ 212 | 188/ 26 | +| Two Coroutines (millis) | 1998/ 236 | 382/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine | 844/ 32 | 238/ 21 | -| Two Coroutines | 1016/ 51 | 410/ 40 | +| One Coroutine (micros) | 1776/ 212 | 160/ 26 | +| Two Coroutines (micros) | 1942/ 236 | 326/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 816/ 32 | 210/ 21 | -| Two Coroutines (micros) | 960/ 51 | 354/ 40 | +| One Coroutine (seconds) | 1904/ 212 | 288/ 26 | +| Two Coroutines (seconds) | 2130/ 236 | 514/ 50 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 944/ 32 | 338/ 21 | -| Two Coroutines (seconds) | 1148/ 51 | 542/ 40 | +| Scheduler, One Coroutine (millis) | 1992/ 214 | 376/ 28 | +| Scheduler, Two Coroutines (millis) | 2178/ 238 | 562/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 968/ 34 | 362/ 23 | -| Scheduler, Two Coroutines | 1132/ 53 | 526/ 42 | +| Scheduler, One Coroutine (micros) | 1964/ 214 | 348/ 28 | +| Scheduler, Two Coroutines (micros) | 2122/ 238 | 506/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 940/ 34 | 334/ 23 | -| Scheduler, Two Coroutines (micros) | 1076/ 53 | 470/ 42 | +| Scheduler, One Coroutine (seconds) | 2092/ 214 | 476/ 28 | +| Scheduler, Two Coroutines (seconds) | 2310/ 238 | 694/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 1068/ 34 | 462/ 23 | -| Scheduler, Two Coroutines (seconds) | 1264/ 53 | 658/ 42 | +| Scheduler, One Coroutine (setup) | 2046/ 214 | 430/ 28 | +| Scheduler, Two Coroutines (setup) | 2332/ 238 | 716/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 1018/ 34 | 412/ 23 | -| Scheduler, Two Coroutines (setup) | 1282/ 53 | 676/ 42 | +| Scheduler, One Coroutine (man setup) | 2024/ 214 | 408/ 28 | +| Scheduler, Two Coroutines (man setup) | 2318/ 238 | 702/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 996/ 34 | 390/ 23 | -| Scheduler, Two Coroutines (man setup) | 1268/ 53 | 662/ 42 | +| Scheduler, LogBinProfiler | 2100/ 286 | 484/ 100 | +| Scheduler, LogBinTableRenderer | 3502/ 304 | 1886/ 118 | +| Scheduler, LogBinJsonRenderer | 3022/ 308 | 1406/ 122 | |---------------------------------------+--------------+-------------| -| Blink Function | 938/ 14 | 332/ 3 | -| Blink Coroutine | 1158/ 32 | 552/ 21 | +| Blink Function | 1948/ 189 | 332/ 3 | +| Blink Coroutine | 2118/ 212 | 502/ 26 | +--------------------------------------------------------------------+ ``` @@ -543,37 +743,41 @@ etc) for a handful of AceRoutine features. Here are some highlights: +--------------------------------------------------------------------+ | functionality | flash/ ram | delta | |---------------------------------------+--------------+-------------| -| Baseline | 260329/27916 | 0/ 0 | +| Baseline | 264981/27984 | 0/ 0 | +|---------------------------------------+--------------+-------------| +| One Delay Function | 265045/27992 | 64/ 8 | +| Two Delay Functions | 265109/27992 | 128/ 8 | |---------------------------------------+--------------+-------------| -| One Delay Function | 260377/27916 | 48/ 0 | -| Two Delay Functions | 260441/27916 | 112/ 0 | +| One Coroutine (millis) | 265177/28028 | 196/ 44 | +| Two Coroutines (millis) | 265337/28060 | 356/ 76 | |---------------------------------------+--------------+-------------| -| One Coroutine | 260525/27944 | 196/ 28 | -| Two Coroutines | 260669/27960 | 340/ 44 | +| One Coroutine (micros) | 265209/28028 | 228/ 44 | +| Two Coroutines (micros) | 265369/28060 | 388/ 76 | |---------------------------------------+--------------+-------------| -| One Coroutine (micros) | 260541/27944 | 212/ 28 | -| Two Coroutines (micros) | 260701/27960 | 372/ 44 | +| One Coroutine (seconds) | 265209/28028 | 228/ 44 | +| Two Coroutines (seconds) | 265385/28060 | 404/ 76 | |---------------------------------------+--------------+-------------| -| One Coroutine (seconds) | 260541/27944 | 212/ 28 | -| Two Coroutines (seconds) | 260717/27960 | 388/ 44 | +| Scheduler, One Coroutine (millis) | 265321/28036 | 340/ 52 | +| Scheduler, Two Coroutines (millis) | 265449/28060 | 468/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine | 260573/27944 | 244/ 28 | -| Scheduler, Two Coroutines | 260701/27968 | 372/ 52 | +| Scheduler, One Coroutine (micros) | 265321/28036 | 340/ 52 | +| Scheduler, Two Coroutines (micros) | 265449/28060 | 468/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 260589/27944 | 260/ 28 | -| Scheduler, Two Coroutines (micros) | 260733/27968 | 404/ 52 | +| Scheduler, One Coroutine (seconds) | 265337/28036 | 356/ 52 | +| Scheduler, Two Coroutines (seconds) | 265497/28060 | 516/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 260589/27944 | 260/ 28 | -| Scheduler, Two Coroutines (seconds) | 260749/27968 | 420/ 52 | +| Scheduler, One Coroutine (setup) | 265337/28036 | 356/ 52 | +| Scheduler, Two Coroutines (setup) | 265513/28060 | 532/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 260605/27944 | 276/ 28 | -| Scheduler, Two Coroutines (setup) | 260765/27968 | 436/ 52 | +| Scheduler, One Coroutine (man setup) | 265337/28036 | 356/ 52 | +| Scheduler, Two Coroutines (man setup) | 265513/28060 | 532/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 260589/27944 | 260/ 28 | -| Scheduler, Two Coroutines (man setup) | 260749/27968 | 420/ 52 | +| Scheduler, LogBinProfiler | 265449/28100 | 468/ 116 | +| Scheduler, LogBinTableRenderer | 267381/28100 | 2400/ 116 | +| Scheduler, LogBinJsonRenderer | 266773/28104 | 1792/ 120 | |---------------------------------------+--------------+-------------| -| Blink Function | 261001/27988 | 672/ 72 | -| Blink Coroutine | 261133/28008 | 804/ 92 | +| Blink Function | 265669/28064 | 688/ 80 | +| Blink Coroutine | 265801/28100 | 820/ 116 | +--------------------------------------------------------------------+ ``` @@ -614,7 +818,7 @@ ESP8266: |---------------------+--------+-------------+--------| | EmptyLoop | 10000 | 0.100 | 0.000 | | DirectScheduling | 10000 | 0.500 | 0.400 | -| CoroutineScheduling | 10000 | 0.900 | 0.800 | +| CoroutineScheduling | 10000 | 1.000 | 0.900 | +---------------------+--------+-------------+--------+ ``` diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 57672fc..3661e46 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -39,6 +39,12 @@ is installed. * [Custom Coroutines](#CustomCoroutines) * [Manual Coroutines](#ManualCoroutines) * [Coroutine Setup](#CoroutineSetup) +* [Coroutine Profiling](#CoroutineProfiling) + * [Creating Profilers Directly](#CreatingProfilersDirectly) + * [Creating Profilers on Heap](#CreatingProfilersOnHeap) + * [Running Coroutine With Profiler](#RunningCoroutineWithProfiler) + * [Running Scheduler With Profiler](#RunningSchedulerWithProfiler) + * [Rendering the Profiler Results](#RenderingProfilerResults) * [Coroutine Communication](#Communication) * [Instance Variables](#InstanceVariables) * [Channels (Experimental)](#Channels) @@ -819,11 +825,6 @@ necessary because the `Coroutine::Coroutine()` constructor automatically inserts itself into the internal singly-linked list. The `setupCoroutine()` is retained for backwards compatibility, but is now marked deprecated. -Starting with v1.3, the name of the coroutine is no longer saved, and -`Coroutine::getName()` does not exist anymore. `CoroutineScheduler::list()` -prints the integer value of the coroutine instance instead of the name of the -coroutine. - ### Direct Scheduling or CoroutineScheduler @@ -1148,6 +1149,265 @@ flash per coroutine. On 32-bit processors, it takes slightly less memory, about AVR processors. The virtual dispatch on `Coroutine::setupCoroutine()` consumes about 14 bytes of flash per invocation. + +## Coroutine Profiling + +Version 1.5 added the ability to profile the execution time of +`Coroutine::runCoroutine()` and render the information as a formatted table, or +as a JSON object. The `CoroutineProfiler` is an interface that allows an object +to receive information about the execution time of the +`Coroutine::runCoroutine()` method: + +```C++ +class CoroutineProfiler { + public: + /** + * Process the completion of the runCoroutine() method which took + * `micros` microseconds. + */ + virtual void updateElapsedMicros(uint32_t micros) = 0; +}; +``` + +Each `Coroutine` object has the ability to hold a pointer to a +`CoroutineProfiler` object: + +```C++ +class Coroutine { + ... + public: + void setProfiler(CoroutineProfiler* profiler); + CoroutineProfiler* getProfiler() const; + + int runCoroutineWithProfiler(); + ... +}; +``` + +Currently only a single implementation of `CoroutineProfiler` is provided, the +`LogBinProfiler`. It contains 32 bins of `uint16_t` which tracks the number of +times a `micros` was seen. The bins are logarithmically scaled, so that Bin 0 +collects all events `<2us`, Bin 1 collects events `<4us`, Bin 2 collects events +`<8us`, Bin 30 collects events `<2147s`, and the last Bin 31 collects events +`<4295s`. + +```C++ +class LogBinProfiler : public CoroutineProfiler { + public: + static const uint8_t kNumBins = 32; + + public: + LogBinProfiler(); + + void updateElapsedMicros(uint32_t micros) override; + void clear(); + + static void createProfilers(); + static void deleteProfilers(); + static void clearProfilers(); + + public: + uint16_t mBins[kNumBins]; +}; +``` + +Details on how to configure and use these are are provided below, but it may +help to look at 2 examples while looking through the following subsections: + +* [HelloCoroutineWithProfiler](examples/HelloCoroutineWithProfiler) +* [HelloSchedulerWithProfiler](examples/HelloSchedulerWithProfiler) + + +### Creating Profilers Directly + +By default, a `Coroutine` has no reference to a `CoroutineProfiler`. The user +can directly assign a profiler instance by creating it statically, then calling +`Coroutine::setProfiler()` like this: + +```C++ +#include +using namespace ace_routine; + +COROUTINE(coroutine1) { + ... +} + +COROUTINE(coroutine1) { + ... +} + +LogBinProfiler profiler1; +LogBinProfiler profiler2; + +void setup() { + ... + coroutine1.setProfiler(&profiler1); + coroutine2.setProfiler(&profiler2); + ... +} +``` + +This technique works well if you have a small number of coroutines. + + +### Creating Profilers on Heap + +If you are using a substantial number of coroutines, it is cumbersome to +manually create these profilers for all coroutines. In that case, you can use +the `LogBinProfiler::createProfilers()` convenience function which loops through +every coroutine (defined by `Coroutine::getRoot()`, and assigns an instance of +`LogBinProfiler` that is created on the heap: + +```C++ +#include +using namespace ace_routine; + +void setup() { + ... + LogBinProfiler::createProfilers(); +} +``` + +In the unlikely event that you delete the Profiler instances which were created +on the heap, you can call the `LogBinProfiler::deleteProfilers()` static method. + +Finally, the `LogBinProfiler::clearProfilers()` static method calls the +`LogBinProfiler::clear()` method on every profiler attached to every coroutine +so that the event count in all the bins are cleared to 0. + + +### Running Coroutine with Profiler + +Once a `Coroutine` is assigned a `CoroutineProfiler`, the statistics can be +gathered in a couple of ways. The simplest is to call the new +`Coroutine::runCoroutineWithProfiler()` instead of the normal +`Coroutine::runCoroutine()` in the global `loop()` function like this: + +```C++ +#include +using namespace ace_routine; + +COROUTINE(myCoroutine) { + ... +} + +LogBinProfiler profiler; + +void setup() { + ... + myCoroutine.setName(F("myCoroutine")); + myCoroutine.setProfiler(&profiler); + ... +} + +void loop() { + myCoroutine.runCoroutineWithProfiler(); + ... +} + +This technique is intended for resource constrained environments, usually 8-bit +processors, where the overhead of a `CoroutineScheduler` is not desired. + + +### Running Scheduler with Profiler + +If the environment is using the `CoroutineScheduler`, it will automatically call +the `Coroutine::runCoroutineWithProfiler()` on each coroutine and gather the +profiling information automatically. + +```C++ +#include +using namespace ace_routine; + +COROUTINE(myCoroutine) { + ... +} + +void setup() { + ... + myCoroutine.setName(F("myCoroutine")); + myCoroutine.setProfiler(&profiler); + + LogBinProfiler::createProfilers(); + CoroutineScheduler::setup(); +} + +void loop() { + CoroutineScheduler::loop(); +} +``` + + +### Rendering the Profiler Results + +The `LogBinProfiler` comes with 2 rendering classes: + +* `LogBinTableRenderer` + * displays the event count in a human-readable formatted table with fixed + column widths +* `LogBinJsonRenderer` + * prints the same info as a JSON object + +These classes expose a simple `printTo()` static function like this: + +``` +class LogBinTableRenderer { + public: + static void printTo( + Print& printer, + uint8_t startBin, + uint8_t endBin, + bool clear = true, + bool rollup = true + ); +}; + +class LogBinJsonRenderer{ + public: + static void printTo( + Print& printer, + uint8_t startBin, + uint8_t endBin, + bool clear = true, + bool rollup = true + ); +}; +``` + +* The `printer` is usually the `Serial` object, but can be changed to something + else if needed. +* The `startBin` (0-31) and `endBin` (0-32) identify the bins which should be + printed. + * A range of something like [2, 14) is useful to keep the width of the table + reasonable. + * Often the bins lower and higher than this range do not contain any events. +* The `clear` flag (default true) causes the bins to be cleared (through the + `LogBinProfiler::clear()` method) so that new events can be tracked. +* The `rollup` flag (default true) causes roll up of the exterior bins. + * Events before `startBin` are added to the first bin. + * Events at or after `endBin` are added to the last bin (at `endBin-1`) + +For example, calling `LogBinTableRenderer::printTo(Serial, 2, 16)` prints +something like this: + +``` +name <16us <32us <64us<128us<256us<512us <1ms <2ms <4ms <8ms >> +0x1DB 16898 52688 0 0 0 0 0 0 0 0 1 +readPin 65535 1128 0 0 0 0 0 0 0 0 0 +blinkLed 65535 800 0 0 0 0 0 0 0 0 0 +``` + +And calling `LogBinJsonRenderer::printTo(Serial, 2, 16)` prints something like +this: + +``` +{ +"0x1DB":[16898,52688,0,0,0,0,0,0,0,0,1], +"readPin":[65535,1128,0,0,0,0,0,0,0,0,0], +"blinkLed":[65535,800,0,0,0,0,0,0,0,0,0] +} +``` + ## Coroutine Communication From 07bfdc16e17fe1bd5b265295be5354fecc1a9189 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 15:52:37 -0700 Subject: [PATCH 46/59] Coroutine.cpp: Store sStatusStrings[] in PROGMEM, saving 14 bytes (8-bits) and 28 bytes (ESP8266) of static RAM if Coroutine::statusPrintTo() is used --- src/ace_routine/Coroutine.cpp | 9 +++++---- src/ace_routine/Coroutine.h | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/ace_routine/Coroutine.cpp b/src/ace_routine/Coroutine.cpp index 85b9ea2..ba40647 100644 --- a/src/ace_routine/Coroutine.cpp +++ b/src/ace_routine/Coroutine.cpp @@ -29,9 +29,8 @@ namespace ace_routine { // Create the sStatusStrings lookup table to translate Status integer to a // human-readable string. When it is used, it increases flash memory by 86 -// bytes, and static RAM by 14 bytes. It is currently only used by -// CoroutineScheduler::list() but I think it's worth it to make debugging -// easier. +// bytes. It is currently only used by CoroutineScheduler::list() but I think +// it's worth it to make debugging easier. static const char kStatusSuspendedString[] PROGMEM = "Suspended"; static const char kStatusYieldingString[] PROGMEM = "Yielding"; @@ -40,7 +39,9 @@ static const char kStatusRunningString[] PROGMEM = "Running"; static const char kStatusEndingString[] PROGMEM = "Ending"; static const char kStatusTerminatedString[] PROGMEM = "Terminated"; -const __FlashStringHelper* const sStatusStrings[] = { +// Store the array of PROGMEM pointers in PROGMEM as well, saving 14 bytes of +// RAM on AVR, and 28 bytes on ESP8266. +const __FlashStringHelper* const sStatusStrings[] PROGMEM = { FPSTR(kStatusSuspendedString), FPSTR(kStatusYieldingString), FPSTR(kStatusDelayingString), diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index bdd00b7..0554b83 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -267,7 +267,7 @@ extern className##_##name name namespace ace_routine { /** A lookup table from Status integer to human-readable strings. */ -extern const __FlashStringHelper* const sStatusStrings[]; +extern const __FlashStringHelper* const sStatusStrings[] PROGMEM; // Forward declaration of CoroutineSchedulerTemplate template class CoroutineSchedulerTemplate; @@ -637,7 +637,8 @@ class CoroutineTemplate { /** Print the human-readable string of the Status. */ void statusPrintTo(Print& printer) { - printer.print(sStatusStrings[mStatus]); + printer.print((const __FlashStringHelper*) + pgm_read_ptr(&sStatusStrings[mStatus])); } /** From c0fe99942b6010b5e58360c13bd9803f35e66f40 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 16:06:56 -0700 Subject: [PATCH 47/59] Coroutine.h: Add a T_DELAY template parameter to CoroutineTemplate class, set it to uint16_t --- src/ace_routine/Coroutine.h | 41 ++++++++++++++------- src/ace_routine/testing/TestableCoroutine.h | 2 +- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/ace_routine/Coroutine.h b/src/ace_routine/Coroutine.h index 0554b83..48d8e24 100644 --- a/src/ace_routine/Coroutine.h +++ b/src/ace_routine/Coroutine.h @@ -30,6 +30,7 @@ SOFTWARE. #include // PrintStr<> #include "CoroutineProfiler.h" #include "ClockInterface.h" +#include "compat.h" // PROGMEM class __FlashStringHelper; class AceRoutineTest_statusStrings; @@ -275,10 +276,21 @@ template class CoroutineSchedulerTemplate; /** * Base class of all coroutines. The actual coroutine code is an implementation * of the virtual runCoroutine() method. + * + * @tparam T_CLOCK class that provides micros(), millis() and seconds() + * functions, usually `ClockInterface` but can be something else for testing + * purposes. + * @tparam T_DELAY type used to store the mDelayStart and mDelayDuration, + * usually `uint16_t`. It may be possible to create a variant set of + * Coroutine32 and CoroutineScheduler32 classes which use a `uint32_t` + * instead of a `uint16_t`. This would probably allow the + * `COROUTINE_DELAY()`, `COROUTINE_DELAY_MICROS()` and + * `COROUTINE_DELAY_SECONDS()` macros to accept 32-bit integers instead of + * 16-bits. I have not tested this possibility at all. */ -template +template class CoroutineTemplate { - friend class CoroutineSchedulerTemplate>; + friend class CoroutineSchedulerTemplate>; friend class ::AceRoutineTest_statusStrings; friend class ::SuspendTest_suspendAndResume; @@ -459,22 +471,22 @@ class CoroutineTemplate { /** Check if delay millis time is over. */ bool isDelayExpired() const { - uint16_t nowMillis = coroutineMillis(); - uint16_t elapsed = nowMillis - mDelayStart; + T_DELAY nowMillis = coroutineMillis(); + T_DELAY elapsed = nowMillis - mDelayStart; return elapsed >= mDelayDuration; } /** Check if delay micros time is over. */ bool isDelayMicrosExpired() const { - uint16_t nowMicros = coroutineMicros(); - uint16_t elapsed = nowMicros - mDelayStart; + T_DELAY nowMicros = coroutineMicros(); + T_DELAY elapsed = nowMicros - mDelayStart; return elapsed >= mDelayDuration; } /** Check if delay seconds time is over. */ bool isDelaySecondsExpired() const { - uint16_t nowSeconds = coroutineSeconds(); - uint16_t elapsed = nowSeconds - mDelayStart; + T_DELAY nowSeconds = coroutineSeconds(); + T_DELAY elapsed = nowSeconds - mDelayStart; return elapsed >= mDelayDuration; } @@ -684,7 +696,7 @@ class CoroutineTemplate { * COROUTINE_DELAY() macro inside Coroutine::runCoroutine()) because the * clock increments by 1 millisecond.) */ - void setDelayMillis(uint16_t delayMillis) { + void setDelayMillis(T_DELAY delayMillis) { mDelayStart = coroutineMillis(); // If delayMillis is a compile-time constant, the compiler seems to @@ -698,7 +710,7 @@ class CoroutineTemplate { * Configure the delay timer for delayMicros. Similar to seDelayMillis(), * the maximum delay is 32767 micros. */ - void setDelayMicros(uint16_t delayMicros) { + void setDelayMicros(T_DELAY delayMicros) { mDelayStart = coroutineMicros(); // If delayMicros is a compile-time constant, the compiler seems to @@ -712,7 +724,7 @@ class CoroutineTemplate { * Configure the delay timer for delaySeconds. Similar to seDelayMillis(), * the maximum delay is 32767 seconds. */ - void setDelaySeconds(uint16_t delaySeconds) { + void setDelaySeconds(T_DELAY delaySeconds) { mDelayStart = coroutineSeconds(); // If delaySeconds is a compile-time constant, the compiler seems to @@ -791,15 +803,16 @@ class CoroutineTemplate { * COROUTINE_DELAY_SECONDS(). The unit of this number is context dependent, * milliseconds, microseconds, or seconds. */ - uint16_t mDelayStart; + T_DELAY mDelayStart; /** * Delay time specified by COROUTINE_DELAY(), COROUTINE_DELAY_MICROS() or, * COROUTINE_DELAY_SECONDS(). The unit of this number is context dependent, * milliseconds, microseconds, or seconds. */ - uint16_t mDelayDuration; + T_DELAY mDelayDuration; + /** Pointer to a profiler instance, either static or on the heap. */ CoroutineProfiler* mProfiler = nullptr; }; @@ -809,7 +822,7 @@ class CoroutineTemplate { * class of all user-defined coroutines created using the COROUTINE() macro or * through manual subclassing of this class. */ -using Coroutine = CoroutineTemplate; +using Coroutine = CoroutineTemplate; } diff --git a/src/ace_routine/testing/TestableCoroutine.h b/src/ace_routine/testing/TestableCoroutine.h index 2cbb512..71878df 100644 --- a/src/ace_routine/testing/TestableCoroutine.h +++ b/src/ace_routine/testing/TestableCoroutine.h @@ -35,7 +35,7 @@ namespace testing { * A version of Coroutine that uses the TestableClockInterface to provide the * clock can for unit testing purposes. */ -using TestableCoroutine = CoroutineTemplate; +using TestableCoroutine = CoroutineTemplate; } } From 0d56460c6ed5e8ed9dcee87b08793e0e89ef565a Mon Sep 17 00:00:00 2001 From: Brian Park Date: Thu, 17 Mar 2022 16:38:18 -0700 Subject: [PATCH 48/59] USER_GUIDE.md: Fix markdown errors --- USER_GUIDE.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 3661e46..ccb2416 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -1262,6 +1262,14 @@ every coroutine (defined by `Coroutine::getRoot()`, and assigns an instance of #include using namespace ace_routine; +COROUTINE(coroutine1) { + ... +} + +COROUTINE(coroutine1) { + ... +} + void setup() { ... LogBinProfiler::createProfilers(); @@ -1304,6 +1312,7 @@ void loop() { myCoroutine.runCoroutineWithProfiler(); ... } +``` This technique is intended for resource constrained environments, usually 8-bit processors, where the overhead of a `CoroutineScheduler` is not desired. @@ -1350,7 +1359,7 @@ The `LogBinProfiler` comes with 2 rendering classes: These classes expose a simple `printTo()` static function like this: -``` +```C++ class LogBinTableRenderer { public: static void printTo( From 4c63da534c73e581a0207e47b3f92e583b0f1af3 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 18 Mar 2022 11:56:22 -0700 Subject: [PATCH 49/59] CoroutineScheduler.h: Extract profiling code into loopWithProfiler(), keeping loop() free of profiling --- CHANGELOG.md | 25 +++---- USER_GUIDE.md | 73 ++++++++++++++----- .../HelloSchedulerWithProfiler.ino | 2 +- src/ace_routine/CoroutineScheduler.h | 69 +++++++++++++++--- 4 files changed, 124 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0467399..b41977f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,35 +10,32 @@ * Resource consumption * Increases flash usage by 6-10 bytes per coroutine. * Increases static ram usage by 3 bytes (AVR) or 4 bytes (32-bit) - per coroutine. + per coroutine, plus the additional storage for string itself. * Support profiling of `Coroutine::runCoroutine()` execution time. * See [Coroutine Profiling](USER_GUIDE.md#CoroutineProfiling) in the `USER_GUIDE.md`. * API changes * Add `CoroutineProfiler` interface with a `updateElapsedMicros()` method. - * Add `Coroutine::setProfiler()`. + * Add `Coroutine::setProfiler()` to store the profiler pointer. * Add `Coroutine::runCoroutineWithProfiler()` which measures the - elapsed time of `runCoroutine()`. - * Update `CoroutineScheduler::runCoroutine()` to call - `runCoroutineWithProfiler()`. + elapsed time of `runCoroutine()` and calls + `CoroutineProfiler::updateElapsedMicros()`. + * Add `CoroutineScheduler::runCoroutineWithProfiler()` which calls + `Coroutine::runCoroutineWithProfiler()` instead of the normal + `Coroutine::runCoroutine()`. + * Add `CoroutineScheduler::loopWithProfiler()` public static method + which calls `runCoroutineWithProfiler()`. * Provide `LogBinProfiler` subclass of `CoroutineProfiler`. * Keeps a frequency count of the elapsed microseconds using 32 bins representing the `log2()` function of the elapsed microseconds. - * Provide 2 renderers: + * Provide 2 renderers of `LogBinProfiler`: * `LogBinTableRenderer::printTo()` prints a formatted table of the frequency count over all coroutines. This represents a poor-man's version of the log-log graph of the frequency count. * `LogBinJsonRenderer::printTo()` prints the frequency count in JSON format. - * Resource consumption - * Increases static ram usage by 2 bytes (AVR) or 4 bytes (32-bit) - per coroutine. - * Increases latency of `CoroutineScheduler::runCoroutine()` by only - 100ns (AVR, ESP8266), 133ns (STM32, Teensy 3.2), and 33ns (ESP32). - * Increases the flash size of the `CoroutineScheduler` by 100-140 - bytes for both 8-bit and 32-bit processors, even if - `CoroutineProfiler` is not used. This is a one-time hit. + * Memory consumption * See [HelloCoroutineWithProfiler](examples/HelloCoroutineWithProfiler) and [HelloSchedulerWithProfiler](examples/HelloSchedulerWithProfiler). * Thanks to peufeu2@ who provided the ideas and proof of concept in diff --git a/USER_GUIDE.md b/USER_GUIDE.md index ccb2416..621b172 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -40,11 +40,12 @@ is installed. * [Manual Coroutines](#ManualCoroutines) * [Coroutine Setup](#CoroutineSetup) * [Coroutine Profiling](#CoroutineProfiling) - * [Creating Profilers Directly](#CreatingProfilersDirectly) - * [Creating Profilers on Heap](#CreatingProfilersOnHeap) + * [Creating Profilers Manually](#CreatingProfilersManually) + * [Creating Profilers Automatically](#CreatingProfilersAutomatically) * [Running Coroutine With Profiler](#RunningCoroutineWithProfiler) * [Running Scheduler With Profiler](#RunningSchedulerWithProfiler) * [Rendering the Profiler Results](#RenderingProfilerResults) + * [Profiling Resource Consumption](#ProfilingResourceConsumption) * [Coroutine Communication](#Communication) * [Instance Variables](#InstanceVariables) * [Channels (Experimental)](#Channels) @@ -1217,8 +1218,8 @@ help to look at 2 examples while looking through the following subsections: * [HelloCoroutineWithProfiler](examples/HelloCoroutineWithProfiler) * [HelloSchedulerWithProfiler](examples/HelloSchedulerWithProfiler) - -### Creating Profilers Directly + +### Creating Profilers Manually By default, a `Coroutine` has no reference to a `CoroutineProfiler`. The user can directly assign a profiler instance by creating it statically, then calling @@ -1249,14 +1250,13 @@ void setup() { This technique works well if you have a small number of coroutines. - -### Creating Profilers on Heap + +### Creating Profilers Automatically If you are using a substantial number of coroutines, it is cumbersome to manually create these profilers for all coroutines. In that case, you can use the `LogBinProfiler::createProfilers()` convenience function which loops through -every coroutine (defined by `Coroutine::getRoot()`, and assigns an instance of -`LogBinProfiler` that is created on the heap: +every coroutine and creates an instance of `LogBinProfiler` on the heap: ```C++ #include @@ -1276,8 +1276,9 @@ void setup() { } ``` -In the unlikely event that you delete the Profiler instances which were created -on the heap, you can call the `LogBinProfiler::deleteProfilers()` static method. +In the unlikely event that you need to delete the Profiler instances which were +created on the heap, you can call the `LogBinProfiler::deleteProfilers()` static +method. Finally, the `LogBinProfiler::clearProfilers()` static method calls the `LogBinProfiler::clear()` method on every profiler attached to every coroutine @@ -1309,20 +1310,16 @@ void setup() { } void loop() { - myCoroutine.runCoroutineWithProfiler(); + myCoroutine.runCoroutineWithProfiler(); // <---- instead of runCoroutine() ... } ``` -This technique is intended for resource constrained environments, usually 8-bit -processors, where the overhead of a `CoroutineScheduler` is not desired. - ### Running Scheduler with Profiler -If the environment is using the `CoroutineScheduler`, it will automatically call -the `Coroutine::runCoroutineWithProfiler()` on each coroutine and gather the -profiling information automatically. +To activate profiling when using the `CoroutineScheduler`, just replace the call +to `CoroutineScheduler::loop()` with `CoroutineScheduler::loopWithProfiler()`. ```C++ #include @@ -1342,7 +1339,7 @@ void setup() { } void loop() { - CoroutineScheduler::loop(); + CoroutineScheduler::loopWithProfiler(); // <---- instead of loop() } ``` @@ -1417,6 +1414,46 @@ this: } ``` + +### Profiling Resource Consumption + +The ability to profile the execution time of coroutines does not come for free, +but I have tried to make it as cheap as possible. + +**Memory consumption** + +If the profiling feature is not wanted, you can continue to use the +`Coroutine::runCoroutine()` or the `CoroutineScheduler::loop()` functions, and +the flash usage will not increase. The only additional resource is 2 extra bytes +(8-bit processors) or 4 extra bytes (32-bit processors) of static RAM, *per +coroutine*, because each coroutine holds a pointer to the `CoroutineProfiler`, +even if it is not used. + +If the profiling feature is enabled, the +[MemoryBenchmark](examples/MemoryBenchmark) program shows that: + +* Using `Coroutine::runCoroutineWithProfiler()` consumes 50-80 bytes of extra + bytes of flash *per coroutine* compared to the normal + `Coroutine::runCoroutine()`, probably due to the virtual dispatch. +* Using `CoroutineScheduler::loopWithProfiler()` consumes an additional 50-100 + bytes of flash compared to using `CoroutineScheduler::loop()`, *plus* the + additional 50-80 bytes of flash *per coroutine* because the dispatching is + routed to `Coroutine::runCoroutineWithProfiler()`. +* The `LogBinProfiler` consumes at least 64 bytes of static RAM per instance + because it holds an array of 32 bin of `uint16_t` integers. It also increases + the flash usage by 120-150 bytes, but that's a one-time hit, not per profiler + or coroutine. +* The `LogBinTableRenderer` increases flash usage by 1300-2000 bytes. +* The `LogBinJsonRenderer` increases flash usage by 700-1200 bytes. + +**CPU consumption** + +The [AutoBenchmark](examples/AutoBenchmark) program shows that calling the +profiler-enabled methods, `Coroutine::runCoroutineWithProfiler()` and +`CoroutineScheduler::loopWithProfiler(), increases latency by only 100ns (AVR, +ESP8266), 133ns (STM32, Teensy 3.2), and 33ns (ESP32). Most applications should +not be affected by this small increase in latency. + ## Coroutine Communication diff --git a/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino b/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino index 6bb4b56..07ead9c 100644 --- a/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino +++ b/examples/HelloSchedulerWithProfiler/HelloSchedulerWithProfiler.ino @@ -109,5 +109,5 @@ void setup() { } void loop() { - CoroutineScheduler::loop(); + CoroutineScheduler::loopWithProfiler(); } diff --git a/src/ace_routine/CoroutineScheduler.h b/src/ace_routine/CoroutineScheduler.h index 71e7043..2fcc094 100644 --- a/src/ace_routine/CoroutineScheduler.h +++ b/src/ace_routine/CoroutineScheduler.h @@ -92,11 +92,21 @@ class CoroutineSchedulerTemplate { /** * Run the current coroutine using the current scheduler. This method * returns when the underlying Coroutine suspends execution, which allows - * the system loop() to return to do systems processing, such as WiFi. + * the system loop() to return to do systems processing. * Everyone must cooperate to make the whole thing work. */ static void loop() { getScheduler()->runCoroutine(); } + /** + * Run the current coroutine using the current scheduler with the coroutine + * profiler enabled. This method returns when the underlying Coroutine + * suspends execution, which allows the system loop() to return to do + * systems processing. Everyone must cooperate to make the whole thing work. + */ + static void loopWithProfiler() { + getScheduler()->runCoroutineWithProfiler(); + } + /** * Print out the known coroutines to the printer (usually Serial). Note that * if this method is never called, the linker will strip out the code. If @@ -146,7 +156,10 @@ class CoroutineSchedulerTemplate { } } - /** Run the current coroutine. */ + /** + * Run the current coroutine without the overhead of the profiler by calling + * Coroutine::runCoroutine(). + */ void runCoroutine() { // If reached the end, start from the beginning again. if (*mCurrent == nullptr) { @@ -159,11 +172,46 @@ class CoroutineSchedulerTemplate { } } - #if ACE_ROUTINE_DEBUG == 1 - Serial.print(F("Processing ")); - Serial.print((uintptr_t) (*mCurrent)); - Serial.println(); - #endif + // Handle the coroutine's dispatch back to the last known internal status. + switch ((*mCurrent)->getStatus()) { + case T_COROUTINE::kStatusYielding: + case T_COROUTINE::kStatusDelaying: + // The coroutine itself knows whether it is yielding or delaying, and + // its continuation context determines whether to call + // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or + // Coroutine::isDelaySecondsExpired(). + (*mCurrent)->runCoroutine(); + break; + + case T_COROUTINE::kStatusEnding: + // mark it terminated + (*mCurrent)->setTerminated(); + break; + + default: + // For all other cases, just skip to the next coroutine. + break; + } + + // Go to the next coroutine + mCurrent = (*mCurrent)->getNext(); + } + + /* + * Run the current coroutine with profiling enabled by calling + * Coroutine::runCoroutineWithProfiler(). + */ + void runCoroutineWithProfiler() { + // If reached the end, start from the beginning again. + if (*mCurrent == nullptr) { + mCurrent = T_COROUTINE::getRoot(); + // Return if the list is empty. Checking for a null getRoot() inside the + // if-statement is deliberate, since it optimizes the common case where + // the linked list is not empty. + if (*mCurrent == nullptr) { + return; + } + } // Handle the coroutine's dispatch back to the last known internal status. switch ((*mCurrent)->getStatus()) { @@ -174,11 +222,8 @@ class CoroutineSchedulerTemplate { // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or // Coroutine::isDelaySecondsExpired(). // - // The `CoroutineScheduler` always enables the profiler by calling - // `Coroutine::runCoroutineWithProfiler()`. If memory usage is a - // problem, then consider calling the `Coroutine::runCoroutine()` - // directly in the global `loop()` function, instead of going through - // the `CoroutineScheduler`. + // This version calls `Coroutine::runCoroutineWithProfiler()` to + // enable the profiler. (*mCurrent)->runCoroutineWithProfiler(); break; From 25f42d6d9e51938239172dc2aa7903de4136e243 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 18 Mar 2022 11:57:15 -0700 Subject: [PATCH 50/59] MemoryBenchmark: Add separate benchmarks for Coroutine::runCoroutineWithProfiler() and CoroutineScheduler::loopWithProfiler() --- examples/MemoryBenchmark/MemoryBenchmark.ino | 156 +++++++++---- examples/MemoryBenchmark/README.md | 220 +++++++++++------- examples/MemoryBenchmark/attiny.txt | 34 +-- examples/MemoryBenchmark/collect.sh | 2 +- examples/MemoryBenchmark/esp32.txt | 34 +-- examples/MemoryBenchmark/esp8266.txt | 34 +-- examples/MemoryBenchmark/generate_table.awk | 36 +-- examples/MemoryBenchmark/micro.txt | 34 +-- examples/MemoryBenchmark/nano.txt | 34 +-- examples/MemoryBenchmark/stm32.txt | 34 +-- examples/MemoryBenchmark/teensy32.txt | 34 +-- .../validate_using_epoxy_duino.sh | 2 +- 12 files changed, 404 insertions(+), 250 deletions(-) diff --git a/examples/MemoryBenchmark/MemoryBenchmark.ino b/examples/MemoryBenchmark/MemoryBenchmark.ino index d114c1a..d99d3b2 100644 --- a/examples/MemoryBenchmark/MemoryBenchmark.ino +++ b/examples/MemoryBenchmark/MemoryBenchmark.ino @@ -24,21 +24,25 @@ #define FEATURE_TWO_COROUTINES_MICROS 6 #define FEATURE_ONE_COROUTINE_SECONDS 7 #define FEATURE_TWO_COROUTINES_SECONDS 8 -#define FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS 9 -#define FEATURE_SCHEDULER_TWO_COROUTINES_MILLIS 10 -#define FEATURE_SCHEDULER_ONE_COROUTINE_MICROS 11 -#define FEATURE_SCHEDULER_TWO_COROUTINES_MICROS 12 -#define FEATURE_SCHEDULER_ONE_COROUTINE_SECONDS 13 -#define FEATURE_SCHEDULER_TWO_COROUTINES_SECONDS 14 -#define FEATURE_SCHEDULER_SETUP_ONE_COROUTINE 15 -#define FEATURE_SCHEDULER_SETUP_TWO_COROUTINES 16 -#define FEATURE_SCHEDULER_MANUAL_SETUP_ONE_COROUTINE 17 -#define FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES 18 -#define FEATURE_LOG_BIN_PROFILER 19 -#define FEATURE_LOG_BIN_TABLE_RENDERER 20 -#define FEATURE_LOG_BIN_JSON_RENDERER 21 -#define FEATURE_BLINK_FUNCTION 22 -#define FEATURE_BLINK_COROUTINE 23 +#define FEATURE_ONE_COROUTINE_WITH_PROFILER 9 +#define FEATURE_TWO_COROUTINES_WITH_PROFILER 10 +#define FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS 11 +#define FEATURE_SCHEDULER_TWO_COROUTINES_MILLIS 12 +#define FEATURE_SCHEDULER_ONE_COROUTINE_MICROS 13 +#define FEATURE_SCHEDULER_TWO_COROUTINES_MICROS 14 +#define FEATURE_SCHEDULER_ONE_COROUTINE_SECONDS 15 +#define FEATURE_SCHEDULER_TWO_COROUTINES_SECONDS 16 +#define FEATURE_SCHEDULER_SETUP_ONE_COROUTINE 17 +#define FEATURE_SCHEDULER_SETUP_TWO_COROUTINES 18 +#define FEATURE_SCHEDULER_MANUAL_SETUP_ONE_COROUTINE 19 +#define FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES 20 +#define FEATURE_SCHEDULER_ONE_COROUTINE_WITH_PROFILER 21 +#define FEATURE_SCHEDULER_TWO_COROUTINES_WITH_PROFILER 22 +#define FEATURE_SCHEDULER_LOG_BIN_PROFILER 23 +#define FEATURE_SCHEDULER_LOG_BIN_TABLE_RENDERER 24 +#define FEATURE_SCHEDULER_LOG_BIN_JSON_RENDERER 25 +#define FEATURE_BLINK_FUNCTION 26 +#define FEATURE_BLINK_COROUTINE 27 #if FEATURE != FEATURE_BASELINE #include @@ -165,6 +169,31 @@ volatile int disableCompilerOptimization = 0; } } +#elif FEATURE == FEATURE_ONE_COROUTINE_WITH_PROFILER + + COROUTINE(a) { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + +#elif FEATURE == FEATURE_TWO_COROUTINES_WITH_PROFILER + + COROUTINE(a) { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + + COROUTINE(b) { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + #elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS class MyCoroutine : public Coroutine { @@ -384,6 +413,56 @@ volatile int disableCompilerOptimization = 0; MyCoroutineA a; MyCoroutineB b; +#elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_WITH_PROFILER + + class MyCoroutine : public Coroutine { + public: + int runCoroutine() override { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + }; + + MyCoroutine a; + +#elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES_WITH_PROFILER + + class MyCoroutineA : public Coroutine { + public: + int runCoroutine() override { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + }; + + class MyCoroutineB : public Coroutine { + public: + int runCoroutine() override { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + }; + + MyCoroutineA a; + MyCoroutineB b; + +#elif FEATURE == FEATURE_SCHEDULER_LOG_BIN_PROFILER \ + || FEATURE == FEATURE_SCHEDULER_LOG_BIN_TABLE_RENDERER \ + || FEATURE == FEATURE_SCHEDULER_LOG_BIN_JSON_RENDERER + + COROUTINE(profiled) { + COROUTINE_LOOP() { + disableCompilerOptimization = 1; + COROUTINE_DELAY(10); + } + } + #elif FEATURE == FEATURE_BLINK_FUNCTION #ifndef LED_BUILTIN @@ -416,17 +495,6 @@ volatile int disableCompilerOptimization = 0; } } -#elif FEATURE == FEATURE_LOG_BIN_PROFILER \ - || FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER \ - || FEATURE == FEATURE_LOG_BIN_JSON_RENDERER - - COROUTINE(profiled) { - COROUTINE_LOOP() { - disableCompilerOptimization = 1; - COROUTINE_DELAY(10); - } - } - #elif FEATURE == FEATURE_BLINK_COROUTINE #ifndef LED_BUILTIN @@ -463,9 +531,9 @@ volatile int disableCompilerOptimization = 0; FooClass* foo; #endif -#if FEATURE == FEATURE_LOG_BIN_PROFILER \ - || FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER \ - || FEATURE == FEATURE_LOG_BIN_JSON_RENDERER +#if FEATURE == FEATURE_SCHEDULER_LOG_BIN_PROFILER \ + || FEATURE == FEATURE_SCHEDULER_LOG_BIN_TABLE_RENDERER \ + || FEATURE == FEATURE_SCHEDULER_LOG_BIN_JSON_RENDERER LogBinProfiler profiler; #endif @@ -484,8 +552,9 @@ void setup() { foo = new FooClass(); #endif +// Setup the CoroutineScheduler for FEATURE_* which use it. #if FEATURE >= FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS \ - && FEATURE <= FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES + && FEATURE < FEATURE_BLINK_FUNCTION CoroutineScheduler::setup(); #if FEATURE == FEATURE_SCHEDULER_SETUP_ONE_COROUTINE \ @@ -500,9 +569,9 @@ void setup() { #endif -#if FEATURE == FEATURE_LOG_BIN_PROFILER \ - || FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER \ - || FEATURE == FEATURE_LOG_BIN_JSON_RENDERER +#if FEATURE == FEATURE_SCHEDULER_LOG_BIN_PROFILER \ + || FEATURE == FEATURE_SCHEDULER_LOG_BIN_TABLE_RENDERER \ + || FEATURE == FEATURE_SCHEDULER_LOG_BIN_JSON_RENDERER profiled.setProfiler(&profiler); #endif } @@ -534,6 +603,11 @@ void loop() { #elif FEATURE == FEATURE_TWO_COROUTINES_SECONDS a.runCoroutine(); b.runCoroutine(); +#elif FEATURE == FEATURE_ONE_COROUTINE_WITH_PROFILER + a.runCoroutineWithProfiler(); +#elif FEATURE == FEATURE_TWO_COROUTINES_WITH_PROFILER + a.runCoroutineWithProfiler(); + b.runCoroutineWithProfiler(); #elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_MILLIS CoroutineScheduler::loop(); #elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES_MILLIS @@ -554,14 +628,18 @@ void loop() { CoroutineScheduler::loop(); #elif FEATURE == FEATURE_SCHEDULER_MANUAL_SETUP_TWO_COROUTINES CoroutineScheduler::loop(); -#elif FEATURE == FEATURE_LOG_BIN_PROFILER - CoroutineScheduler::loop(); +#elif FEATURE == FEATURE_SCHEDULER_ONE_COROUTINE_WITH_PROFILER + CoroutineScheduler::loopWithProfiler(); +#elif FEATURE == FEATURE_SCHEDULER_TWO_COROUTINES_WITH_PROFILER + CoroutineScheduler::loopWithProfiler(); +#elif FEATURE == FEATURE_SCHEDULER_LOG_BIN_PROFILER + CoroutineScheduler::loopWithProfiler(); disableCompilerOptimization = profiler.mBins[3]; -#elif FEATURE == FEATURE_LOG_BIN_TABLE_RENDERER - CoroutineScheduler::loop(); +#elif FEATURE == FEATURE_SCHEDULER_LOG_BIN_TABLE_RENDERER + CoroutineScheduler::loopWithProfiler(); LogBinTableRenderer::printTo(Serial, 0, 32); -#elif FEATURE == FEATURE_LOG_BIN_JSON_RENDERER - CoroutineScheduler::loop(); +#elif FEATURE == FEATURE_SCHEDULER_LOG_BIN_JSON_RENDERER + CoroutineScheduler::loopWithProfiler(); LogBinJsonRenderer::printTo(Serial, 0, 32); #elif FEATURE == FEATURE_BLINK_COROUTINE blink.runCoroutine(); diff --git a/examples/MemoryBenchmark/README.md b/examples/MemoryBenchmark/README.md index 588e716..7bf7d18 100644 --- a/examples/MemoryBenchmark/README.md +++ b/examples/MemoryBenchmark/README.md @@ -202,24 +202,30 @@ $ make README.md | One Coroutine (seconds) | 1302/ 107 | 276/ 26 | | Two Coroutines (seconds) | 1524/ 131 | 498/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 1396/ 109 | 370/ 28 | -| Scheduler, Two Coroutines (millis) | 1582/ 133 | 556/ 52 | +| One Coroutine, Profiler | 1276/ 107 | 250/ 26 | +| Two Coroutines, Profiler | 1528/ 131 | 502/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 1364/ 109 | 338/ 28 | -| Scheduler, Two Coroutines (micros) | 1518/ 133 | 492/ 52 | +| Scheduler, One Coroutine (millis) | 1336/ 109 | 310/ 28 | +| Scheduler, Two Coroutines (millis) | 1522/ 133 | 496/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 1492/ 109 | 466/ 28 | -| Scheduler, Two Coroutines (seconds) | 1706/ 133 | 680/ 52 | +| Scheduler, One Coroutine (micros) | 1304/ 109 | 278/ 28 | +| Scheduler, Two Coroutines (micros) | 1458/ 133 | 432/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 1446/ 109 | 420/ 28 | -| Scheduler, Two Coroutines (setup) | 1728/ 133 | 702/ 52 | +| Scheduler, One Coroutine (seconds) | 1432/ 109 | 406/ 28 | +| Scheduler, Two Coroutines (seconds) | 1646/ 133 | 620/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 1424/ 109 | 398/ 28 | -| Scheduler, Two Coroutines (man setup) | 1714/ 133 | 688/ 52 | +| Scheduler, One Coroutine (setup) | 1388/ 109 | 362/ 28 | +| Scheduler, Two Coroutines (setup) | 1670/ 133 | 644/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 1500/ 181 | 474/ 100 | -| Scheduler, LogBinTableRenderer | 2864/ 193 | 1838/ 112 | -| Scheduler, LogBinJsonRenderer | 2398/ 197 | 1372/ 116 | +| Scheduler, One Coroutine (man setup) | 1364/ 109 | 338/ 28 | +| Scheduler, Two Coroutines (man setup) | 1654/ 133 | 628/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine, Profiler | 1396/ 109 | 370/ 28 | +| Scheduler, Two Coroutines, Profiler | 1582/ 133 | 556/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 1512/ 181 | 486/ 100 | +| Scheduler, LogBinTableRenderer | 2876/ 193 | 1850/ 112 | +| Scheduler, LogBinJsonRenderer | 2410/ 197 | 1384/ 116 | |---------------------------------------+--------------+-------------| | Blink Function | 1176/ 84 | 150/ 3 | | Blink Coroutine | 1330/ 107 | 304/ 26 | @@ -251,24 +257,30 @@ $ make README.md | One Coroutine (seconds) | 1904/ 212 | 288/ 26 | | Two Coroutines (seconds) | 2130/ 236 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 1992/ 214 | 376/ 28 | -| Scheduler, Two Coroutines (millis) | 2178/ 238 | 562/ 52 | +| One Coroutine, Profiler | 1874/ 212 | 258/ 26 | +| Two Coroutines, Profiler | 2132/ 236 | 516/ 50 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (millis) | 1928/ 214 | 312/ 28 | +| Scheduler, Two Coroutines (millis) | 2114/ 238 | 498/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (micros) | 1900/ 214 | 284/ 28 | +| Scheduler, Two Coroutines (micros) | 2058/ 238 | 442/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 1964/ 214 | 348/ 28 | -| Scheduler, Two Coroutines (micros) | 2122/ 238 | 506/ 52 | +| Scheduler, One Coroutine (seconds) | 2028/ 214 | 412/ 28 | +| Scheduler, Two Coroutines (seconds) | 2246/ 238 | 630/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 2092/ 214 | 476/ 28 | -| Scheduler, Two Coroutines (seconds) | 2310/ 238 | 694/ 52 | +| Scheduler, One Coroutine (setup) | 1978/ 214 | 362/ 28 | +| Scheduler, Two Coroutines (setup) | 2264/ 238 | 648/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 2046/ 214 | 430/ 28 | -| Scheduler, Two Coroutines (setup) | 2332/ 238 | 716/ 52 | +| Scheduler, One Coroutine (man setup) | 1956/ 214 | 340/ 28 | +| Scheduler, Two Coroutines (man setup) | 2250/ 238 | 634/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 2024/ 214 | 408/ 28 | -| Scheduler, Two Coroutines (man setup) | 2318/ 238 | 702/ 52 | +| Scheduler, One Coroutine, Profiler | 1992/ 214 | 376/ 28 | +| Scheduler, Two Coroutines, Profiler | 2178/ 238 | 562/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 2100/ 286 | 484/ 100 | -| Scheduler, LogBinTableRenderer | 3502/ 304 | 1886/ 118 | -| Scheduler, LogBinJsonRenderer | 3022/ 308 | 1406/ 122 | +| Scheduler, LogBinProfiler | 2112/ 286 | 496/ 100 | +| Scheduler, LogBinTableRenderer | 3514/ 304 | 1898/ 118 | +| Scheduler, LogBinJsonRenderer | 3034/ 308 | 1418/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 1948/ 189 | 332/ 3 | | Blink Coroutine | 2118/ 212 | 502/ 26 | @@ -300,24 +312,30 @@ $ make README.md | One Coroutine (seconds) | 3870/ 177 | 288/ 26 | | Two Coroutines (seconds) | 4096/ 201 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 3958/ 179 | 376/ 28 | -| Scheduler, Two Coroutines (millis) | 4144/ 203 | 562/ 52 | +| One Coroutine, Profiler | 3840/ 177 | 258/ 26 | +| Two Coroutines, Profiler | 4098/ 201 | 516/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 3930/ 179 | 348/ 28 | -| Scheduler, Two Coroutines (micros) | 4088/ 203 | 506/ 52 | +| Scheduler, One Coroutine (millis) | 3894/ 179 | 312/ 28 | +| Scheduler, Two Coroutines (millis) | 4080/ 203 | 498/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 4058/ 179 | 476/ 28 | -| Scheduler, Two Coroutines (seconds) | 4276/ 203 | 694/ 52 | +| Scheduler, One Coroutine (micros) | 3866/ 179 | 284/ 28 | +| Scheduler, Two Coroutines (micros) | 4024/ 203 | 442/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 4012/ 179 | 430/ 28 | -| Scheduler, Two Coroutines (setup) | 4298/ 203 | 716/ 52 | +| Scheduler, One Coroutine (seconds) | 3994/ 179 | 412/ 28 | +| Scheduler, Two Coroutines (seconds) | 4212/ 203 | 630/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 3990/ 179 | 408/ 28 | -| Scheduler, Two Coroutines (man setup) | 4284/ 203 | 702/ 52 | +| Scheduler, One Coroutine (setup) | 3944/ 179 | 362/ 28 | +| Scheduler, Two Coroutines (setup) | 4230/ 203 | 648/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 4066/ 251 | 484/ 100 | -| Scheduler, LogBinTableRenderer | 5466/ 269 | 1884/ 118 | -| Scheduler, LogBinJsonRenderer | 4986/ 273 | 1404/ 122 | +| Scheduler, One Coroutine (man setup) | 3922/ 179 | 340/ 28 | +| Scheduler, Two Coroutines (man setup) | 4216/ 203 | 634/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine, Profiler | 3958/ 179 | 376/ 28 | +| Scheduler, Two Coroutines, Profiler | 4144/ 203 | 562/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 4078/ 251 | 496/ 100 | +| Scheduler, LogBinTableRenderer | 5478/ 269 | 1896/ 118 | +| Scheduler, LogBinJsonRenderer | 4998/ 273 | 1416/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 4022/ 154 | 440/ 3 | | Blink Coroutine | 4192/ 177 | 610/ 26 | @@ -349,24 +367,30 @@ $ make README.md | One Coroutine (seconds) | 22080/ 3572 | 148/ 32 | | Two Coroutines (seconds) | 22244/ 3600 | 312/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 22232/ 3576 | 300/ 36 | -| Scheduler, Two Coroutines (millis) | 22336/ 3604 | 404/ 64 | +| One Coroutine, Profiler | 22172/ 3572 | 240/ 32 | +| Two Coroutines, Profiler | 22328/ 3600 | 396/ 60 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (millis) | 22132/ 3576 | 200/ 36 | +| Scheduler, Two Coroutines (millis) | 22236/ 3604 | 304/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 22232/ 3576 | 300/ 36 | -| Scheduler, Two Coroutines (micros) | 22336/ 3604 | 404/ 64 | +| Scheduler, One Coroutine (micros) | 22196/ 3576 | 264/ 36 | +| Scheduler, Two Coroutines (micros) | 22300/ 3604 | 368/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 22248/ 3576 | 316/ 36 | -| Scheduler, Two Coroutines (seconds) | 22368/ 3604 | 436/ 64 | +| Scheduler, One Coroutine (seconds) | 22148/ 3576 | 216/ 36 | +| Scheduler, Two Coroutines (seconds) | 22268/ 3604 | 336/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 22252/ 3576 | 320/ 36 | -| Scheduler, Two Coroutines (setup) | 22384/ 3604 | 452/ 64 | +| Scheduler, One Coroutine (setup) | 22152/ 3576 | 220/ 36 | +| Scheduler, Two Coroutines (setup) | 22284/ 3604 | 352/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 22244/ 3576 | 312/ 36 | -| Scheduler, Two Coroutines (man setup) | 22376/ 3604 | 444/ 64 | +| Scheduler, One Coroutine (man setup) | 22144/ 3576 | 212/ 36 | +| Scheduler, Two Coroutines (man setup) | 22276/ 3604 | 344/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 22356/ 3644 | 424/ 104 | -| Scheduler, LogBinTableRenderer | 23740/ 3644 | 1808/ 104 | -| Scheduler, LogBinJsonRenderer | 23200/ 3644 | 1268/ 104 | +| Scheduler, One Coroutine, Profiler | 22232/ 3576 | 300/ 36 | +| Scheduler, Two Coroutines, Profiler | 22336/ 3604 | 404/ 64 | +|---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 22368/ 3644 | 436/ 104 | +| Scheduler, LogBinTableRenderer | 23752/ 3644 | 1820/ 104 | +| Scheduler, LogBinJsonRenderer | 23212/ 3644 | 1280/ 104 | |---------------------------------------+--------------+-------------| | Blink Function | 22168/ 3544 | 236/ 4 | | Blink Coroutine | 22280/ 3572 | 348/ 32 | @@ -398,24 +422,30 @@ $ make README.md | One Coroutine (seconds) | 265209/28028 | 228/ 44 | | Two Coroutines (seconds) | 265385/28060 | 404/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 265321/28036 | 340/ 52 | -| Scheduler, Two Coroutines (millis) | 265449/28060 | 468/ 76 | +| One Coroutine, Profiler | 265257/28028 | 276/ 44 | +| Two Coroutines, Profiler | 265433/28060 | 452/ 76 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (millis) | 265241/28036 | 260/ 52 | +| Scheduler, Two Coroutines (millis) | 265385/28060 | 404/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 265321/28036 | 340/ 52 | -| Scheduler, Two Coroutines (micros) | 265449/28060 | 468/ 76 | +| Scheduler, One Coroutine (micros) | 265257/28036 | 276/ 52 | +| Scheduler, Two Coroutines (micros) | 265401/28060 | 420/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 265337/28036 | 356/ 52 | -| Scheduler, Two Coroutines (seconds) | 265497/28060 | 516/ 76 | +| Scheduler, One Coroutine (seconds) | 265257/28036 | 276/ 52 | +| Scheduler, Two Coroutines (seconds) | 265417/28060 | 436/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 265337/28036 | 356/ 52 | -| Scheduler, Two Coroutines (setup) | 265513/28060 | 532/ 76 | +| Scheduler, One Coroutine (setup) | 265273/28036 | 292/ 52 | +| Scheduler, Two Coroutines (setup) | 265433/28060 | 452/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 265337/28036 | 356/ 52 | -| Scheduler, Two Coroutines (man setup) | 265513/28060 | 532/ 76 | +| Scheduler, One Coroutine (man setup) | 265257/28036 | 276/ 52 | +| Scheduler, Two Coroutines (man setup) | 265433/28060 | 452/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 265449/28100 | 468/ 116 | +| Scheduler, One Coroutine, Profiler | 265321/28036 | 340/ 52 | +| Scheduler, Two Coroutines, Profiler | 265449/28060 | 468/ 76 | +|---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 265465/28100 | 484/ 116 | | Scheduler, LogBinTableRenderer | 267381/28100 | 2400/ 116 | -| Scheduler, LogBinJsonRenderer | 266773/28104 | 1792/ 120 | +| Scheduler, LogBinJsonRenderer | 266789/28104 | 1808/ 120 | |---------------------------------------+--------------+-------------| | Blink Function | 265669/28064 | 688/ 80 | | Blink Coroutine | 265801/28100 | 820/ 116 | @@ -447,24 +477,30 @@ $ make README.md | One Coroutine (seconds) | 231081/16292 | 668/ 72 | | Two Coroutines (seconds) | 231269/16316 | 856/ 96 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 231181/16292 | 768/ 72 | -| Scheduler, Two Coroutines (millis) | 231321/16324 | 908/ 104 | +| One Coroutine, Profiler | 231117/16292 | 704/ 72 | +| Two Coroutines, Profiler | 231333/16316 | 920/ 96 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (millis) | 231129/16292 | 716/ 72 | +| Scheduler, Two Coroutines (millis) | 231269/16324 | 856/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 231181/16292 | 768/ 72 | -| Scheduler, Two Coroutines (micros) | 231321/16324 | 908/ 104 | +| Scheduler, One Coroutine (micros) | 231141/16292 | 728/ 72 | +| Scheduler, Two Coroutines (micros) | 231281/16324 | 868/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 231197/16292 | 784/ 72 | -| Scheduler, Two Coroutines (seconds) | 231353/16324 | 940/ 104 | +| Scheduler, One Coroutine (seconds) | 231145/16292 | 732/ 72 | +| Scheduler, Two Coroutines (seconds) | 231301/16324 | 888/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 231209/16292 | 796/ 72 | -| Scheduler, Two Coroutines (setup) | 231381/16324 | 968/ 104 | +| Scheduler, One Coroutine (setup) | 231157/16292 | 744/ 72 | +| Scheduler, Two Coroutines (setup) | 231329/16324 | 916/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 231197/16292 | 784/ 72 | -| Scheduler, Two Coroutines (man setup) | 231373/16324 | 960/ 104 | +| Scheduler, One Coroutine (man setup) | 231145/16292 | 732/ 72 | +| Scheduler, Two Coroutines (man setup) | 231321/16324 | 908/ 104 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 231313/16364 | 900/ 144 | -| Scheduler, LogBinTableRenderer | 232645/16364 | 2232/ 144 | -| Scheduler, LogBinJsonRenderer | 232093/16364 | 1680/ 144 | +| Scheduler, One Coroutine, Profiler | 231181/16292 | 768/ 72 | +| Scheduler, Two Coroutines, Profiler | 231321/16324 | 908/ 104 | +|---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 231321/16364 | 908/ 144 | +| Scheduler, LogBinTableRenderer | 232653/16364 | 2240/ 144 | +| Scheduler, LogBinJsonRenderer | 232101/16364 | 1688/ 144 | |---------------------------------------+--------------+-------------| | Blink Function | 231301/16268 | 888/ 48 | | Blink Coroutine | 231413/16300 | 1000/ 80 | @@ -497,24 +533,30 @@ $ make README.md | One Coroutine (seconds) | 10824/ 4188 | 176/ 32 | | Two Coroutines (seconds) | 10964/ 4216 | 316/ 60 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 10976/ 4192 | 328/ 36 | -| Scheduler, Two Coroutines (millis) | 11092/ 4220 | 444/ 64 | +| One Coroutine, Profiler | 10904/ 4188 | 256/ 32 | +| Two Coroutines, Profiler | 11072/ 4216 | 424/ 60 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (millis) | 10868/ 4192 | 220/ 36 | +| Scheduler, Two Coroutines (millis) | 10984/ 4220 | 336/ 64 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (micros) | 10924/ 4192 | 276/ 36 | +| Scheduler, Two Coroutines (micros) | 11028/ 4220 | 380/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 10964/ 4192 | 316/ 36 | -| Scheduler, Two Coroutines (micros) | 11068/ 4220 | 420/ 64 | +| Scheduler, One Coroutine (seconds) | 10888/ 4192 | 240/ 36 | +| Scheduler, Two Coroutines (seconds) | 11024/ 4220 | 376/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 10996/ 4192 | 348/ 36 | -| Scheduler, Two Coroutines (seconds) | 11132/ 4220 | 484/ 64 | +| Scheduler, One Coroutine (setup) | 10904/ 4192 | 256/ 36 | +| Scheduler, Two Coroutines (setup) | 11052/ 4220 | 404/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 11012/ 4192 | 364/ 36 | -| Scheduler, Two Coroutines (setup) | 11160/ 4220 | 512/ 64 | +| Scheduler, One Coroutine (man setup) | 10880/ 4192 | 232/ 36 | +| Scheduler, Two Coroutines (man setup) | 11032/ 4220 | 384/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 10988/ 4192 | 340/ 36 | -| Scheduler, Two Coroutines (man setup) | 11140/ 4220 | 492/ 64 | +| Scheduler, One Coroutine, Profiler | 10976/ 4192 | 328/ 36 | +| Scheduler, Two Coroutines, Profiler | 11092/ 4220 | 444/ 64 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 11380/ 4268 | 732/ 112 | +| Scheduler, LogBinProfiler | 11396/ 4268 | 748/ 112 | | Scheduler, LogBinTableRenderer | 14120/ 4284 | 3472/ 128 | -| Scheduler, LogBinJsonRenderer | 13412/ 4284 | 2764/ 128 | +| Scheduler, LogBinJsonRenderer | 13476/ 4284 | 2828/ 128 | |---------------------------------------+--------------+-------------| | Blink Function | 11104/ 4164 | 456/ 8 | | Blink Coroutine | 11236/ 4188 | 588/ 32 | diff --git a/examples/MemoryBenchmark/attiny.txt b/examples/MemoryBenchmark/attiny.txt index a51bca5..363ddc9 100644 --- a/examples/MemoryBenchmark/attiny.txt +++ b/examples/MemoryBenchmark/attiny.txt @@ -7,18 +7,22 @@ 6 1336 8192 131 512 7 1302 8192 107 512 8 1524 8192 131 512 -9 1396 8192 109 512 -10 1582 8192 133 512 -11 1364 8192 109 512 -12 1518 8192 133 512 -13 1492 8192 109 512 -14 1706 8192 133 512 -15 1446 8192 109 512 -16 1728 8192 133 512 -17 1424 8192 109 512 -18 1714 8192 133 512 -19 1500 8192 181 512 -20 2864 8192 193 512 -21 2398 8192 197 512 -22 1176 8192 84 512 -23 1330 8192 107 512 +9 1276 8192 107 512 +10 1528 8192 131 512 +11 1336 8192 109 512 +12 1522 8192 133 512 +13 1304 8192 109 512 +14 1458 8192 133 512 +15 1432 8192 109 512 +16 1646 8192 133 512 +17 1388 8192 109 512 +18 1670 8192 133 512 +19 1364 8192 109 512 +20 1654 8192 133 512 +21 1396 8192 109 512 +22 1582 8192 133 512 +23 1512 8192 181 512 +24 2876 8192 193 512 +25 2410 8192 197 512 +26 1176 8192 84 512 +27 1330 8192 107 512 diff --git a/examples/MemoryBenchmark/collect.sh b/examples/MemoryBenchmark/collect.sh index 9e84de6..8786b1f 100755 --- a/examples/MemoryBenchmark/collect.sh +++ b/examples/MemoryBenchmark/collect.sh @@ -16,7 +16,7 @@ set -eu PROGRAM_NAME='MemoryBenchmark.ino' -NUM_FEATURES=23 # excluding FEATURE_BASELINE +NUM_FEATURES=27 # excluding FEATURE_BASELINE # Assume that https://github.com/bxparks/AUniter is installed as a # sibling project to AceRoutine. diff --git a/examples/MemoryBenchmark/esp32.txt b/examples/MemoryBenchmark/esp32.txt index 70415fa..87d83f4 100644 --- a/examples/MemoryBenchmark/esp32.txt +++ b/examples/MemoryBenchmark/esp32.txt @@ -7,18 +7,22 @@ 6 231249 1310720 16316 327680 7 231081 1310720 16292 327680 8 231269 1310720 16316 327680 -9 231181 1310720 16292 327680 -10 231321 1310720 16324 327680 -11 231181 1310720 16292 327680 -12 231321 1310720 16324 327680 -13 231197 1310720 16292 327680 -14 231353 1310720 16324 327680 -15 231209 1310720 16292 327680 -16 231381 1310720 16324 327680 -17 231197 1310720 16292 327680 -18 231373 1310720 16324 327680 -19 231313 1310720 16364 327680 -20 232645 1310720 16364 327680 -21 232093 1310720 16364 327680 -22 231301 1310720 16268 327680 -23 231413 1310720 16300 327680 +9 231117 1310720 16292 327680 +10 231333 1310720 16316 327680 +11 231129 1310720 16292 327680 +12 231269 1310720 16324 327680 +13 231141 1310720 16292 327680 +14 231281 1310720 16324 327680 +15 231145 1310720 16292 327680 +16 231301 1310720 16324 327680 +17 231157 1310720 16292 327680 +18 231329 1310720 16324 327680 +19 231145 1310720 16292 327680 +20 231321 1310720 16324 327680 +21 231181 1310720 16292 327680 +22 231321 1310720 16324 327680 +23 231321 1310720 16364 327680 +24 232653 1310720 16364 327680 +25 232101 1310720 16364 327680 +26 231301 1310720 16268 327680 +27 231413 1310720 16300 327680 diff --git a/examples/MemoryBenchmark/esp8266.txt b/examples/MemoryBenchmark/esp8266.txt index 8b241fe..6bae3ef 100644 --- a/examples/MemoryBenchmark/esp8266.txt +++ b/examples/MemoryBenchmark/esp8266.txt @@ -7,18 +7,22 @@ 6 265369 1044464 28060 81920 7 265209 1044464 28028 81920 8 265385 1044464 28060 81920 -9 265321 1044464 28036 81920 -10 265449 1044464 28060 81920 -11 265321 1044464 28036 81920 -12 265449 1044464 28060 81920 -13 265337 1044464 28036 81920 -14 265497 1044464 28060 81920 -15 265337 1044464 28036 81920 -16 265513 1044464 28060 81920 -17 265337 1044464 28036 81920 -18 265513 1044464 28060 81920 -19 265449 1044464 28100 81920 -20 267381 1044464 28100 81920 -21 266773 1044464 28104 81920 -22 265669 1044464 28064 81920 -23 265801 1044464 28100 81920 +9 265257 1044464 28028 81920 +10 265433 1044464 28060 81920 +11 265241 1044464 28036 81920 +12 265385 1044464 28060 81920 +13 265257 1044464 28036 81920 +14 265401 1044464 28060 81920 +15 265257 1044464 28036 81920 +16 265417 1044464 28060 81920 +17 265273 1044464 28036 81920 +18 265433 1044464 28060 81920 +19 265257 1044464 28036 81920 +20 265433 1044464 28060 81920 +21 265321 1044464 28036 81920 +22 265449 1044464 28060 81920 +23 265465 1044464 28100 81920 +24 267381 1044464 28100 81920 +25 266789 1044464 28104 81920 +26 265669 1044464 28064 81920 +27 265801 1044464 28100 81920 diff --git a/examples/MemoryBenchmark/generate_table.awk b/examples/MemoryBenchmark/generate_table.awk index 50c4037..f175cb4 100755 --- a/examples/MemoryBenchmark/generate_table.awk +++ b/examples/MemoryBenchmark/generate_table.awk @@ -15,21 +15,25 @@ BEGIN { labels[6] = "Two Coroutines (micros)" labels[7] = "One Coroutine (seconds)" labels[8] = "Two Coroutines (seconds)" - labels[9] = "Scheduler, One Coroutine (millis)" - labels[10] = "Scheduler, Two Coroutines (millis)" - labels[11] = "Scheduler, One Coroutine (micros)" - labels[12] = "Scheduler, Two Coroutines (micros)" - labels[13] = "Scheduler, One Coroutine (seconds)" - labels[14] = "Scheduler, Two Coroutines (seconds)" - labels[15] = "Scheduler, One Coroutine (setup)" - labels[16] = "Scheduler, Two Coroutines (setup)" - labels[17] = "Scheduler, One Coroutine (man setup)" - labels[18] = "Scheduler, Two Coroutines (man setup)" - labels[19] = "Scheduler, LogBinProfiler" - labels[20] = "Scheduler, LogBinTableRenderer" - labels[21] = "Scheduler, LogBinJsonRenderer" - labels[22] = "Blink Function" - labels[23] = "Blink Coroutine" + labels[9] = "One Coroutine, Profiler" + labels[10] = "Two Coroutines, Profiler" + labels[11] = "Scheduler, One Coroutine (millis)" + labels[12] = "Scheduler, Two Coroutines (millis)" + labels[13] = "Scheduler, One Coroutine (micros)" + labels[14] = "Scheduler, Two Coroutines (micros)" + labels[15] = "Scheduler, One Coroutine (seconds)" + labels[16] = "Scheduler, Two Coroutines (seconds)" + labels[17] = "Scheduler, One Coroutine (setup)" + labels[18] = "Scheduler, Two Coroutines (setup)" + labels[19] = "Scheduler, One Coroutine (man setup)" + labels[20] = "Scheduler, Two Coroutines (man setup)" + labels[21] = "Scheduler, One Coroutine, Profiler" + labels[22] = "Scheduler, Two Coroutines, Profiler" + labels[23] = "Scheduler, LogBinProfiler" + labels[24] = "Scheduler, LogBinTableRenderer" + labels[25] = "Scheduler, LogBinJsonRenderer" + labels[26] = "Blink Function" + labels[27] = "Blink Coroutine" record_index = 0 } { @@ -55,11 +59,13 @@ END { || labels[i] ~ /^One Coroutine \(millis\)$/ \ || labels[i] ~ /^One Coroutine \(micros\)$/ \ || labels[i] ~ /^One Coroutine \(seconds\)$/ \ + || labels[i] ~ /^One Coroutine, Profiler$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(millis\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(micros\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(seconds\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(setup\)$/ \ || labels[i] ~ /^Scheduler, One Coroutine \(man setup\)$/ \ + || labels[i] ~ /^Scheduler, One Coroutine, Profiler$/ \ || labels[i] ~ /^Scheduler, LogBinProfiler$/ \ || labels[i] ~ /^Blink Function$/ \ ) { diff --git a/examples/MemoryBenchmark/micro.txt b/examples/MemoryBenchmark/micro.txt index 0cec484..536bc36 100644 --- a/examples/MemoryBenchmark/micro.txt +++ b/examples/MemoryBenchmark/micro.txt @@ -7,18 +7,22 @@ 6 3908 28672 201 2560 7 3870 28672 177 2560 8 4096 28672 201 2560 -9 3958 28672 179 2560 -10 4144 28672 203 2560 -11 3930 28672 179 2560 -12 4088 28672 203 2560 -13 4058 28672 179 2560 -14 4276 28672 203 2560 -15 4012 28672 179 2560 -16 4298 28672 203 2560 -17 3990 28672 179 2560 -18 4284 28672 203 2560 -19 4066 28672 251 2560 -20 5466 28672 269 2560 -21 4986 28672 273 2560 -22 4022 28672 154 2560 -23 4192 28672 177 2560 +9 3840 28672 177 2560 +10 4098 28672 201 2560 +11 3894 28672 179 2560 +12 4080 28672 203 2560 +13 3866 28672 179 2560 +14 4024 28672 203 2560 +15 3994 28672 179 2560 +16 4212 28672 203 2560 +17 3944 28672 179 2560 +18 4230 28672 203 2560 +19 3922 28672 179 2560 +20 4216 28672 203 2560 +21 3958 28672 179 2560 +22 4144 28672 203 2560 +23 4078 28672 251 2560 +24 5478 28672 269 2560 +25 4998 28672 273 2560 +26 4022 28672 154 2560 +27 4192 28672 177 2560 diff --git a/examples/MemoryBenchmark/nano.txt b/examples/MemoryBenchmark/nano.txt index 8bf4fc5..255fc99 100644 --- a/examples/MemoryBenchmark/nano.txt +++ b/examples/MemoryBenchmark/nano.txt @@ -7,18 +7,22 @@ 6 1942 30720 236 2048 7 1904 30720 212 2048 8 2130 30720 236 2048 -9 1992 30720 214 2048 -10 2178 30720 238 2048 -11 1964 30720 214 2048 -12 2122 30720 238 2048 -13 2092 30720 214 2048 -14 2310 30720 238 2048 -15 2046 30720 214 2048 -16 2332 30720 238 2048 -17 2024 30720 214 2048 -18 2318 30720 238 2048 -19 2100 30720 286 2048 -20 3502 30720 304 2048 -21 3022 30720 308 2048 -22 1948 30720 189 2048 -23 2118 30720 212 2048 +9 1874 30720 212 2048 +10 2132 30720 236 2048 +11 1928 30720 214 2048 +12 2114 30720 238 2048 +13 1900 30720 214 2048 +14 2058 30720 238 2048 +15 2028 30720 214 2048 +16 2246 30720 238 2048 +17 1978 30720 214 2048 +18 2264 30720 238 2048 +19 1956 30720 214 2048 +20 2250 30720 238 2048 +21 1992 30720 214 2048 +22 2178 30720 238 2048 +23 2112 30720 286 2048 +24 3514 30720 304 2048 +25 3034 30720 308 2048 +26 1948 30720 189 2048 +27 2118 30720 212 2048 diff --git a/examples/MemoryBenchmark/stm32.txt b/examples/MemoryBenchmark/stm32.txt index 5822dd1..b4ada5d 100644 --- a/examples/MemoryBenchmark/stm32.txt +++ b/examples/MemoryBenchmark/stm32.txt @@ -7,18 +7,22 @@ 6 22276 131072 3600 20480 7 22080 131072 3572 20480 8 22244 131072 3600 20480 -9 22232 131072 3576 20480 -10 22336 131072 3604 20480 -11 22232 131072 3576 20480 -12 22336 131072 3604 20480 -13 22248 131072 3576 20480 -14 22368 131072 3604 20480 -15 22252 131072 3576 20480 -16 22384 131072 3604 20480 -17 22244 131072 3576 20480 -18 22376 131072 3604 20480 -19 22356 131072 3644 20480 -20 23740 131072 3644 20480 -21 23200 131072 3644 20480 -22 22168 131072 3544 20480 -23 22280 131072 3572 20480 +9 22172 131072 3572 20480 +10 22328 131072 3600 20480 +11 22132 131072 3576 20480 +12 22236 131072 3604 20480 +13 22196 131072 3576 20480 +14 22300 131072 3604 20480 +15 22148 131072 3576 20480 +16 22268 131072 3604 20480 +17 22152 131072 3576 20480 +18 22284 131072 3604 20480 +19 22144 131072 3576 20480 +20 22276 131072 3604 20480 +21 22232 131072 3576 20480 +22 22336 131072 3604 20480 +23 22368 131072 3644 20480 +24 23752 131072 3644 20480 +25 23212 131072 3644 20480 +26 22168 131072 3544 20480 +27 22280 131072 3572 20480 diff --git a/examples/MemoryBenchmark/teensy32.txt b/examples/MemoryBenchmark/teensy32.txt index cf905b3..92024c4 100644 --- a/examples/MemoryBenchmark/teensy32.txt +++ b/examples/MemoryBenchmark/teensy32.txt @@ -7,18 +7,22 @@ 6 10968 262144 4216 65536 7 10824 262144 4188 65536 8 10964 262144 4216 65536 -9 10976 262144 4192 65536 -10 11092 262144 4220 65536 -11 10964 262144 4192 65536 -12 11068 262144 4220 65536 -13 10996 262144 4192 65536 -14 11132 262144 4220 65536 -15 11012 262144 4192 65536 -16 11160 262144 4220 65536 -17 10988 262144 4192 65536 -18 11140 262144 4220 65536 -19 11380 262144 4268 65536 -20 14120 262144 4284 65536 -21 13412 262144 4284 65536 -22 11104 262144 4164 65536 -23 11236 262144 4188 65536 +9 10904 262144 4188 65536 +10 11072 262144 4216 65536 +11 10868 262144 4192 65536 +12 10984 262144 4220 65536 +13 10924 262144 4192 65536 +14 11028 262144 4220 65536 +15 10888 262144 4192 65536 +16 11024 262144 4220 65536 +17 10904 262144 4192 65536 +18 11052 262144 4220 65536 +19 10880 262144 4192 65536 +20 11032 262144 4220 65536 +21 10976 262144 4192 65536 +22 11092 262144 4220 65536 +23 11396 262144 4268 65536 +24 14120 262144 4284 65536 +25 13476 262144 4284 65536 +26 11104 262144 4164 65536 +27 11236 262144 4188 65536 diff --git a/examples/MemoryBenchmark/validate_using_epoxy_duino.sh b/examples/MemoryBenchmark/validate_using_epoxy_duino.sh index 1841ffd..91be6e0 100755 --- a/examples/MemoryBenchmark/validate_using_epoxy_duino.sh +++ b/examples/MemoryBenchmark/validate_using_epoxy_duino.sh @@ -8,7 +8,7 @@ set -eu PROGRAM_NAME='MemoryBenchmark.ino' -NUM_FEATURES=23 # excluding FEATURE_BASELINE +NUM_FEATURES=27 # excluding FEATURE_BASELINE temp_out_file= function cleanup() { From 7c15d8b455c133937c47c9011456cb92ec6f27b4 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 18 Mar 2022 12:38:30 -0700 Subject: [PATCH 51/59] AutoBenchmark: Add benchmarks for runCoroutineWithProfiler() and loopWithProfiler() --- examples/AutoBenchmark/AutoBenchmark.ino | 91 ++++++++++++---- examples/AutoBenchmark/README.md | 126 ++++++++++++++-------- examples/AutoBenchmark/esp32.txt | 9 +- examples/AutoBenchmark/esp8266.txt | 7 +- examples/AutoBenchmark/generate_table.awk | 17 +-- examples/AutoBenchmark/micro.txt | 9 +- examples/AutoBenchmark/nano.txt | 11 +- examples/AutoBenchmark/stm32.txt | 12 +-- examples/AutoBenchmark/teensy32.txt | 7 +- 9 files changed, 199 insertions(+), 90 deletions(-) diff --git a/examples/AutoBenchmark/AutoBenchmark.ino b/examples/AutoBenchmark/AutoBenchmark.ino index 2feddc6..8573e20 100644 --- a/examples/AutoBenchmark/AutoBenchmark.ino +++ b/examples/AutoBenchmark/AutoBenchmark.ino @@ -8,9 +8,11 @@ #include #include -#include // printPad3To() +#include // printUint32AsFloat3To() using namespace ace_routine; -using ace_common::printPad3To; +using ace_common::printUint32AsFloat3To; + +//----------------------------------------------------------------------------- // NUM_ITERATIONS must be in multiples of 1000, due to the algorithm used to // convert to nanos below. @@ -57,69 +59,96 @@ void checkEqual( } } -uint16_t doEmptyLoop(uint32_t iterations) { +//----------------------------------------------------------------------------- + +uint32_t doEmptyLoop(uint32_t iterations) { yield(); counter = 0; - uint16_t start = millis(); + uint32_t start = millis(); for (uint32_t i = 0; i < iterations; i++) { counter++; } - uint16_t end = millis(); + uint32_t end = millis(); yield(); checkEqual(F("doEmptyLoop(): "), counter, iterations); return end - start; } -uint16_t doDirectScheduling(uint32_t iterations) { +uint32_t doDirectScheduling(uint32_t iterations) { yield(); counter = 0; - uint16_t start = millis(); + uint32_t start = millis(); // Run for 1/2 as many iterations because each loop calls 2 coroutines. for (uint32_t i = 0; i < iterations / 2; i++) { counterA.runCoroutine(); counterB.runCoroutine(); } - uint16_t end = millis(); + uint32_t end = millis(); yield(); checkEqual(F("doDirectScheduling(): "), counter, iterations); return end - start; } -uint16_t doCoroutineScheduling(uint32_t iterations) { +uint32_t doDirectSchedulingWithProfiler(uint32_t iterations) { + yield(); + counter = 0; + uint32_t start = millis(); + + // Run for 1/2 as many iterations because each loop calls 2 coroutines. + for (uint32_t i = 0; i < iterations / 2; i++) { + counterA.runCoroutineWithProfiler(); + counterB.runCoroutineWithProfiler(); + } + uint32_t end = millis(); + yield(); + checkEqual(F("doDirectSchedulingWithProfiler(): "), counter, iterations); + return end - start; +} + +uint32_t doCoroutineScheduling(uint32_t iterations) { yield(); counter = 0; - uint16_t start = millis(); + uint32_t start = millis(); for (uint32_t i = 0; i < iterations; i++) { CoroutineScheduler::loop(); } - uint16_t end = millis(); + uint32_t end = millis(); yield(); checkEqual(F("doCoroutineScheduling()"), counter, iterations); return end - start; } -void printNanosAsMicros(Print& printer, uint16_t nanos) { - uint16_t wholeMicros = nanos / 1000; - uint16_t fracMicros = nanos - wholeMicros * 1000; - printer.print(wholeMicros); - printer.print('.'); - printPad3To(printer, fracMicros, '0'); +uint32_t doCoroutineSchedulingWithProfiler(uint32_t iterations) { + yield(); + counter = 0; + uint32_t start = millis(); + for (uint32_t i = 0; i < iterations; i++) { + CoroutineScheduler::loopWithProfiler(); + } + uint32_t end = millis(); + yield(); + checkEqual(F("doCoroutineSchedulingWithProfiler()"), counter, iterations); + return end - start; } +//----------------------------------------------------------------------------- + // Print millis 'ms' as micros (to 3 decimal places) per iteration as a floating // point number. The number of 'iterations' must be divisible by 1000. void printStats( - const __FlashStringHelper* name, uint16_t ms, uint32_t iterations) { - uint16_t nanosPerIteration = (uint32_t) ms * 1000 / (iterations / 1000); + const __FlashStringHelper* name, uint32_t ms, uint32_t iterations) { + uint32_t nanosPerIteration = ms * 1000 / (iterations / 1000); SERIAL_PORT_MONITOR.print(name); SERIAL_PORT_MONITOR.print(' '); - printNanosAsMicros(SERIAL_PORT_MONITOR, nanosPerIteration); + printUint32AsFloat3To(SERIAL_PORT_MONITOR, nanosPerIteration); SERIAL_PORT_MONITOR.print(' '); SERIAL_PORT_MONITOR.print(iterations); SERIAL_PORT_MONITOR.println(); } +//----------------------------------------------------------------------------- + void setup() { #if ! defined(EPOXY_DUINO) delay(1000); @@ -136,21 +165,37 @@ void setup() { SERIAL_PORT_MONITOR.println(sizeof(CoroutineScheduler)); SERIAL_PORT_MONITOR.print(F("sizeof(Channel): ")); SERIAL_PORT_MONITOR.println(sizeof(Channel)); + SERIAL_PORT_MONITOR.print(F("sizeof(LogBinProfiler): ")); + SERIAL_PORT_MONITOR.println(sizeof(LogBinProfiler)); + SERIAL_PORT_MONITOR.print(F("sizeof(LogBinTableRenderer): ")); + SERIAL_PORT_MONITOR.println(sizeof(LogBinTableRenderer)); + SERIAL_PORT_MONITOR.print(F("sizeof(LogBinJsonRenderer): ")); + SERIAL_PORT_MONITOR.println(sizeof(LogBinJsonRenderer)); CoroutineScheduler::setup(); //CoroutineScheduler::list(SERIAL_PORT_MONITOR); SERIAL_PORT_MONITOR.println(F("BENCHMARKS")); - uint16_t emptyLoopMillis = doEmptyLoop(NUM_ITERATIONS); + uint32_t emptyLoopMillis = doEmptyLoop(NUM_ITERATIONS); printStats(F("EmptyLoop"), emptyLoopMillis, NUM_ITERATIONS); - uint16_t directMillis = doDirectScheduling(NUM_ITERATIONS); + uint32_t directMillis = doDirectScheduling(NUM_ITERATIONS); printStats(F("DirectScheduling"), directMillis, NUM_ITERATIONS); - uint16_t schedulerMillis = doCoroutineScheduling(NUM_ITERATIONS); + uint32_t directMillisWithProfiler = + doDirectSchedulingWithProfiler(NUM_ITERATIONS); + printStats(F("DirectSchedulingWithProfiler"), + directMillisWithProfiler, NUM_ITERATIONS); + + uint32_t schedulerMillis = doCoroutineScheduling(NUM_ITERATIONS); printStats(F("CoroutineScheduling"), schedulerMillis, NUM_ITERATIONS); + uint32_t schedulerMillisWithProfiler = + doCoroutineSchedulingWithProfiler(NUM_ITERATIONS); + printStats(F("CoroutineSchedulingWithProfiler"), + schedulerMillisWithProfiler, NUM_ITERATIONS); + SERIAL_PORT_MONITOR.println(F("END")); #if defined(EPOXY_DUINO) diff --git a/examples/AutoBenchmark/README.md b/examples/AutoBenchmark/README.md index 01b8a00..c78a3f8 100644 --- a/examples/AutoBenchmark/README.md +++ b/examples/AutoBenchmark/README.md @@ -142,15 +142,22 @@ Sizes of Objects: sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 +sizeof(LogBinProfiler): 66 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 CPU: -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 1.700 | 0.000 | -| DirectScheduling | 10000 | 2.900 | 1.200 | -| CoroutineScheduling | 10000 | 7.200 | 5.500 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 10000 | 1.900 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 10000 | 2.800 | 0.900 | +| DirectSchedulingWithProfiler | 10000 | 5.800 | 3.900 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 10000 | 7.000 | 5.100 | +| CoroutineSchedulingWithProfiler | 10000 | 9.300 | 7.400 | ++---------------------------------+--------+-------------+--------+ ``` @@ -166,15 +173,22 @@ Sizes of Objects: sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 +sizeof(LogBinProfiler): 66 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 CPU: -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 1.800 | 0.000 | -| DirectScheduling | 10000 | 2.800 | 1.000 | -| CoroutineScheduling | 10000 | 7.200 | 5.400 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 10000 | 1.700 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 10000 | 2.800 | 1.100 | +| DirectSchedulingWithProfiler | 10000 | 5.800 | 4.100 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 10000 | 7.100 | 5.400 | +| CoroutineSchedulingWithProfiler | 10000 | 9.400 | 7.700 | ++---------------------------------+--------+-------------+--------+ ``` @@ -186,18 +200,19 @@ CPU: ``` Sizes of Objects: -sizeof(Coroutine): 28 -sizeof(CoroutineScheduler): 4 -sizeof(Channel): 12 CPU: -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 30000 | 0.133 | 0.000 | -| DirectScheduling | 30000 | 0.533 | 0.400 | -| CoroutineScheduling | 30000 | 1.266 | 1.133 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 30000 | 0.166 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 30000 | 0.533 | 0.367 | +| DirectSchedulingWithProfiler | 30000 | 0.933 | 0.767 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 30000 | 1.066 | 0.900 | +| CoroutineSchedulingWithProfiler | 30000 | 1.466 | 1.300 | ++---------------------------------+--------+-------------+--------+ ``` @@ -212,15 +227,22 @@ Sizes of Objects: sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 CPU: -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 0.100 | 0.000 | -| DirectScheduling | 10000 | 0.500 | 0.400 | -| CoroutineScheduling | 10000 | 1.000 | 0.900 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 10000 | 0.100 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 10000 | 0.500 | 0.400 | +| DirectSchedulingWithProfiler | 10000 | 0.800 | 0.700 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 10000 | 0.900 | 0.800 | +| CoroutineSchedulingWithProfiler | 10000 | 1.100 | 1.000 | ++---------------------------------+--------+-------------+--------+ ``` @@ -235,15 +257,22 @@ Sizes of Objects: sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 CPU: -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 30000 | 0.066 | 0.000 | -| DirectScheduling | 30000 | 0.133 | 0.067 | -| CoroutineScheduling | 30000 | 0.366 | 0.300 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 30000 | 0.033 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 30000 | 0.133 | 0.100 | +| DirectSchedulingWithProfiler | 30000 | 0.233 | 0.200 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 30000 | 0.333 | 0.300 | +| CoroutineSchedulingWithProfiler | 30000 | 0.433 | 0.400 | ++---------------------------------+--------+-------------+--------+ ``` @@ -259,15 +288,22 @@ Sizes of Objects: sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 CPU: -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 30000 | 0.066 | 0.000 | -| DirectScheduling | 30000 | 0.233 | 0.167 | -| CoroutineScheduling | 30000 | 0.666 | 0.600 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 30000 | 0.066 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 30000 | 0.233 | 0.167 | +| DirectSchedulingWithProfiler | 30000 | 0.266 | 0.200 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 30000 | 0.500 | 0.434 | +| CoroutineSchedulingWithProfiler | 30000 | 0.666 | 0.600 | ++---------------------------------+--------+-------------+--------+ ``` diff --git a/examples/AutoBenchmark/esp32.txt b/examples/AutoBenchmark/esp32.txt index 08a0c39..8962292 100644 --- a/examples/AutoBenchmark/esp32.txt +++ b/examples/AutoBenchmark/esp32.txt @@ -2,8 +2,13 @@ SIZEOF sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 BENCHMARKS -EmptyLoop 0.066 30000 +EmptyLoop 0.033 30000 DirectScheduling 0.133 30000 -CoroutineScheduling 0.366 30000 +DirectSchedulingWithProfiler 0.233 30000 +CoroutineScheduling 0.333 30000 +CoroutineSchedulingWithProfiler 0.433 30000 END diff --git a/examples/AutoBenchmark/esp8266.txt b/examples/AutoBenchmark/esp8266.txt index c256052..b095164 100644 --- a/examples/AutoBenchmark/esp8266.txt +++ b/examples/AutoBenchmark/esp8266.txt @@ -2,8 +2,13 @@ SIZEOF sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 BENCHMARKS EmptyLoop 0.100 10000 DirectScheduling 0.500 10000 -CoroutineScheduling 1.000 10000 +DirectSchedulingWithProfiler 0.800 10000 +CoroutineScheduling 0.900 10000 +CoroutineSchedulingWithProfiler 1.100 10000 END diff --git a/examples/AutoBenchmark/generate_table.awk b/examples/AutoBenchmark/generate_table.awk index 09ae2bf..5ff3128 100755 --- a/examples/AutoBenchmark/generate_table.awk +++ b/examples/AutoBenchmark/generate_table.awk @@ -59,16 +59,19 @@ END { print "" print "CPU:" - printf("+---------------------+--------+-------------+--------+\n") - printf("| Functionality | iters | micros/iter | diff |\n") + printf("+---------------------------------+--------+-------------+--------+\n") + printf("| Functionality | iters | micros/iter | diff |\n") for (i = 0; i < TOTAL_BENCHMARKS; i++) { name = u[i]["name"] - if (name ~ /^EmptyLoop$/ || name ~ /^DirectScheduler$/){ - printf("|---------------------+--------+-------------+--------|\n") + if (name ~ /^EmptyLoop$/ \ + || name ~ /^DirectScheduling$/ \ + || name ~ /^CoroutineScheduling$/ \ + ) { + printf("|---------------------------------+--------+-------------+--------|\n") } - printf("| %-19s | %6d | %11.3f | %6.3f |\n", - u[i]["name"], u[i]["iterations"], u[i]["micros"], u[i]["diff"]) + printf("| %-31s | %6d | %11.3f | %6.3f |\n", + name, u[i]["iterations"], u[i]["micros"], u[i]["diff"]) } - printf("+---------------------+--------+-------------+--------+\n") + printf("+---------------------------------+--------+-------------+--------+\n") } diff --git a/examples/AutoBenchmark/micro.txt b/examples/AutoBenchmark/micro.txt index 55c853a..6584918 100644 --- a/examples/AutoBenchmark/micro.txt +++ b/examples/AutoBenchmark/micro.txt @@ -2,8 +2,13 @@ SIZEOF sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 +sizeof(LogBinProfiler): 66 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 BENCHMARKS -EmptyLoop 1.800 10000 +EmptyLoop 1.700 10000 DirectScheduling 2.800 10000 -CoroutineScheduling 7.200 10000 +DirectSchedulingWithProfiler 5.800 10000 +CoroutineScheduling 7.100 10000 +CoroutineSchedulingWithProfiler 9.400 10000 END diff --git a/examples/AutoBenchmark/nano.txt b/examples/AutoBenchmark/nano.txt index bd6e659..e545e53 100644 --- a/examples/AutoBenchmark/nano.txt +++ b/examples/AutoBenchmark/nano.txt @@ -2,8 +2,13 @@ SIZEOF sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 +sizeof(LogBinProfiler): 66 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 BENCHMARKS -EmptyLoop 1.700 10000 -DirectScheduling 2.900 10000 -CoroutineScheduling 7.200 10000 +EmptyLoop 1.900 10000 +DirectScheduling 2.800 10000 +DirectSchedulingWithProfiler 5.800 10000 +CoroutineScheduling 7.000 10000 +CoroutineSchedulingWithProfiler 9.300 10000 END diff --git a/examples/AutoBenchmark/stm32.txt b/examples/AutoBenchmark/stm32.txt index dcfb5c7..a50013e 100644 --- a/examples/AutoBenchmark/stm32.txt +++ b/examples/AutoBenchmark/stm32.txt @@ -1,9 +1,9 @@ -SIZEOF -sizeof(Coroutine): 28 -sizeof(CoroutineScheduler): 4 -sizeof(Channel): 12 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 BENCHMARKS -EmptyLoop 0.133 30000 +EmptyLoop 0.166 30000 DirectScheduling 0.533 30000 -CoroutineScheduling 1.266 30000 +DirectSchedulingWithProfiler 0.933 30000 +CoroutineScheduling 1.066 30000 +CoroutineSchedulingWithProfiler 1.466 30000 END diff --git a/examples/AutoBenchmark/teensy32.txt b/examples/AutoBenchmark/teensy32.txt index 358df17..2d497b6 100644 --- a/examples/AutoBenchmark/teensy32.txt +++ b/examples/AutoBenchmark/teensy32.txt @@ -2,8 +2,13 @@ SIZEOF sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 BENCHMARKS EmptyLoop 0.066 30000 DirectScheduling 0.233 30000 -CoroutineScheduling 0.666 30000 +DirectSchedulingWithProfiler 0.266 30000 +CoroutineScheduling 0.500 30000 +CoroutineSchedulingWithProfiler 0.666 30000 END From 46d7b60db188f5cb9c2983e8402de4e31b2c9d85 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Fri, 18 Mar 2022 12:55:11 -0700 Subject: [PATCH 52/59] USER_GUIDE.md: Update new CPU latency numbers; update HelloCoroutineWithProfiler and HelloSchedulerWithProfiler --- CHANGELOG.md | 1 - README.md | 151 ++++++++++++++++++++++++++++---------------------- USER_GUIDE.md | 19 +++++-- 3 files changed, 99 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b41977f..ee7b03b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,7 +35,6 @@ version of the log-log graph of the frequency count. * `LogBinJsonRenderer::printTo()` prints the frequency count in JSON format. - * Memory consumption * See [HelloCoroutineWithProfiler](examples/HelloCoroutineWithProfiler) and [HelloSchedulerWithProfiler](examples/HelloSchedulerWithProfiler). * Thanks to peufeu2@ who provided the ideas and proof of concept in diff --git a/README.md b/README.md index ec4f280..1c2ec41 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ others (in my opinion of course): and 4 bytes of static RAM independent of the number of coroutines * extremely fast context switching * Direct Scheduling (call `Coroutine::runCoroutine()` directly) - * ~1.2 microseconds on a 16 MHz ATmega328P + * ~1.0 microseconds on a 16 MHz ATmega328P * ~0.4 microseconds on a 48 MHz SAMD21 * ~0.3 microseconds on a 72 MHz STM32 * ~0.3 microseconds on a 80 MHz ESP8266 @@ -67,12 +67,12 @@ others (in my opinion of course): * ~0.17 microseconds on 96 MHz Teensy 3.2 (depending on compiler settings) * Coroutine Scheduling (use `CoroutineScheduler::loop()`): - * ~5.5 microseconds on a 16 MHz ATmega328P + * ~5.2 microseconds on a 16 MHz ATmega328P * ~1.3 microseconds on a 48 MHz SAMD21 * ~0.9 microseconds on a 72 MHz STM32 - * ~0.6 microseconds on a 80 MHz ESP8266 - * ~0.2 microseconds on a 240 MHz ESP32 - * ~0.5 microseconds on 96 MHz Teensy 3.2 (depending on compiler + * ~0.8 microseconds on a 80 MHz ESP8266 + * ~0.3 microseconds on a 240 MHz ESP32 + * ~0.4 microseconds on 96 MHz Teensy 3.2 (depending on compiler settings) * uses the [computed goto](https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html) feature of the GCC compiler (also supported by Clang) to avoid the @@ -298,9 +298,9 @@ Version 1.5 added support for profiling the execution time of only a single implementation (`LogBinProfiler`) is provided. The [HelloCoroutineWithProfiler.ino](examples/HelloCoroutineWithProfiler) -program shows how to setup the profilers and extract the profiling information. -This example is intended for resource constrained 8-bit processors which do not -want to pay for the cost of the `CoroutineScheduler`. +program shows how to setup the profilers and extract the profiling information +using the `Coroutine::runCoroutineWithProfiler()` instead of the usual +`Coroutine::runCoroutine()`: ```C++ #include @@ -332,12 +332,9 @@ COROUTINE(printHelloWorld) { COROUTINE(printProfiling) { COROUTINE_LOOP() { - LogBinTableRenderer tableRenderer(Coroutine::getRoot()); - LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); - - tableRenderer.printTo( + LogBinTableRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); - jsonRenderer.printTo( + LogBinJsonRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/); COROUTINE_DELAY(5000); @@ -395,12 +392,13 @@ blinkLed 65535 830 0 0 0 0 0 0 0 0 0 ### HelloSchedulerWithProfiler The [HelloSchedulerWithProfiler.ino](examples/HelloSchedulerWithProfiler) sketch -implements the same thing as `HelloCoroutineWithProfiler` using the -`CoroutineScheduler` which automatically supports the `CoroutineProfiler`. -The assumption was that if the environment has enough resources to support -a `CoroutineScheduler`, then it is probably not a large burden to include the -code to support `CoroutineProfiler` by default. Hence, this is intended for -32-bit environments where flash and static RAM resources are more plentiful. +implements the same thing as `HelloCoroutineWithProfiler` using 2 techniques to +handle larger numbers of coroutines: + +* use `LogBinProfiler::createProfilers()` to automatically create the profilers + on the heap and assign them to all coroutines +* use `CoroutineScheduler::loopWithProfiler()` method instead of the + `CoroutineScheduler::loop()` method. ```C++ #include @@ -432,12 +430,9 @@ COROUTINE(printHelloWorld) { COROUTINE(printProfiling) { COROUTINE_LOOP() { - LogBinTableRenderer tableRenderer(Coroutine::getRoot()); - LogBinJsonRenderer jsonRenderer(Coroutine::getRoot()); - - tableRenderer.printTo( + LogBinTableRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/, false /*clear*/); - jsonRenderer.printTo( + LogBinJsonRenderer::printTo( Serial, 3 /*startBin*/, 14 /*endBin*/); COROUTINE_DELAY(5000); @@ -457,13 +452,13 @@ void setup() { readPin.setName(F("readPin")); // Create profilers on the heap and attach them to all coroutines. - LogBinProfiler::createProfilers(Coroutine::getRoot()); + LogBinProfiler::createProfilers(); CoroutineScheduler::setup(); } void loop() { - CoroutineScheduler::loop(); + CoroutineScheduler::loopWithProfiler(); } ``` @@ -665,6 +660,9 @@ On 8-bit processors (AVR Nano, Uno, etc): sizeof(Coroutine): 16 sizeof(CoroutineScheduler): 2 sizeof(Channel): 5 +sizeof(LogBinProfiler): 66 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 ``` On 32-bit processors (e.g. Teensy ARM, ESP8266, ESP32): @@ -673,6 +671,9 @@ On 32-bit processors (e.g. Teensy ARM, ESP8266, ESP32): sizeof(Coroutine): 28 sizeof(CoroutineScheduler): 4 sizeof(Channel): 12 +sizeof(LogBinProfiler): 68 +sizeof(LogBinTableRenderer): 1 +sizeof(LogBinJsonRenderer): 1 ``` The `CoroutineScheduler` consumes only 2 bytes (8-bit processors) or 4 bytes @@ -713,24 +714,30 @@ etc) for a handful of AceRoutine features. Here are some highlights: | One Coroutine (seconds) | 1904/ 212 | 288/ 26 | | Two Coroutines (seconds) | 2130/ 236 | 514/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 1992/ 214 | 376/ 28 | -| Scheduler, Two Coroutines (millis) | 2178/ 238 | 562/ 52 | +| One Coroutine, Profiler | 1874/ 212 | 258/ 26 | +| Two Coroutines, Profiler | 2132/ 236 | 516/ 50 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 1964/ 214 | 348/ 28 | -| Scheduler, Two Coroutines (micros) | 2122/ 238 | 506/ 52 | +| Scheduler, One Coroutine (millis) | 1928/ 214 | 312/ 28 | +| Scheduler, Two Coroutines (millis) | 2114/ 238 | 498/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 2092/ 214 | 476/ 28 | -| Scheduler, Two Coroutines (seconds) | 2310/ 238 | 694/ 52 | +| Scheduler, One Coroutine (micros) | 1900/ 214 | 284/ 28 | +| Scheduler, Two Coroutines (micros) | 2058/ 238 | 442/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 2046/ 214 | 430/ 28 | -| Scheduler, Two Coroutines (setup) | 2332/ 238 | 716/ 52 | +| Scheduler, One Coroutine (seconds) | 2028/ 214 | 412/ 28 | +| Scheduler, Two Coroutines (seconds) | 2246/ 238 | 630/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 2024/ 214 | 408/ 28 | -| Scheduler, Two Coroutines (man setup) | 2318/ 238 | 702/ 52 | +| Scheduler, One Coroutine (setup) | 1978/ 214 | 362/ 28 | +| Scheduler, Two Coroutines (setup) | 2264/ 238 | 648/ 52 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 2100/ 286 | 484/ 100 | -| Scheduler, LogBinTableRenderer | 3502/ 304 | 1886/ 118 | -| Scheduler, LogBinJsonRenderer | 3022/ 308 | 1406/ 122 | +| Scheduler, One Coroutine (man setup) | 1956/ 214 | 340/ 28 | +| Scheduler, Two Coroutines (man setup) | 2250/ 238 | 634/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine, Profiler | 1992/ 214 | 376/ 28 | +| Scheduler, Two Coroutines, Profiler | 2178/ 238 | 562/ 52 | +|---------------------------------------+--------------+-------------| +| Scheduler, LogBinProfiler | 2112/ 286 | 496/ 100 | +| Scheduler, LogBinTableRenderer | 3514/ 304 | 1898/ 118 | +| Scheduler, LogBinJsonRenderer | 3034/ 308 | 1418/ 122 | |---------------------------------------+--------------+-------------| | Blink Function | 1948/ 189 | 332/ 3 | | Blink Coroutine | 2118/ 212 | 502/ 26 | @@ -757,24 +764,30 @@ etc) for a handful of AceRoutine features. Here are some highlights: | One Coroutine (seconds) | 265209/28028 | 228/ 44 | | Two Coroutines (seconds) | 265385/28060 | 404/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (millis) | 265321/28036 | 340/ 52 | -| Scheduler, Two Coroutines (millis) | 265449/28060 | 468/ 76 | +| One Coroutine, Profiler | 265257/28028 | 276/ 44 | +| Two Coroutines, Profiler | 265433/28060 | 452/ 76 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (millis) | 265241/28036 | 260/ 52 | +| Scheduler, Two Coroutines (millis) | 265385/28060 | 404/ 76 | +|---------------------------------------+--------------+-------------| +| Scheduler, One Coroutine (micros) | 265257/28036 | 276/ 52 | +| Scheduler, Two Coroutines (micros) | 265401/28060 | 420/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (micros) | 265321/28036 | 340/ 52 | -| Scheduler, Two Coroutines (micros) | 265449/28060 | 468/ 76 | +| Scheduler, One Coroutine (seconds) | 265257/28036 | 276/ 52 | +| Scheduler, Two Coroutines (seconds) | 265417/28060 | 436/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (seconds) | 265337/28036 | 356/ 52 | -| Scheduler, Two Coroutines (seconds) | 265497/28060 | 516/ 76 | +| Scheduler, One Coroutine (setup) | 265273/28036 | 292/ 52 | +| Scheduler, Two Coroutines (setup) | 265433/28060 | 452/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (setup) | 265337/28036 | 356/ 52 | -| Scheduler, Two Coroutines (setup) | 265513/28060 | 532/ 76 | +| Scheduler, One Coroutine (man setup) | 265257/28036 | 276/ 52 | +| Scheduler, Two Coroutines (man setup) | 265433/28060 | 452/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, One Coroutine (man setup) | 265337/28036 | 356/ 52 | -| Scheduler, Two Coroutines (man setup) | 265513/28060 | 532/ 76 | +| Scheduler, One Coroutine, Profiler | 265321/28036 | 340/ 52 | +| Scheduler, Two Coroutines, Profiler | 265449/28060 | 468/ 76 | |---------------------------------------+--------------+-------------| -| Scheduler, LogBinProfiler | 265449/28100 | 468/ 116 | +| Scheduler, LogBinProfiler | 265465/28100 | 484/ 116 | | Scheduler, LogBinTableRenderer | 267381/28100 | 2400/ 116 | -| Scheduler, LogBinJsonRenderer | 266773/28104 | 1792/ 120 | +| Scheduler, LogBinJsonRenderer | 266789/28104 | 1808/ 120 | |---------------------------------------+--------------+-------------| | Blink Function | 265669/28064 | 688/ 80 | | Blink Coroutine | 265801/28100 | 820/ 116 | @@ -801,25 +814,33 @@ See [examples/AutoBenchmark](examples/AutoBenchmark). Here are 2 samples: Arduino Nano: ``` -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 1.700 | 0.000 | -| DirectScheduling | 10000 | 2.900 | 1.200 | -| CoroutineScheduling | 10000 | 7.200 | 5.500 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 10000 | 1.900 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 10000 | 2.800 | 0.900 | +| DirectSchedulingWithProfiler | 10000 | 5.800 | 3.900 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 10000 | 7.000 | 5.100 | +| CoroutineSchedulingWithProfiler | 10000 | 9.300 | 7.400 | ++---------------------------------+--------+-------------+--------+ ``` ESP8266: ``` -+---------------------+--------+-------------+--------+ -| Functionality | iters | micros/iter | diff | -|---------------------+--------+-------------+--------| -| EmptyLoop | 10000 | 0.100 | 0.000 | -| DirectScheduling | 10000 | 0.500 | 0.400 | -| CoroutineScheduling | 10000 | 1.000 | 0.900 | -+---------------------+--------+-------------+--------+ ++---------------------------------+--------+-------------+--------+ +| Functionality | iters | micros/iter | diff | +|---------------------------------+--------+-------------+--------| +| EmptyLoop | 10000 | 0.100 | 0.000 | +|---------------------------------+--------+-------------+--------| +| DirectScheduling | 10000 | 0.500 | 0.400 | +| DirectSchedulingWithProfiler | 10000 | 0.800 | 0.700 | +|---------------------------------+--------+-------------+--------| +| CoroutineScheduling | 10000 | 0.900 | 0.800 | +| CoroutineSchedulingWithProfiler | 10000 | 1.100 | 1.000 | ++---------------------------------+--------+-------------+--------+ ``` diff --git a/USER_GUIDE.md b/USER_GUIDE.md index 621b172..f8b3797 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -45,7 +45,7 @@ is installed. * [Running Coroutine With Profiler](#RunningCoroutineWithProfiler) * [Running Scheduler With Profiler](#RunningSchedulerWithProfiler) * [Rendering the Profiler Results](#RenderingProfilerResults) - * [Profiling Resource Consumption](#ProfilingResourceConsumption) + * [Profiler Resource Consumption](#ProfilerResourceConsumption) * [Coroutine Communication](#Communication) * [Instance Variables](#InstanceVariables) * [Channels (Experimental)](#Channels) @@ -1414,8 +1414,8 @@ this: } ``` - -### Profiling Resource Consumption + +### Profiler Resource Consumption The ability to profile the execution time of coroutines does not come for free, but I have tried to make it as cheap as possible. @@ -1450,9 +1450,16 @@ If the profiling feature is enabled, the The [AutoBenchmark](examples/AutoBenchmark) program shows that calling the profiler-enabled methods, `Coroutine::runCoroutineWithProfiler()` and -`CoroutineScheduler::loopWithProfiler(), increases latency by only 100ns (AVR, -ESP8266), 133ns (STM32, Teensy 3.2), and 33ns (ESP32). Most applications should -not be affected by this small increase in latency. +`CoroutineScheduler::loopWithProfiler(), increases latency by: + +* 3 - 3.2 micros on AVR +* 0.4 micros on STM32F1 +* 0.2 - 0.3 micros on ESP8266 +* 0.1 micros on ESP32 +* 0.033 - 0.166 micros on Teensy 3.2 + +On 32-bit processors, the overhead seems neglegible. On 8-bit processors, the 3 +microsecond of overhead might be an issue with sensitive applications. ## Coroutine Communication From f6bc4671b999a032df5c2e98ce044f4911464541 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 19 Mar 2022 16:14:14 -0700 Subject: [PATCH 53/59] README.md,USER_GUIDE.md: Update list of classes in library; add AceCommon as a required library --- README.md | 53 ++++++++++++++++++++++++++++++++++----------------- USER_GUIDE.md | 43 ++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 1c2ec41..a78207b 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,10 @@ [![AUnit Tests](https://github.com/bxparks/AceRoutine/actions/workflows/aunit_tests.yml/badge.svg)](https://github.com/bxparks/AceRoutine/actions/workflows/aunit_tests.yml) -**Breaking Changes in v1.3**: Breaking changes were made in v1.3 to reduce the -flash memory consumption of `Coroutine` instances by 800-1000 bytes. See the -[CHANGELOG.md](CHANGELOG.md) for a complete list. +**NEW: Profiling in v1.5**: Version 1.5 adds the ability to profile the +execution time of `Coroutine::runCoroutine()` and render the histogram as a +table or a JSON object. See [Coroutine +Profiling](USER_GUIDE.md#CoroutineProfiling) for details. A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms. @@ -16,15 +17,28 @@ using a `yield()` or `delay()` functionality to allow other coroutines to execute. When the scheduler makes its way back to the original coroutine, the execution continues right after the `yield()` or `delay()`. -There are only 3 classes in this library: -* `Coroutine` class provides the context variables for all coroutines, -* `CoroutineScheduler` class optionally handles the scheduling, +There are only 2 core classes in this library: + +* `Coroutine` class provides the context variables for all coroutines +* `CoroutineScheduler` class handles the scheduling (optional) + +The following classes are used for profiling: + +* `CoroutineProfiler` interface +* `LogBinProfiler` provides an implementation that tracks the execution time + in 32 logarithmic bins between 1us to 4295s. +* `LogBinTableRenderer` prints the histogram as a table +* `LogBinJsonRenderer` prints the history as a JSON object + +The following is an experimental feature: + * `Channel` class allows coroutines to send messages to each other. This is an experimental feature whose API and feature may change considerably in the future. The library provides a number of macros to help create coroutines and manage their life cycle: + * `COROUTINE()`: defines an instance of the `Coroutine` class or an instance of a user-defined subclass of `Coroutine` * `COROUTINE_BEGIN()`: must occur at the start of a coroutine body @@ -44,6 +58,7 @@ their life cycle: Here are some of the compelling features of this library compared to others (in my opinion of course): + * low memory usage * 8-bit (e.g. AVR) processors: * the first `Coroutine` consumes about 230 bytes of flash @@ -84,6 +99,7 @@ others (in my opinion of course): * fully unit tested using [AUnit](https://github.com/bxparks/AUnit) Some limitations are: + * A `Coroutine` cannot return any values. * A `Coroutine` is stackless and therefore cannot preserve local stack variables across multiple calls. Often the class member variables or function static @@ -104,7 +120,7 @@ AceRoutine is a self-contained library that works on any platform supporting the Arduino API (AVR, Teensy, ESP8266, ESP32, etc), and it provides a handful of additional macros that can reduce boilerplate code. -**Version**: 1.4.2 (2022-02-04) +**Version**: 1.5.0 (2022-03-19) **Changelog**: [CHANGELOG.md](CHANGELOG.md) @@ -393,7 +409,7 @@ blinkLed 65535 830 0 0 0 0 0 0 0 0 0 The [HelloSchedulerWithProfiler.ino](examples/HelloSchedulerWithProfiler) sketch implements the same thing as `HelloCoroutineWithProfiler` using 2 techniques to -handle larger numbers of coroutines: +handle more than a handful of coroutines: * use `LogBinProfiler::createProfilers()` to automatically create the profilers on the heap and assign them to all coroutines @@ -480,22 +496,22 @@ blinkLed 65535 830 0 0 0 0 0 0 0 0 0 ## Installation -The latest stable release is available in the Arduino IDE Library Manager. Only -a single library needs to be installed since v1.1: +The latest stable release is available in the Arduino IDE Library Manager. Two +libraries need to be installed as of v1.5.0: * Search for "AceRoutine". Click Install. +* It should automatically install (or prompt you to install) the "AceCommon" + library. -The direct dependency to the [AceCommon](https://github.com/bxparks/AceCommon) -library was removed in v1.4.2, but some of the programs under `tests/` and -`examples/` may still require the `AceCommon` library to be installed. - -The development version can be installed by cloning the following git repo: +The development version can be installed by cloning the following git repos: * AceRoutine (https://github.com/bxparks/AceRoutine) +* AceCommon (https://github.com/bxparks/AceCommon) -You can copy this directory to the `./libraries` directory used by the -Arduino IDE. (The result is a directory named `./libraries/AceRoutine`). Or you -can create symlinks from `/.libraries` to this directory. +You can copy these directories to the `./libraries` directory used by the +Arduino IDE. (You should see 2 directories, named `./libraries/AceRoutine` and +`./libraries/AceCommon). Or you can create symlinks from `/.libraries` to these +directories. The `develop` branch contains the latest working version. The `master` branch contains the stable release. @@ -504,6 +520,7 @@ The `master` branch contains the stable release. ### Source Code The source files are organized as follows: + * `src/AceRoutine.h` - main header file * `src/ace_routine/` - implementation files * `src/ace_routine/testing/` - internal testing files diff --git a/USER_GUIDE.md b/USER_GUIDE.md index f8b3797..f792228 100644 --- a/USER_GUIDE.md +++ b/USER_GUIDE.md @@ -4,7 +4,7 @@ See the [README.md](README.md) for installation instructions and other background information. This document describes how to use the library once it is installed. -**Version**: 1.4.2 (2022-02-04) +**Version**: 1.5.0 (2022-03-19) ## Table of Contents @@ -1059,12 +1059,10 @@ class ManualCoroutine : public Coroutine { ManualCoroutine manualRoutine(params, ..., objects, ...); ``` -Prior to v1.3, a manual coroutine (created without the `COROUTINE()` macro) was -*not* automatically added to the linked list used by the `CoroutineScheduler`. -This was changed in v1.3 so that the `Coroutine::Coroutine()` constructor -now automatically adds itself to the internal linked list. Calling -`setupCoroutine()` is no longer required. The method is retained for backwards -compatibility, but it is a no-op and is marked deprecated. +The `Coroutine::Coroutine()` constructor automatically adds itself to the +internal list of coroutines, so manually created coroutines are available to the +`CoroutineScheduler` automatically just like the coroutines defined by the +`COROUTINE()` macro. Some examples of manual coroutines: @@ -1139,7 +1137,7 @@ void setup() { You need to call `CoroutineScheduler::setupCoroutines()` explicitly if you want it. The `CoroutineScheduler::setup()` method does *not* call `setupCoroutines()` -automatically. +automatically in order to save flash memory if the feature is not used. **Warning**: The `Coroutine::setupCoroutine()` can consume significant amounts of memory, especially on AVR processors. On AVR processors, each @@ -1155,9 +1153,14 @@ about 14 bytes of flash per invocation. Version 1.5 added the ability to profile the execution time of `Coroutine::runCoroutine()` and render the information as a formatted table, or -as a JSON object. The `CoroutineProfiler` is an interface that allows an object -to receive information about the execution time of the -`Coroutine::runCoroutine()` method: +as a JSON object. If the profiling feature is not used, no additional flash +memory is consumed. The static RAM usage does increase by 2 bytes (8-bits) and 4 +bytes (32-bits) per coroutine. + +The following classes and API methods were added to support the profiling +feature. The `CoroutineProfiler` class is an interface that allows an object to +receive information about the execution time of the `Coroutine::runCoroutine()` +method: ```C++ class CoroutineProfiler { @@ -1185,12 +1188,18 @@ class Coroutine { }; ``` +**Note**: When creating Coroutines with profiling enabled, it will probably be +necessary to assign human-readable names to each coroutine for identification +purposes. See [Coroutine Names](#CoroutineNames) for information on the +`setName()`, `getCName()`, `getFName()`, `getNameType()`, and `printNameTo()` +methods. Each coroutine name will consume additional flash memory. + Currently only a single implementation of `CoroutineProfiler` is provided, the `LogBinProfiler`. It contains 32 bins of `uint16_t` which tracks the number of times a `micros` was seen. The bins are logarithmically scaled, so that Bin 0 collects all events `<2us`, Bin 1 collects events `<4us`, Bin 2 collects events -`<8us`, Bin 30 collects events `<2147s`, and the last Bin 31 collects events -`<4295s`. +`<8us`, ..., Bin 30 collects events `<2147s`, and the last Bin 31 collects +events `<4295s`. ```C++ class LogBinProfiler : public CoroutineProfiler { @@ -1384,16 +1393,16 @@ class LogBinJsonRenderer{ else if needed. * The `startBin` (0-31) and `endBin` (0-32) identify the bins which should be printed. - * A range of something like [2, 14) is useful to keep the width of the table + * A range of something like [2, 13) is useful to keep the width of the table reasonable. - * Often the bins lower and higher than this range do not contain any events. + * Often the bins below and above than this range do not contain any events. * The `clear` flag (default true) causes the bins to be cleared (through the `LogBinProfiler::clear()` method) so that new events can be tracked. * The `rollup` flag (default true) causes roll up of the exterior bins. * Events before `startBin` are added to the first bin. * Events at or after `endBin` are added to the last bin (at `endBin-1`) -For example, calling `LogBinTableRenderer::printTo(Serial, 2, 16)` prints +For example, calling `LogBinTableRenderer::printTo(Serial, 2, 13)` prints something like this: ``` @@ -1403,7 +1412,7 @@ readPin 65535 1128 0 0 0 0 0 0 0 0 0 blinkLed 65535 800 0 0 0 0 0 0 0 0 0 ``` -And calling `LogBinJsonRenderer::printTo(Serial, 2, 16)` prints something like +And calling `LogBinJsonRenderer::printTo(Serial, 2, 13)` prints something like this: ``` From 9aefe3fe36bf2b2037e9d3409961ce34aa132236 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 19 Mar 2022 16:15:01 -0700 Subject: [PATCH 54/59] Bump version to 1.5.0 --- CHANGELOG.md | 1 + docs/doxygen.cfg | 2 +- examples/ChannelBenchmark/README.md | 2 +- examples/ChannelBenchmark/generate_readme.py | 2 +- library.properties | 2 +- src/AceRoutine.h | 4 ++-- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee7b03b..cdd1503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog * Unreleased +* 1.5.0 (2022-03-19) * (Re)add support for human-readable coroutine names. * See [Coroutine Names](USER_GUIDE.md#CoroutineNames) in the `USER_GUIDE.md`. diff --git a/docs/doxygen.cfg b/docs/doxygen.cfg index a42090d..1ced2eb 100644 --- a/docs/doxygen.cfg +++ b/docs/doxygen.cfg @@ -38,7 +38,7 @@ PROJECT_NAME = "AceRoutine" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.2 +PROJECT_NUMBER = 1.5.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/examples/ChannelBenchmark/README.md b/examples/ChannelBenchmark/README.md index 8a88508..f95d9e9 100644 --- a/examples/ChannelBenchmark/README.md +++ b/examples/ChannelBenchmark/README.md @@ -16,7 +16,7 @@ operations took, per iteration. All times in below are in microseconds. -**Version**: AceRoutine v1.4.2 +**Version**: AceRoutine v1.5.0 **DO NOT EDIT**: This file was auto-generated using `make README.md`. diff --git a/examples/ChannelBenchmark/generate_readme.py b/examples/ChannelBenchmark/generate_readme.py index 0cf4d70..a409a84 100755 --- a/examples/ChannelBenchmark/generate_readme.py +++ b/examples/ChannelBenchmark/generate_readme.py @@ -40,7 +40,7 @@ All times in below are in microseconds. -**Version**: AceRoutine v1.4.2 +**Version**: AceRoutine v1.5.0 **DO NOT EDIT**: This file was auto-generated using `make README.md`. diff --git a/library.properties b/library.properties index ece52b7..14c5494 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=AceRoutine -version=1.4.2 +version=1.5.0 author=Brian T. Park maintainer=Brian T. Park sentence=A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms. diff --git a/src/AceRoutine.h b/src/AceRoutine.h index 9947f94..0ef39b4 100644 --- a/src/AceRoutine.h +++ b/src/AceRoutine.h @@ -43,8 +43,8 @@ SOFTWARE. #endif // Version format: xxyyzz == "xx.yy.zz" -#define ACE_ROUTINE_VERSION 10402 -#define ACE_ROUTINE_VERSION_STRING "1.4.2" +#define ACE_ROUTINE_VERSION 10500 +#define ACE_ROUTINE_VERSION_STRING "1.5.0" #include "ace_routine/Coroutine.h" #include "ace_routine/CoroutineScheduler.h" From ece7b55245b67ca03af9742bb82927b3d9295a90 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 19 Mar 2022 16:19:03 -0700 Subject: [PATCH 55/59] src: Fix doxygen warnings --- src/ace_routine/CoroutineProfiler.h | 4 ++++ src/ace_routine/LogBinJsonRenderer.h | 2 +- src/ace_routine/LogBinProfiler.h | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ace_routine/CoroutineProfiler.h b/src/ace_routine/CoroutineProfiler.h index 14bf99f..af18cb3 100644 --- a/src/ace_routine/CoroutineProfiler.h +++ b/src/ace_routine/CoroutineProfiler.h @@ -29,6 +29,10 @@ SOFTWARE. namespace ace_routine { +/** + * An interface class for profiling classes that can track the elapsed time + * consumed by `Coroutine::runCoroutine()`. + */ class CoroutineProfiler { public: /** Use default constructor. */ diff --git a/src/ace_routine/LogBinJsonRenderer.h b/src/ace_routine/LogBinJsonRenderer.h index c39a14e..ce33da8 100644 --- a/src/ace_routine/LogBinJsonRenderer.h +++ b/src/ace_routine/LogBinJsonRenderer.h @@ -34,7 +34,7 @@ SOFTWARE. namespace ace_routine { /** - * Print the `LogBinProfiler bins as a JSON array. For example, here + * Print the `LogBinProfiler` bins as a JSON array. For example, here * is the output from `examples/SoundManager`: * * @verbatim diff --git a/src/ace_routine/LogBinProfiler.h b/src/ace_routine/LogBinProfiler.h index 6b3deed..b0ef8c0 100644 --- a/src/ace_routine/LogBinProfiler.h +++ b/src/ace_routine/LogBinProfiler.h @@ -53,6 +53,7 @@ namespace ace_routine { template class LogBinProfilerTemplate : public CoroutineProfiler { public: + /** Number of event counter bins used by this class. */ static const uint8_t kNumBins = 32; public: @@ -134,6 +135,7 @@ class LogBinProfilerTemplate : public CoroutineProfiler { } public: + /** Event count bins. */ uint16_t mBins[kNumBins]; }; From e60321feb6efdef29199bc84db2f6a696d6ac030 Mon Sep 17 00:00:00 2001 From: Brian Park Date: Sat, 19 Mar 2022 16:19:26 -0700 Subject: [PATCH 56/59] docs: Regenerate doxygen --- docs/html/AceRoutine_8h_source.html | 14 +- docs/html/Channel_8h_source.html | 2 +- docs/html/ClockInterface_8h_source.html | 2 +- docs/html/CoroutineProfiler_8h_source.html | 133 +++ docs/html/CoroutineScheduler_8h_source.html | 279 ++--- docs/html/Coroutine_8cpp_source.html | 45 +- docs/html/Coroutine_8h.html | 94 +- docs/html/Coroutine_8h__dep__incl.map | 11 +- docs/html/Coroutine_8h__dep__incl.md5 | 2 +- docs/html/Coroutine_8h__dep__incl.png | Bin 24212 -> 64074 bytes docs/html/Coroutine_8h__incl.map | 14 +- docs/html/Coroutine_8h__incl.md5 | 2 +- docs/html/Coroutine_8h__incl.png | Bin 12138 -> 24033 bytes docs/html/Coroutine_8h_source.html | 840 ++++++++------- docs/html/LogBinJsonRenderer_8h_source.html | 182 ++++ docs/html/LogBinProfiler_8cpp_source.html | 145 +++ docs/html/LogBinProfiler_8h_source.html | 206 ++++ .../html/LogBinTableRenderer_8cpp_source.html | 230 +++++ docs/html/LogBinTableRenderer_8h_source.html | 204 ++++ docs/html/annotated.html | 10 +- .../classace__routine_1_1Channel-members.html | 2 +- docs/html/classace__routine_1_1Channel.html | 2 +- ...ce__routine_1_1ClockInterface-members.html | 2 +- .../classace__routine_1_1ClockInterface.html | 2 +- ..._routine_1_1CoroutineProfiler-members.html | 88 ++ ...lassace__routine_1_1CoroutineProfiler.html | 151 +++ ...e_1_1CoroutineProfiler__inherit__graph.map | 4 + ...e_1_1CoroutineProfiler__inherit__graph.md5 | 1 + ...e_1_1CoroutineProfiler__inherit__graph.png | Bin 0 -> 6308 bytes ...1_1CoroutineSchedulerTemplate-members.html | 7 +- ...routine_1_1CoroutineSchedulerTemplate.html | 47 +- ..._routine_1_1CoroutineTemplate-members.html | 120 ++- ...lassace__routine_1_1CoroutineTemplate.html | 971 ++++++++++++------ ...tine_1_1CoroutineTemplate__coll__graph.map | 5 +- ...tine_1_1CoroutineTemplate__coll__graph.md5 | 2 +- ...tine_1_1CoroutineTemplate__coll__graph.png | Bin 4111 -> 7671 bytes ...1_1LogBinJsonRendererTemplate-members.html | 87 ++ ...routine_1_1LogBinJsonRendererTemplate.html | 191 ++++ ...ine_1_1LogBinProfilerTemplate-members.html | 95 ++ ...ce__routine_1_1LogBinProfilerTemplate.html | 253 +++++ ...1_1LogBinProfilerTemplate__coll__graph.map | 4 + ...1_1LogBinProfilerTemplate__coll__graph.md5 | 1 + ...1_1LogBinProfilerTemplate__coll__graph.png | Bin 0 -> 6280 bytes ...LogBinProfilerTemplate__inherit__graph.map | 4 + ...LogBinProfilerTemplate__inherit__graph.md5 | 1 + ...LogBinProfilerTemplate__inherit__graph.png | Bin 0 -> 6280 bytes ..._1LogBinTableRendererTemplate-members.html | 87 ++ ...outine_1_1LogBinTableRendererTemplate.html | 199 ++++ docs/html/classes.html | 21 +- docs/html/compat_8h.html | 15 +- docs/html/compat_8h__dep__incl.map | 13 +- docs/html/compat_8h__dep__incl.md5 | 2 +- docs/html/compat_8h__dep__incl.png | Bin 6226 -> 62175 bytes docs/html/compat_8h_source.html | 2 +- docs/html/dir_000000_000001.html | 2 +- .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 2 +- .../dir_bbf1ec131ffa96b8d365d81f56025723.html | 2 +- docs/html/files.html | 10 +- docs/html/functions.html | 189 +++- docs/html/functions_func.html | 140 ++- docs/html/functions_type.html | 8 +- docs/html/functions_vars.html | 45 +- docs/html/globals.html | 2 +- docs/html/globals_defs.html | 2 +- docs/html/graph_legend.html | 2 +- docs/html/hierarchy.html | 92 ++ docs/html/index.html | 2 +- docs/html/inherit_graph_0.map | 3 + docs/html/inherit_graph_0.md5 | 1 + docs/html/inherit_graph_0.png | Bin 0 -> 1846 bytes docs/html/inherit_graph_1.map | 3 + docs/html/inherit_graph_1.md5 | 1 + docs/html/inherit_graph_1.png | Bin 0 -> 1916 bytes docs/html/inherit_graph_2.map | 4 + docs/html/inherit_graph_2.md5 | 1 + docs/html/inherit_graph_2.png | Bin 0 -> 5216 bytes docs/html/inherit_graph_3.map | 3 + docs/html/inherit_graph_3.md5 | 1 + docs/html/inherit_graph_3.png | Bin 0 -> 3496 bytes docs/html/inherit_graph_4.map | 3 + docs/html/inherit_graph_4.md5 | 1 + docs/html/inherit_graph_4.png | Bin 0 -> 3144 bytes docs/html/inherit_graph_5.map | 3 + docs/html/inherit_graph_5.md5 | 1 + docs/html/inherit_graph_5.png | Bin 0 -> 4044 bytes docs/html/inherit_graph_6.map | 3 + docs/html/inherit_graph_6.md5 | 1 + docs/html/inherit_graph_6.png | Bin 0 -> 3936 bytes docs/html/inherits.html | 118 +++ docs/html/menudata.js | 7 + docs/html/search/all_1.js | 44 +- docs/html/search/all_2.js | 4 +- docs/html/search/all_3.js | 4 +- docs/html/search/all_4.js | 5 +- docs/html/search/all_5.js | 20 +- docs/html/search/all_6.js | 16 +- docs/html/search/all_7.js | 11 +- docs/html/search/all_8.js | 13 +- docs/html/search/all_9.js | 15 +- docs/html/search/all_a.js | 20 +- docs/html/search/all_b.js | 6 +- docs/html/search/all_c.js | 20 +- docs/html/search/all_d.html | 30 + docs/html/search/all_d.js | 4 + docs/html/search/all_e.html | 30 + docs/html/search/all_e.js | 4 + docs/html/search/all_f.html | 30 + docs/html/search/all_f.js | 5 + docs/html/search/classes_0.js | 9 +- docs/html/search/classes_1.html | 30 + docs/html/search/classes_1.js | 6 + docs/html/search/defines_0.js | 2 +- docs/html/search/defines_1.js | 24 +- docs/html/search/defines_2.js | 6 +- docs/html/search/defines_3.js | 2 +- docs/html/search/defines_4.js | 4 +- docs/html/search/files_0.js | 4 +- docs/html/search/functions_0.js | 14 +- docs/html/search/functions_1.js | 3 +- docs/html/search/functions_2.js | 18 +- docs/html/search/functions_3.js | 12 +- docs/html/search/functions_4.js | 6 +- docs/html/search/functions_5.js | 6 +- docs/html/search/functions_6.js | 18 +- docs/html/search/functions_7.js | 6 +- docs/html/search/functions_8.js | 19 +- docs/html/search/functions_9.html | 30 + docs/html/search/functions_9.js | 4 + docs/html/search/functions_a.html | 30 + docs/html/search/functions_a.js | 4 + docs/html/search/functions_b.html | 30 + docs/html/search/functions_b.js | 5 + docs/html/search/pages_0.js | 2 +- docs/html/search/searchdata.js | 8 +- docs/html/search/typedefs_0.js | 2 +- docs/html/search/typedefs_1.js | 2 +- docs/html/search/typedefs_2.html | 30 + docs/html/search/typedefs_2.js | 4 + docs/html/search/variables_0.js | 15 +- docs/html/search/variables_1.js | 14 +- 140 files changed, 4867 insertions(+), 1229 deletions(-) create mode 100644 docs/html/CoroutineProfiler_8h_source.html create mode 100644 docs/html/LogBinJsonRenderer_8h_source.html create mode 100644 docs/html/LogBinProfiler_8cpp_source.html create mode 100644 docs/html/LogBinProfiler_8h_source.html create mode 100644 docs/html/LogBinTableRenderer_8cpp_source.html create mode 100644 docs/html/LogBinTableRenderer_8h_source.html create mode 100644 docs/html/classace__routine_1_1CoroutineProfiler-members.html create mode 100644 docs/html/classace__routine_1_1CoroutineProfiler.html create mode 100644 docs/html/classace__routine_1_1CoroutineProfiler__inherit__graph.map create mode 100644 docs/html/classace__routine_1_1CoroutineProfiler__inherit__graph.md5 create mode 100644 docs/html/classace__routine_1_1CoroutineProfiler__inherit__graph.png create mode 100644 docs/html/classace__routine_1_1LogBinJsonRendererTemplate-members.html create mode 100644 docs/html/classace__routine_1_1LogBinJsonRendererTemplate.html create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate-members.html create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate.html create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate__coll__graph.map create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate__coll__graph.md5 create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate__coll__graph.png create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate__inherit__graph.map create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate__inherit__graph.md5 create mode 100644 docs/html/classace__routine_1_1LogBinProfilerTemplate__inherit__graph.png create mode 100644 docs/html/classace__routine_1_1LogBinTableRendererTemplate-members.html create mode 100644 docs/html/classace__routine_1_1LogBinTableRendererTemplate.html create mode 100644 docs/html/hierarchy.html create mode 100644 docs/html/inherit_graph_0.map create mode 100644 docs/html/inherit_graph_0.md5 create mode 100644 docs/html/inherit_graph_0.png create mode 100644 docs/html/inherit_graph_1.map create mode 100644 docs/html/inherit_graph_1.md5 create mode 100644 docs/html/inherit_graph_1.png create mode 100644 docs/html/inherit_graph_2.map create mode 100644 docs/html/inherit_graph_2.md5 create mode 100644 docs/html/inherit_graph_2.png create mode 100644 docs/html/inherit_graph_3.map create mode 100644 docs/html/inherit_graph_3.md5 create mode 100644 docs/html/inherit_graph_3.png create mode 100644 docs/html/inherit_graph_4.map create mode 100644 docs/html/inherit_graph_4.md5 create mode 100644 docs/html/inherit_graph_4.png create mode 100644 docs/html/inherit_graph_5.map create mode 100644 docs/html/inherit_graph_5.md5 create mode 100644 docs/html/inherit_graph_5.png create mode 100644 docs/html/inherit_graph_6.map create mode 100644 docs/html/inherit_graph_6.md5 create mode 100644 docs/html/inherit_graph_6.png create mode 100644 docs/html/inherits.html create mode 100644 docs/html/search/all_d.html create mode 100644 docs/html/search/all_d.js create mode 100644 docs/html/search/all_e.html create mode 100644 docs/html/search/all_e.js create mode 100644 docs/html/search/all_f.html create mode 100644 docs/html/search/all_f.js create mode 100644 docs/html/search/classes_1.html create mode 100644 docs/html/search/classes_1.js create mode 100644 docs/html/search/functions_9.html create mode 100644 docs/html/search/functions_9.js create mode 100644 docs/html/search/functions_a.html create mode 100644 docs/html/search/functions_a.js create mode 100644 docs/html/search/functions_b.html create mode 100644 docs/html/search/functions_b.js create mode 100644 docs/html/search/typedefs_2.html create mode 100644 docs/html/search/typedefs_2.js diff --git a/docs/html/AceRoutine_8h_source.html b/docs/html/AceRoutine_8h_source.html index a18f0af..8cc21cf 100644 --- a/docs/html/AceRoutine_8h_source.html +++ b/docs/html/AceRoutine_8h_source.html @@ -22,7 +22,7 @@
AceRoutine -  1.4.2 +  1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
@@ -105,14 +105,18 @@
43 #endif
44 
45 // Version format: xxyyzz == "xx.yy.zz"
-
46 #define ACE_ROUTINE_VERSION 10402
-
47 #define ACE_ROUTINE_VERSION_STRING "1.4.2"
+
46 #define ACE_ROUTINE_VERSION 10500
+
47 #define ACE_ROUTINE_VERSION_STRING "1.5.0"
48 
49 #include "ace_routine/Coroutine.h"
50 #include "ace_routine/CoroutineScheduler.h"
51 #include "ace_routine/Channel.h"
-
52 
-
53 #endif
+
52 #include "ace_routine/CoroutineProfiler.h"
+
53 #include "ace_routine/LogBinProfiler.h"
+
54 #include "ace_routine/LogBinTableRenderer.h"
+
55 #include "ace_routine/LogBinJsonRenderer.h"
+
56 
+
57 #endif
diff --git a/docs/html/Channel_8h_source.html b/docs/html/Channel_8h_source.html index bf623cd..7f69fed 100644 --- a/docs/html/Channel_8h_source.html +++ b/docs/html/Channel_8h_source.html @@ -22,7 +22,7 @@
AceRoutine -  1.4.2 +  1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
diff --git a/docs/html/ClockInterface_8h_source.html b/docs/html/ClockInterface_8h_source.html index 882dded..353d93b 100644 --- a/docs/html/ClockInterface_8h_source.html +++ b/docs/html/ClockInterface_8h_source.html @@ -22,7 +22,7 @@
AceRoutine -  1.4.2 +  1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
diff --git a/docs/html/CoroutineProfiler_8h_source.html b/docs/html/CoroutineProfiler_8h_source.html new file mode 100644 index 0000000..64e2b0a --- /dev/null +++ b/docs/html/CoroutineProfiler_8h_source.html @@ -0,0 +1,133 @@ + + + + + + + +AceRoutine: /home/brian/src/AceRoutine/src/ace_routine/CoroutineProfiler.h Source File + + + + + + + + + +
+
+ + + + + + +
+
AceRoutine +  1.5.0 +
+
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
CoroutineProfiler.h
+
+
+
1 /*
+
2 MIT License
+
3 
+
4 Copyright (c) 2022 Brian T. Park
+
5 
+
6 Permission is hereby granted, free of charge, to any person obtaining a copy
+
7 of this software and associated documentation files (the "Software"), to deal
+
8 in the Software without restriction, including without limitation the rights
+
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+
10 copies of the Software, and to permit persons to whom the Software is
+
11 furnished to do so, subject to the following conditions:
+
12 
+
13 The above copyright notice and this permission notice shall be included in all
+
14 copies or substantial portions of the Software.
+
15 
+
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+
22 SOFTWARE.
+
23 */
+
24 
+
25 #ifndef ACE_ROUTINE_COROUTINE_PROFILER_H
+
26 #define ACE_ROUTINE_COROUTINE_PROFILER_H
+
27 
+
28 #include <stdint.h> // uint32_t
+
29 
+
30 namespace ace_routine {
+
31 
+ +
37  public:
+
39  CoroutineProfiler() = default;
+
40 
+
64  #if defined(ARDUINO_ARCH_AVR)
+
65  ~CoroutineProfiler() = default;
+
66  #else
+
67  virtual ~CoroutineProfiler() = default;
+
68  #endif
+
69 
+
74  virtual void updateElapsedMicros(uint32_t micros) = 0;
+
75 };
+
76 
+
77 }
+
78 
+
79 #endif
+
+
virtual void updateElapsedMicros(uint32_t micros)=0
Process the completion of the runCoroutine() method which took micros microseconds.
+
An interface class for profiling classes that can track the elapsed time consumed by Coroutine::runCo...
+
virtual ~CoroutineProfiler()=default
The destructor is NON-virtual on AVR processors because adding a virtual destructor causes flash cons...
+
CoroutineProfiler()=default
Use default constructor.
+ + + + diff --git a/docs/html/CoroutineScheduler_8h_source.html b/docs/html/CoroutineScheduler_8h_source.html index 4978f0b..5b46b04 100644 --- a/docs/html/CoroutineScheduler_8h_source.html +++ b/docs/html/CoroutineScheduler_8h_source.html @@ -22,7 +22,7 @@
AceRoutine -  1.4.2 +  1.5.0
A low-memory, fast-switching, cooperative multitasking library using stackless coroutines on Arduino platforms.
@@ -102,124 +102,167 @@
29  #include <Arduino.h> // Serial, Print
30 #endif
31 #include "Coroutine.h"
-
32 
-
33 class Print;
-
34 
-
35 namespace ace_routine {
-
36 
-
80 template <typename T_COROUTINE>
-
81 class CoroutineSchedulerTemplate {
-
82  public:
-
84  static void setup() { getScheduler()->setupScheduler(); }
-
85 
-
87  static void setupCoroutines() {
-
88  getScheduler()->setupCoroutinesInternal();
-
89  }
-
90 
-
97  static void loop() { getScheduler()->runCoroutine(); }
-
98 
-
105  static void list(Print& printer) {
-
106  getScheduler()->listCoroutines(printer);
-
107  }
-
108 
-
109  private:
-
110  // Disable copy-constructor and assignment operator
- - -
113  delete;
-
114 
-
116  static CoroutineSchedulerTemplate* getScheduler() {
-
117  static CoroutineSchedulerTemplate singletonScheduler;
-
118  return &singletonScheduler;
-
119  }
-
120 
-
122  CoroutineSchedulerTemplate() = default;
-
123 
-
134  void setupScheduler() {
-
135  mCurrent = T_COROUTINE::getRoot();
-
136  }
-
137 
-
139  void setupCoroutinesInternal() {
-
140  for (T_COROUTINE** p = T_COROUTINE::getRoot();
-
141  (*p) != nullptr;
-
142  p = (*p)->getNext()) {
-
143 
-
144  (*p)->setupCoroutine();
-
145  }
-
146  }
-
147 
-
149  void runCoroutine() {
-
150  // If reached the end, start from the beginning again.
-
151  if (*mCurrent == nullptr) {
-
152  mCurrent = T_COROUTINE::getRoot();
-
153  // Return if the list is empty. Checking for a null getRoot() inside the
-
154  // if-statement is deliberate, since it optimizes the common case where
-
155  // the linked list is not empty.
-
156  if (*mCurrent == nullptr) {
-
157  return;
-
158  }
-
159  }
-
160 
-
161  #if ACE_ROUTINE_DEBUG == 1
-
162  Serial.print(F("Processing "));
-
163  Serial.print((uintptr_t) (*mCurrent));
-
164  Serial.println();
-
165  #endif
-
166 
-
167  // Handle the coroutine's dispatch back to the last known internal status.
-
168  switch ((*mCurrent)->getStatus()) {
-
169  case T_COROUTINE::kStatusYielding:
-
170  case T_COROUTINE::kStatusDelaying:
-
171  // The coroutine itself knows whether it is yielding or delaying, and
-
172  // its continuation context determines whether to call
-
173  // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or
-
174  // Coroutine::isDelaySecondsExpired().
-
175  (*mCurrent)->runCoroutine();
-
176  break;
-
177 
-
178  case T_COROUTINE::kStatusEnding:
-
179  // mark it terminated
-
180  (*mCurrent)->setTerminated();
-
181  break;
-
182 
-
183  default:
-
184  // For all other cases, just skip to the next coroutine.
-
185  break;
-
186  }
-
187 
-
188  // Go to the next coroutine
-
189  mCurrent = (*mCurrent)->getNext();
-
190  }
-
191 
-
192 
-
194  void listCoroutines(Print& printer) {
-
195  for (T_COROUTINE** p = T_COROUTINE::getRoot(); (*p) != nullptr;
-
196  p = (*p)->getNext()) {
-
197  printer.print(F("Coroutine "));
-
198  printer.print((uintptr_t) *p);
-
199  printer.print(F("; status: "));
-
200  (*p)->statusPrintTo(printer);
-
201  printer.println();
-
202  }
-
203  }
-
204 
-
205  // The current coroutine is represented by a pointer to a pointer. This
-
206  // allows the root node to be treated the same as all the other nodes, and
-
207  // simplifies the code that traverses the singly-linked list.
-
208  T_COROUTINE** mCurrent = nullptr;
-
209 };
-
210 
-
211 using CoroutineScheduler = CoroutineSchedulerTemplate<Coroutine>;
-
212 
-
213 }
-
214 
-
215 #endif
+
32 #include "CoroutineProfiler.h"
+
33 
+
34 class Print;
+
35 
+
36 namespace ace_routine {
+
37 
+
81 template <typename T_COROUTINE>
+
82 class CoroutineSchedulerTemplate {
+
83  public:
+
85  static void setup() { getScheduler()->setupScheduler(); }
+
86 
+
88  static void setupCoroutines() {
+
89  getScheduler()->setupCoroutinesInternal();
+
90  }
+
91 
+
98  static void loop() { getScheduler()->runCoroutine(); }
+
99 
+
106  static void loopWithProfiler() {
+
107  getScheduler()->runCoroutineWithProfiler();
+
108  }
+
109 
+
116  static void list(Print& printer) {
+
117  getScheduler()->listCoroutines(printer);
+
118  }
+
119 
+
120  private:
+
121  // Disable copy-constructor and assignment operator
+ + +
124  delete;
+
125 
+
127  static CoroutineSchedulerTemplate* getScheduler() {
+
128  static CoroutineSchedulerTemplate singletonScheduler;
+
129  return &singletonScheduler;
+
130  }
+
131 
+
133  CoroutineSchedulerTemplate() = default;
+
134 
+
145  void setupScheduler() {
+
146  mCurrent = T_COROUTINE::getRoot();
+
147  }
+
148 
+
150  void setupCoroutinesInternal() {
+
151  for (T_COROUTINE** p = T_COROUTINE::getRoot();
+
152  (*p) != nullptr;
+
153  p = (*p)->getNext()) {
+
154 
+
155  (*p)->setupCoroutine();
+
156  }
+
157  }
+
158 
+
163  void runCoroutine() {
+
164  // If reached the end, start from the beginning again.
+
165  if (*mCurrent == nullptr) {
+
166  mCurrent = T_COROUTINE::getRoot();
+
167  // Return if the list is empty. Checking for a null getRoot() inside the
+
168  // if-statement is deliberate, since it optimizes the common case where
+
169  // the linked list is not empty.
+
170  if (*mCurrent == nullptr) {
+
171  return;
+
172  }
+
173  }
+
174 
+
175  // Handle the coroutine's dispatch back to the last known internal status.
+
176  switch ((*mCurrent)->getStatus()) {
+
177  case T_COROUTINE::kStatusYielding:
+
178  case T_COROUTINE::kStatusDelaying:
+
179  // The coroutine itself knows whether it is yielding or delaying, and
+
180  // its continuation context determines whether to call
+
181  // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or
+
182  // Coroutine::isDelaySecondsExpired().
+
183  (*mCurrent)->runCoroutine();
+
184  break;
+
185 
+
186  case T_COROUTINE::kStatusEnding:
+
187  // mark it terminated
+
188  (*mCurrent)->setTerminated();
+
189  break;
+
190 
+
191  default:
+
192  // For all other cases, just skip to the next coroutine.
+
193  break;
+
194  }
+
195 
+
196  // Go to the next coroutine
+
197  mCurrent = (*mCurrent)->getNext();
+
198  }
+
199 
+
200  /*
+
201  * Run the current coroutine with profiling enabled by calling
+
202  * Coroutine::runCoroutineWithProfiler().
+
203  */
+
204  void runCoroutineWithProfiler() {
+
205  // If reached the end, start from the beginning again.
+
206  if (*mCurrent == nullptr) {
+
207  mCurrent = T_COROUTINE::getRoot();
+
208  // Return if the list is empty. Checking for a null getRoot() inside the
+
209  // if-statement is deliberate, since it optimizes the common case where
+
210  // the linked list is not empty.
+
211  if (*mCurrent == nullptr) {
+
212  return;
+
213  }
+
214  }
+
215 
+
216  // Handle the coroutine's dispatch back to the last known internal status.
+
217  switch ((*mCurrent)->getStatus()) {
+
218  case T_COROUTINE::kStatusYielding:
+
219  case T_COROUTINE::kStatusDelaying:
+
220  // The coroutine itself knows whether it is yielding or delaying, and
+
221  // its continuation context determines whether to call
+
222  // Coroutine::isDelayExpired(), Coroutine::isDelayMicrosExpired(), or
+
223  // Coroutine::isDelaySecondsExpired().
+
224  //
+
225  // This version calls `Coroutine::runCoroutineWithProfiler()` to
+
226  // enable the profiler.
+
227  (*mCurrent)->runCoroutineWithProfiler();
+
228  break;
+
229 
+
230  case T_COROUTINE::kStatusEnding:
+
231  // mark it terminated
+
232  (*mCurrent)->setTerminated();
+
233  break;
+
234 
+
235  default:
+
236  // For all other cases, just skip to the next coroutine.
+
237  break;
+
238  }
+
239 
+
240  // Go to the next coroutine
+
241  mCurrent = (*mCurrent)->getNext();
+
242  }
+
243 
+
245  void listCoroutines(Print& printer) {
+
246  for (T_COROUTINE** p = T_COROUTINE::getRoot(); (*p) != nullptr;
+
247  p = (*p)->getNext()) {
+
248  printer.print(F("Coroutine "));
+
249  (*p)->printNameTo(printer);
+
250  printer.print(F("; status: "));
+
251  (*p)->statusPrintTo(printer);
+
252  printer.println();
+
253  }
+
254  }
+
255 
+
256  // The current coroutine is represented by a pointer to a pointer. This
+
257  // allows the root node to be treated the same as all the other nodes, and
+
258  // simplifies the code that traverses the singly-linked list.
+
259  T_COROUTINE** mCurrent = nullptr;
+
260 };
+
261 
+
262 using CoroutineScheduler = CoroutineSchedulerTemplate<Coroutine>;
+
263 
+
264 }
+
265 
+
266 #endif
-
static void loop()
Run the current coroutine using the current scheduler.
-
static void setupCoroutines()
Set up the coroutines by calling their setupCoroutine() methods.
-
static void setup()
Set up the scheduler.
-
static void list(Print &printer)
Print out the known coroutines to the printer (usually Serial).
-
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion.
Definition: Coroutine.h:270
+
static void loop()
Run the current coroutine using the current scheduler.
+
static void setupCoroutines()
Set up the coroutines by calling their setupCoroutine() methods.
+
static void loopWithProfiler()
Run the current coroutine using the current scheduler with the coroutine profiler enabled.
+
static void setup()
Set up the scheduler.
+
static void list(Print &printer)
Print out the known coroutines to the printer (usually Serial).
+
Class that manages instances of the Coroutine class, and executes them in a round-robin fashion.
Definition: Coroutine.h:274