From 733d050023d2b7d5219223f0e3ab99294f23d896 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Sat, 30 Mar 2024 19:24:28 -0700 Subject: [PATCH 01/12] basic PI lag controller --- core/threaded/reactor_threaded.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index e364675d6..d8d1bb147 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -222,6 +222,8 @@ void lf_set_present(lf_port_base_t* port) { */ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time); + static interval_t ave_lag = NSEC(0); + static int64_t lag_count = 0; interval_t wait_until_time = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized // Apply the STA to the logical time @@ -242,12 +244,20 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { return true; } + //Subtract the average lag from the requested wait_until_time + interval_t wait_until_time_with_lag = wait_until_time - ave_lag; + instant_t now = lf_time_physical(); + if (wait_until_time_with_lag < now && wait_until_time > now) { + while (wait_until_time > lf_time_physical()){} + return true; + } + // We do the sleep on the cond var so we can be awakened by the // asynchronous scheduling of a physical action. lf_clock_cond_timedwait // returns 0 if it is awakened before the timeout. Hence, we want to run // it repeatedly until either it returns non-zero or the current // physical time matches or exceeds the logical time. - if (lf_clock_cond_timedwait(condition, wait_until_time) != LF_TIMEOUT) { + if (lf_clock_cond_timedwait(condition, wait_until_time_with_lag) != LF_TIMEOUT) { LF_PRINT_DEBUG("-------- wait_until interrupted before timeout."); // Wait did not time out, which means that there @@ -260,7 +270,20 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { } else { // Reached timeout. LF_PRINT_DEBUG("-------- Returned from wait, having waited " PRINTF_TIME " ns.", wait_duration); - return true; + + //Calculate the lag and update the average + interval_t lag = lf_time_physical() - wait_until_time_with_lag; + lag = lag - ave_lag; + lag_count++; + lag = lag / lag_count; + ave_lag += lag; + + //Check if the wait amount was sufficient + if (lf_time_physical() > wait_until_time) { + return true; + } else { + return wait_until(logical_time, condition); + } } } return true; From b5fb4f8238f968284393c09faef0eedaba814f56 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Sun, 31 Mar 2024 21:17:18 -0700 Subject: [PATCH 02/12] return on negative wait_duration --- core/threaded/reactor_threaded.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index d8d1bb147..cbc40f0ff 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -238,16 +238,18 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { if (!fast) { // Check whether we actually need to wait, or if we have already passed the timepoint. interval_t wait_duration = wait_until_time - lf_time_physical(); - if (wait_duration < MIN_SLEEP_DURATION) { - LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION " PRINTF_TIME ". Skipping wait.", - wait_duration, MIN_SLEEP_DURATION); - return true; - } + // if (wait_duration < MIN_SLEEP_DURATION) { + // LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION " PRINTF_TIME ". Skipping wait.", + // wait_duration, MIN_SLEEP_DURATION); + // return true; + // } //Subtract the average lag from the requested wait_until_time interval_t wait_until_time_with_lag = wait_until_time - ave_lag; instant_t now = lf_time_physical(); - if (wait_until_time_with_lag < now && wait_until_time > now) { + if (wait_until_time < now) { + return true; + } else if (wait_until_time_with_lag < now && wait_until_time > now) { while (wait_until_time > lf_time_physical()){} return true; } From cd26b62977d912f1d8bc9c73e317f5a35da616d6 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Mon, 1 Apr 2024 14:22:50 -0700 Subject: [PATCH 03/12] PI controller draft --- core/threaded/reactor_threaded.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index cbc40f0ff..9ff5e1d20 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -42,6 +42,9 @@ extern instant_t start_time; */ #define MAX_STALL_INTERVAL MSEC(1) +#define LAG_CONTROL_KP 0.5 +#define LAG_CONTROL_KI 0.01 + /** * Global mutex, used for synchronizing across environments. Mainly used for token-management and tracing */ @@ -222,8 +225,8 @@ void lf_set_present(lf_port_base_t* port) { */ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time); - static interval_t ave_lag = NSEC(0); - static int64_t lag_count = 0; + static interval_t error_integral = NSEC(0); + static interval_t last_lag = NSEC(0); interval_t wait_until_time = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized // Apply the STA to the logical time @@ -245,11 +248,11 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { // } //Subtract the average lag from the requested wait_until_time - interval_t wait_until_time_with_lag = wait_until_time - ave_lag; + interval_t wait_until_time_with_adjustment = wait_until_time - (LAG_CONTROL_KP * last_lag + LAG_CONTROL_KI * error_integral); instant_t now = lf_time_physical(); if (wait_until_time < now) { return true; - } else if (wait_until_time_with_lag < now && wait_until_time > now) { + } else if (wait_until_time_with_adjustment < now && wait_until_time > now) { while (wait_until_time > lf_time_physical()){} return true; } @@ -259,7 +262,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { // returns 0 if it is awakened before the timeout. Hence, we want to run // it repeatedly until either it returns non-zero or the current // physical time matches or exceeds the logical time. - if (lf_clock_cond_timedwait(condition, wait_until_time_with_lag) != LF_TIMEOUT) { + if (lf_clock_cond_timedwait(condition, wait_until_time_with_adjustment) != LF_TIMEOUT) { LF_PRINT_DEBUG("-------- wait_until interrupted before timeout."); // Wait did not time out, which means that there @@ -274,11 +277,12 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Returned from wait, having waited " PRINTF_TIME " ns.", wait_duration); //Calculate the lag and update the average - interval_t lag = lf_time_physical() - wait_until_time_with_lag; - lag = lag - ave_lag; - lag_count++; - lag = lag / lag_count; - ave_lag += lag; + last_lag = lf_time_physical() - wait_until_time_with_adjustment; + error_integral += last_lag; + // lag = lag - ave_lag; + // lag_count++; + // lag = lag / lag_count; + // ave_lag += lag; //Check if the wait amount was sufficient if (lf_time_physical() > wait_until_time) { From d1f6167d0a848f7e26563e29fa1afec771dd8308 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Sat, 6 Apr 2024 19:12:22 -0700 Subject: [PATCH 04/12] updated controller --- core/threaded/reactor_threaded.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 9ff5e1d20..14a416e32 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -42,8 +42,7 @@ extern instant_t start_time; */ #define MAX_STALL_INTERVAL MSEC(1) -#define LAG_CONTROL_KP 0.5 -#define LAG_CONTROL_KI 0.01 +#define LAG_CONTROL 0.5 /** * Global mutex, used for synchronizing across environments. Mainly used for token-management and tracing @@ -225,8 +224,7 @@ void lf_set_present(lf_port_base_t* port) { */ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time); - static interval_t error_integral = NSEC(0); - static interval_t last_lag = NSEC(0); + static interval_t error_control = NSEC(0); interval_t wait_until_time = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized // Apply the STA to the logical time @@ -248,7 +246,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { // } //Subtract the average lag from the requested wait_until_time - interval_t wait_until_time_with_adjustment = wait_until_time - (LAG_CONTROL_KP * last_lag + LAG_CONTROL_KI * error_integral); + interval_t wait_until_time_with_adjustment = wait_until_time - (LAG_CONTROL * error_control); instant_t now = lf_time_physical(); if (wait_until_time < now) { return true; @@ -277,8 +275,8 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Returned from wait, having waited " PRINTF_TIME " ns.", wait_duration); //Calculate the lag and update the average - last_lag = lf_time_physical() - wait_until_time_with_adjustment; - error_integral += last_lag; + instant_t lag = lf_time_physical() - wait_until_time; + error_control += lag; // lag = lag - ave_lag; // lag_count++; // lag = lag / lag_count; @@ -288,7 +286,8 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { if (lf_time_physical() > wait_until_time) { return true; } else { - return wait_until(logical_time, condition); + while (wait_until_time > lf_time_physical()){} + return true; } } } From 03b23868b699f3c1d82d0becc536540651488999 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Mon, 8 Apr 2024 16:03:45 -0700 Subject: [PATCH 05/12] updated control algorithm --- core/threaded/reactor_threaded.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 14a416e32..e00b84c34 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -246,11 +246,12 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { // } //Subtract the average lag from the requested wait_until_time - interval_t wait_until_time_with_adjustment = wait_until_time - (LAG_CONTROL * error_control); + interval_t wait_until_time_with_adjustment = wait_until_time - error_control; instant_t now = lf_time_physical(); if (wait_until_time < now) { return true; } else if (wait_until_time_with_adjustment < now && wait_until_time > now) { + error_control = error_control - (LAG_CONTROL * (now - wait_until_time_with_adjustment)); while (wait_until_time > lf_time_physical()){} return true; } @@ -276,7 +277,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { //Calculate the lag and update the average instant_t lag = lf_time_physical() - wait_until_time; - error_control += lag; + error_control += LAG_CONTROL * lag; // lag = lag - ave_lag; // lag_count++; // lag = lag / lag_count; From a89636ca3b50f23a7aba8bbec35dd0f8db0e70b2 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Mon, 8 Apr 2024 21:47:21 -0700 Subject: [PATCH 06/12] make constant non-float --- core/threaded/reactor_threaded.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index e00b84c34..0c3ec28e9 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -42,7 +42,7 @@ extern instant_t start_time; */ #define MAX_STALL_INTERVAL MSEC(1) -#define LAG_CONTROL 0.5 +#define LAG_CONTROL_DIV 2 /** * Global mutex, used for synchronizing across environments. Mainly used for token-management and tracing @@ -251,7 +251,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { if (wait_until_time < now) { return true; } else if (wait_until_time_with_adjustment < now && wait_until_time > now) { - error_control = error_control - (LAG_CONTROL * (now - wait_until_time_with_adjustment)); + error_control = error_control - ((now - wait_until_time_with_adjustment) / LAG_CONTROL_DIV); while (wait_until_time > lf_time_physical()){} return true; } @@ -277,7 +277,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { //Calculate the lag and update the average instant_t lag = lf_time_physical() - wait_until_time; - error_control += LAG_CONTROL * lag; + error_control = error_control + (lag / LAG_CONTROL_DIV); // lag = lag - ave_lag; // lag_count++; // lag = lag / lag_count; From d6be76f010a349e91b7e1e51d541cf6dee21023a Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Sat, 13 Apr 2024 18:21:46 -0700 Subject: [PATCH 07/12] fixed the i-constant --- core/threaded/reactor_threaded.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 0c3ec28e9..050784e95 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -42,7 +42,8 @@ extern instant_t start_time; */ #define MAX_STALL_INTERVAL MSEC(1) -#define LAG_CONTROL_DIV 2 +#define KI_DIV 2 +#define KI_MUL 3 /** * Global mutex, used for synchronizing across environments. Mainly used for token-management and tracing @@ -251,7 +252,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { if (wait_until_time < now) { return true; } else if (wait_until_time_with_adjustment < now && wait_until_time > now) { - error_control = error_control - ((now - wait_until_time_with_adjustment) / LAG_CONTROL_DIV); + error_control = error_control - (((now - wait_until_time_with_adjustment) * KI_MUL) / KI_DIV); while (wait_until_time > lf_time_physical()){} return true; } @@ -277,7 +278,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { //Calculate the lag and update the average instant_t lag = lf_time_physical() - wait_until_time; - error_control = error_control + (lag / LAG_CONTROL_DIV); + error_control = error_control + ((lag * KI_MUL) / KI_DIV); // lag = lag - ave_lag; // lag_count++; // lag = lag / lag_count; From 11d9df021dbd43f01b8ef2d30645212408a3a20e Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Tue, 23 Apr 2024 10:57:20 -0700 Subject: [PATCH 08/12] make lag control constants a target property --- core/threaded/reactor_threaded.c | 3 --- low_level_platform/api/platform/lf_arduino_support.h | 3 +++ low_level_platform/api/platform/lf_linux_support.h | 3 +++ low_level_platform/api/platform/lf_macos_support.h | 3 +++ low_level_platform/api/platform/lf_nrf52_support.h | 3 +++ low_level_platform/api/platform/lf_rp2040_support.h | 3 +++ low_level_platform/api/platform/lf_windows_support.h | 3 +++ low_level_platform/api/platform/lf_zephyr_support.h | 3 +++ 8 files changed, 21 insertions(+), 3 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 050784e95..0c81f6a94 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -42,9 +42,6 @@ extern instant_t start_time; */ #define MAX_STALL_INTERVAL MSEC(1) -#define KI_DIV 2 -#define KI_MUL 3 - /** * Global mutex, used for synchronizing across environments. Mainly used for token-management and tracing */ diff --git a/low_level_platform/api/platform/lf_arduino_support.h b/low_level_platform/api/platform/lf_arduino_support.h index 94c5d4933..de5902567 100644 --- a/low_level_platform/api/platform/lf_arduino_support.h +++ b/low_level_platform/api/platform/lf_arduino_support.h @@ -132,4 +132,7 @@ typedef void* lf_thread_t; // Arduinos are embedded platforms with no tty #define NO_TTY +#define KI_DIV 1 +#define KI_MUL 1 + #endif // LF_ARDUINO_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_linux_support.h b/low_level_platform/api/platform/lf_linux_support.h index 18f68b2aa..9d4ecc25f 100644 --- a/low_level_platform/api/platform/lf_linux_support.h +++ b/low_level_platform/api/platform/lf_linux_support.h @@ -52,4 +52,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error Linux platform misses clock support #endif +#define KI_DIV 2 +#define KI_MUL 3 + #endif // LF_LINUX_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_macos_support.h b/low_level_platform/api/platform/lf_macos_support.h index 357729f08..a8e8192fe 100644 --- a/low_level_platform/api/platform/lf_macos_support.h +++ b/low_level_platform/api/platform/lf_macos_support.h @@ -44,6 +44,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #else #include "lf_C11_threads_support.h" #endif +#define KI_DIV 1 +#define KI_MUL 1 + #endif #endif // LF_MACOS_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_nrf52_support.h b/low_level_platform/api/platform/lf_nrf52_support.h index 18613b2e0..7b0520fe3 100644 --- a/low_level_platform/api/platform/lf_nrf52_support.h +++ b/low_level_platform/api/platform/lf_nrf52_support.h @@ -51,4 +51,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef void* lf_mutex_t; typedef void _lf_cond_var_t; +#define KI_DIV 1 +#define KI_MUL 1 + #endif // LF_nRF52832_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index 1b23e3a2e..ea25a6030 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -20,4 +20,7 @@ #define LF_TIME_BUFFER_LENGTH 80 #define _LF_TIMEOUT 1 +#define KI_DIV 1 +#define KI_MUL 1 + #endif // LF_PICO_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_windows_support.h b/low_level_platform/api/platform/lf_windows_support.h index ea6ccffb5..c782b5c6d 100644 --- a/low_level_platform/api/platform/lf_windows_support.h +++ b/low_level_platform/api/platform/lf_windows_support.h @@ -61,6 +61,9 @@ typedef struct { CONDITION_VARIABLE condition; } lf_cond_t; typedef HANDLE lf_thread_t; + +#define KI_DIV 1 +#define KI_MUL 1 #endif // Use 64-bit times and 32-bit unsigned microsteps diff --git a/low_level_platform/api/platform/lf_zephyr_support.h b/low_level_platform/api/platform/lf_zephyr_support.h index 49172eb21..66e8f88cc 100644 --- a/low_level_platform/api/platform/lf_zephyr_support.h +++ b/low_level_platform/api/platform/lf_zephyr_support.h @@ -49,6 +49,9 @@ typedef struct { } lf_cond_t; typedef struct k_thread* lf_thread_t; +#define KI_DIV 1 +#define KI_MUL 1 + /** * @brief Add `value` to `*ptr` and return original value of `*ptr` */ From 0e05e9cfcca7dca5583364c9eac783564d84e064 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Tue, 23 Apr 2024 14:35:21 -0700 Subject: [PATCH 09/12] comments + format check --- core/threaded/reactor_threaded.c | 36 +++++++++---------- .../api/platform/lf_arduino_support.h | 7 ++-- .../api/platform/lf_linux_support.h | 4 ++- .../api/platform/lf_macos_support.h | 8 +++-- .../api/platform/lf_nrf52_support.h | 7 ++-- .../api/platform/lf_rp2040_support.h | 7 ++-- .../api/platform/lf_windows_support.h | 7 ++-- .../api/platform/lf_zephyr_support.h | 7 ++-- 8 files changed, 50 insertions(+), 33 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 0c81f6a94..54d166dd5 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -197,7 +197,8 @@ void lf_set_present(lf_port_base_t* port) { /** * Wait until physical time matches or exceeds the specified logical time, * unless -fast is given. For decentralized coordination, this function will - * add the STA offset to the wait time. + * add the STA offset to the wait time. For lag control, this function will implement + * an I-controller to regulate the lag introduced by the underlying sleep function. * * If an event is put on the event queue during the wait, then the wait is * interrupted and this function returns false. It also returns false if the @@ -222,6 +223,7 @@ void lf_set_present(lf_port_base_t* port) { */ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time); + // Control value for the i-controller static interval_t error_control = NSEC(0); interval_t wait_until_time = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized @@ -235,22 +237,19 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { } #endif if (!fast) { - // Check whether we actually need to wait, or if we have already passed the timepoint. - interval_t wait_duration = wait_until_time - lf_time_physical(); - // if (wait_duration < MIN_SLEEP_DURATION) { - // LF_PRINT_DEBUG("Wait time " PRINTF_TIME " is less than MIN_SLEEP_DURATION " PRINTF_TIME ". Skipping wait.", - // wait_duration, MIN_SLEEP_DURATION); - // return true; - // } - - //Subtract the average lag from the requested wait_until_time + // Subtract the control value from the requested wait_until_time interval_t wait_until_time_with_adjustment = wait_until_time - error_control; instant_t now = lf_time_physical(); + + // If the requested time is already passed, return + // If the adjusted wait time is already passed, but the requested wait time + // didn't come yet, then adjust the control value and busy wait until the requested time. if (wait_until_time < now) { return true; } else if (wait_until_time_with_adjustment < now && wait_until_time > now) { error_control = error_control - (((now - wait_until_time_with_adjustment) * KI_MUL) / KI_DIV); - while (wait_until_time > lf_time_physical()){} + while (wait_until_time > lf_time_physical()) + ; return true; } @@ -271,21 +270,18 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { return false; } else { // Reached timeout. - LF_PRINT_DEBUG("-------- Returned from wait, having waited " PRINTF_TIME " ns.", wait_duration); - - //Calculate the lag and update the average + LF_PRINT_DEBUG("-------- Returned from wait, having waited until " PRINTF_TIME " ns.", wait_until_time); + + // Calculate the lag and update the control value instant_t lag = lf_time_physical() - wait_until_time; error_control = error_control + ((lag * KI_MUL) / KI_DIV); - // lag = lag - ave_lag; - // lag_count++; - // lag = lag / lag_count; - // ave_lag += lag; - //Check if the wait amount was sufficient + // Check if the requested time is passed, if not busy wait if (lf_time_physical() > wait_until_time) { return true; } else { - while (wait_until_time > lf_time_physical()){} + while (wait_until_time > lf_time_physical()) + ; return true; } } diff --git a/low_level_platform/api/platform/lf_arduino_support.h b/low_level_platform/api/platform/lf_arduino_support.h index de5902567..0d67d271b 100644 --- a/low_level_platform/api/platform/lf_arduino_support.h +++ b/low_level_platform/api/platform/lf_arduino_support.h @@ -132,7 +132,10 @@ typedef void* lf_thread_t; // Arduinos are embedded platforms with no tty #define NO_TTY -#define KI_DIV 1 -#define KI_MUL 1 +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. +Currently no lag control support in this platform. */ +#define KI_DIV 1 +#define KI_MUL 0 #endif // LF_ARDUINO_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_linux_support.h b/low_level_platform/api/platform/lf_linux_support.h index 9d4ecc25f..6d588513f 100644 --- a/low_level_platform/api/platform/lf_linux_support.h +++ b/low_level_platform/api/platform/lf_linux_support.h @@ -52,7 +52,9 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #error Linux platform misses clock support #endif -#define KI_DIV 2 +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. */ +#define KI_DIV 2 #define KI_MUL 3 #endif // LF_LINUX_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_macos_support.h b/low_level_platform/api/platform/lf_macos_support.h index a8e8192fe..904ea5313 100644 --- a/low_level_platform/api/platform/lf_macos_support.h +++ b/low_level_platform/api/platform/lf_macos_support.h @@ -44,8 +44,12 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #else #include "lf_C11_threads_support.h" #endif -#define KI_DIV 1 -#define KI_MUL 1 + +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. +Currently no lag control support in this platform. */ +#define KI_DIV 1 +#define KI_MUL 0 #endif diff --git a/low_level_platform/api/platform/lf_nrf52_support.h b/low_level_platform/api/platform/lf_nrf52_support.h index 7b0520fe3..e5a01660d 100644 --- a/low_level_platform/api/platform/lf_nrf52_support.h +++ b/low_level_platform/api/platform/lf_nrf52_support.h @@ -51,7 +51,10 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef void* lf_mutex_t; typedef void _lf_cond_var_t; -#define KI_DIV 1 -#define KI_MUL 1 +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. +Currently no lag control support in this platform. */ +#define KI_DIV 1 +#define KI_MUL 0 #endif // LF_nRF52832_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_rp2040_support.h b/low_level_platform/api/platform/lf_rp2040_support.h index ea25a6030..7796ec80f 100644 --- a/low_level_platform/api/platform/lf_rp2040_support.h +++ b/low_level_platform/api/platform/lf_rp2040_support.h @@ -20,7 +20,10 @@ #define LF_TIME_BUFFER_LENGTH 80 #define _LF_TIMEOUT 1 -#define KI_DIV 1 -#define KI_MUL 1 +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. +Currently no lag control support in this platform. */ +#define KI_DIV 1 +#define KI_MUL 0 #endif // LF_PICO_SUPPORT_H diff --git a/low_level_platform/api/platform/lf_windows_support.h b/low_level_platform/api/platform/lf_windows_support.h index c782b5c6d..4da73e3de 100644 --- a/low_level_platform/api/platform/lf_windows_support.h +++ b/low_level_platform/api/platform/lf_windows_support.h @@ -62,8 +62,11 @@ typedef struct { } lf_cond_t; typedef HANDLE lf_thread_t; -#define KI_DIV 1 -#define KI_MUL 1 +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. +Currently no lag control support in this platform. */ +#define KI_DIV 1 +#define KI_MUL 0 #endif // Use 64-bit times and 32-bit unsigned microsteps diff --git a/low_level_platform/api/platform/lf_zephyr_support.h b/low_level_platform/api/platform/lf_zephyr_support.h index 66e8f88cc..fd679ec05 100644 --- a/low_level_platform/api/platform/lf_zephyr_support.h +++ b/low_level_platform/api/platform/lf_zephyr_support.h @@ -49,8 +49,11 @@ typedef struct { } lf_cond_t; typedef struct k_thread* lf_thread_t; -#define KI_DIV 1 -#define KI_MUL 1 +/* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. +The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. +Currently no lag control support in this platform. */ +#define KI_DIV 1 +#define KI_MUL 0 /** * @brief Add `value` to `*ptr` and return original value of `*ptr` From 01a7f70b48eca8c80a4380b81c28e11c07503375 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Tue, 30 Apr 2024 10:57:33 -0700 Subject: [PATCH 10/12] min bounded the error_control --- core/threaded/reactor_threaded.c | 3 +++ low_level_platform/api/platform/lf_linux_support.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index 2509ef5c3..a2064684b 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -237,6 +237,9 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { } #endif if (!fast) { + if (error_control < NSEC(0)) { + error_control = NSEC(0); + } // Subtract the control value from the requested wait_until_time interval_t wait_until_time_with_adjustment = wait_until_time - error_control; instant_t now = lf_time_physical(); diff --git a/low_level_platform/api/platform/lf_linux_support.h b/low_level_platform/api/platform/lf_linux_support.h index e5cd40b77..6a6c1e58b 100644 --- a/low_level_platform/api/platform/lf_linux_support.h +++ b/low_level_platform/api/platform/lf_linux_support.h @@ -49,7 +49,7 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* The constants used for I-controller for lag regulation under reactor_threaded.c wait_until function. The lag gets multiplied by KI_MUL and divided by KI_DIV before incorporated into control value. */ -#define KI_DIV 2 -#define KI_MUL 3 +#define KI_DIV 1 +#define KI_MUL 1 #endif // LF_LINUX_SUPPORT_H From 9a4767e977d5ab3dbc2c411cf5d2746b9a1421a6 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Sat, 4 May 2024 14:22:41 -0700 Subject: [PATCH 11/12] do not incorporate outlier lags --- core/reactor_common.c | 7 +++++++ core/threaded/reactor_threaded.c | 13 ++++++++----- include/core/reactor_common.h | 1 + 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 33e5582f5..343401127 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -87,6 +87,9 @@ instant_t duration = -1LL; /** Indicator of whether the keepalive command-line option was given. */ bool keepalive_specified = false; +/** The minimum period of triggered timers, used as an upperbound on the lag for wait_until */ +instant_t _min_timer_period = FOREVER; + void* lf_allocate(size_t count, size_t size, struct allocation_record_t** head) { void* mem = calloc(count, size); if (mem == NULL) @@ -306,6 +309,10 @@ void _lf_pop_events(environment_t* env) { // If the trigger is a periodic timer, create a new event for its next execution. if (event->trigger->is_timer && event->trigger->period > 0LL) { + // Update the min timer + if (_min_timer_period > event->trigger->period) { + _min_timer_period = event->trigger->period; + } // Reschedule the trigger. lf_schedule_trigger(env, event->trigger, event->trigger->period, NULL); } diff --git a/core/threaded/reactor_threaded.c b/core/threaded/reactor_threaded.c index a2064684b..a1f9e0cf1 100644 --- a/core/threaded/reactor_threaded.c +++ b/core/threaded/reactor_threaded.c @@ -225,6 +225,8 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { LF_PRINT_DEBUG("-------- Waiting until physical time matches logical time " PRINTF_TIME, logical_time); // Control value for the i-controller static interval_t error_control = NSEC(0); + // Do not incorporate the first lag measurement. It's an outlier due to initilizations + static int flag = false; interval_t wait_until_time = logical_time; #ifdef FEDERATED_DECENTRALIZED // Only apply the STA if coordination is decentralized // Apply the STA to the logical time @@ -237,9 +239,7 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { } #endif if (!fast) { - if (error_control < NSEC(0)) { - error_control = NSEC(0); - } + error_control = LF_MAX(error_control, NSEC(0)); // Subtract the control value from the requested wait_until_time interval_t wait_until_time_with_adjustment = wait_until_time - error_control; instant_t now = lf_time_physical(); @@ -250,7 +250,6 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { if (wait_until_time < now) { return true; } else if (wait_until_time_with_adjustment < now && wait_until_time > now) { - error_control = error_control - (((now - wait_until_time_with_adjustment) * KI_MUL) / KI_DIV); while (wait_until_time > lf_time_physical()) ; return true; @@ -277,7 +276,11 @@ bool wait_until(instant_t logical_time, lf_cond_t* condition) { // Calculate the lag and update the control value instant_t lag = lf_time_physical() - wait_until_time; - error_control = error_control + ((lag * KI_MUL) / KI_DIV); + if (flag && lag <= _min_timer_period) { + error_control = error_control + ((lag * KI_MUL) / KI_DIV); + } else { + flag = true; + } // Check if the requested time is passed, if not busy wait if (lf_time_physical() > wait_until_time) { diff --git a/include/core/reactor_common.h b/include/core/reactor_common.h index 8086ed7db..98a8f5093 100644 --- a/include/core/reactor_common.h +++ b/include/core/reactor_common.h @@ -55,6 +55,7 @@ extern const char** default_argv; extern instant_t duration; extern bool fast; extern bool keepalive_specified; +extern instant_t _min_timer_period; #ifdef FEDERATED_DECENTRALIZED extern interval_t lf_fed_STA_offset; From c96329b163bc9904452b99950ad71d8a52451db4 Mon Sep 17 00:00:00 2001 From: Efsane Soyer Date: Sat, 4 May 2024 14:24:43 -0700 Subject: [PATCH 12/12] fix format --- core/reactor_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/reactor_common.c b/core/reactor_common.c index 343401127..1fcb0b421 100644 --- a/core/reactor_common.c +++ b/core/reactor_common.c @@ -88,7 +88,7 @@ instant_t duration = -1LL; bool keepalive_specified = false; /** The minimum period of triggered timers, used as an upperbound on the lag for wait_until */ -instant_t _min_timer_period = FOREVER; +instant_t _min_timer_period = FOREVER; void* lf_allocate(size_t count, size_t size, struct allocation_record_t** head) { void* mem = calloc(count, size); @@ -309,10 +309,10 @@ void _lf_pop_events(environment_t* env) { // If the trigger is a periodic timer, create a new event for its next execution. if (event->trigger->is_timer && event->trigger->period > 0LL) { - // Update the min timer + // Update the min timer if (_min_timer_period > event->trigger->period) { _min_timer_period = event->trigger->period; - } + } // Reschedule the trigger. lf_schedule_trigger(env, event->trigger, event->trigger->period, NULL); }