From ecc148bde636b804f22bd008db873572d021a5eb Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 16 Apr 2026 18:59:04 +0200 Subject: [PATCH 1/7] implement an array of the last 2^n task times --- Inc/HALAL/Services/Time/Scheduler.hpp | 10 ++++++++ Src/HALAL/Services/Time/Scheduler.cpp | 37 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index ceb16e198..40741238f 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -27,6 +27,16 @@ #include "stm32h7xx_hal_tim.h" #endif +//#define SLOW_CHECK_USE_READY_BITMAP +#define SLOW_CHECK_USE_LAST_N_TASKS + +#define SLOW_CHECK_USE_LAST_N_TASKS_COUNT 512 + +#if defined(SLOW_CHECK_USE_LAST_N_TASKS) +// Must be a 32 bit timer and not be the same as the scheduler timer +extern TIM_TypeDef* perf_timer; +#endif + extern TIM_TypeDef* Scheduler_global_timer; void Scheduler_global_timer_callback(void* raw); void Scheduler_start(void); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ac215b4b4..32f1b8bf5 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -31,8 +31,30 @@ uint64_t Scheduler::global_tick_us_{0}; uint32_t Scheduler::current_interval_us_{0}; uint16_t Scheduler::timeout_idx_{1}; +#if (SLOW_CHECK_USE_LAST_N_TASKS_COUNT & (SLOW_CHECK_USE_LAST_N_TASKS_COUNT - 1)) != 0 +// NOTE: Performance: this is to use an and instead of a mod when storing the data +#error SLOW_CHECK_USE_LAST_N_TASKS_COUNT must be a power of 2 +#endif + +#if defined(SLOW_CHECK_USE_READY_BITMAP) uint16_t failing_id = Scheduler::INVALID_ID; +#elif defined(SLOW_CHECK_USE_LAST_N_TASKS) +struct TaskTimeInfo { + uint16_t id; + uint32_t start_time; + uint32_t end_time; +}; +TaskTimeInfo time_info[SLOW_CHECK_USE_LAST_N_TASKS_COUNT]{}; +#if SLOW_CHECK_USE_LAST_N_TASKS_COUNT > 65536 +#error Use a uint32_t instead and remove these lines +#endif +uint16_t current_time_info{0}; + +// Must be a 32 bit timer and not be the same as the scheduler timer +TIM_TypeDef *perf_timer; +#endif + // ---------------------------- inline void Scheduler::global_timer_disable() { @@ -75,19 +97,32 @@ void Scheduler_start(void) { } void Scheduler::update() { +#ifdef SLOW_CHECK_USE_READY_BITMAP // NOTE: Only _one_ id will be shown per call to update() if (failing_id != Scheduler::INVALID_ID) [[unlikely]] { WARNING("Too slow, could not execute task %u in time", failing_id); failing_id = Scheduler::INVALID_ID; } +#endif while (ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); Task& task = tasks_[bit_index]; +#if defined(SLOW_CHECK_USE_LAST_N_TASKS) + TaskTimeInfo *info = time_info + current_time_info; + info->id = bit_index; + info->start_time = perf_timer->CNT; +#endif + task.callback(); +#if defined(SLOW_CHECK_USE_LAST_N_TASKS) + info->end_time = perf_timer->CNT; + current_time_info = (current_time_info + 1) & SLOW_CHECK_USE_LAST_N_TASKS_COUNT; +#endif + SchedLock(); CLEAR_BIT(ready_bitmap_, 1u << bit_index); if (!task.repeating) [[unlikely]] { @@ -246,9 +281,11 @@ inline void Scheduler::on_timer_update() { SchedLock(); pop_front(); // mark task as ready +#ifdef SLOW_CHECK_USE_READY_BITMAP if ((ready_bitmap_ & task_bit) != 0) [[unlikely]] { failing_id = candidate_id; } +#endif SET_BIT(ready_bitmap_, task_bit); if (task.repeating) [[likely]] { task.next_fire_us = static_cast(global_tick_us_ + task.period_us); From 19cf710aa9d698275002db0f4bece3c93e929aa3 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 13 May 2026 18:37:01 +0200 Subject: [PATCH 2/7] Add changeset and uart helper --- .changesets/scheduler-get-perf.md | 2 ++ .../Services/Communication/UART/UART.hpp | 10 ++++++ Inc/HALAL/Services/Time/Scheduler.hpp | 22 +++++++----- .../Services/Communication/UART/UART.cpp | 6 +++- Src/HALAL/Services/Time/Scheduler.cpp | 34 ++++++++++++++----- 5 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 .changesets/scheduler-get-perf.md diff --git a/.changesets/scheduler-get-perf.md b/.changesets/scheduler-get-perf.md new file mode 100644 index 000000000..25590042d --- /dev/null +++ b/.changesets/scheduler-get-perf.md @@ -0,0 +1,2 @@ +release: minor +summary: Implement simple performance gathering with the scheduler diff --git a/Inc/HALAL/Services/Communication/UART/UART.hpp b/Inc/HALAL/Services/Communication/UART/UART.hpp index d3ac241b5..cecce6603 100644 --- a/Inc/HALAL/Services/Communication/UART/UART.hpp +++ b/Inc/HALAL/Services/Communication/UART/UART.hpp @@ -160,6 +160,16 @@ class UART { */ static bool transmit_polling(uint8_t id, span data); + /**@brief Transmits size bytes by polling. + * + * @param id Id of the UART + * @param data Pointer to data to be sent. + * @param length Length of data to be sent. + * @return bool Returns true if the packet has been send successfully. + * Returns false if the UART is busy or a problem has occurred. + */ + static bool transmit_polling(uint8_t id, uint8_t *data, size_t length); + /** * @brief This method request the receive of size bytes * by DMA and interrupts. Thus the data should not be used until diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 40741238f..36bb55b1c 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -27,16 +27,16 @@ #include "stm32h7xx_hal_tim.h" #endif -//#define SLOW_CHECK_USE_READY_BITMAP -#define SLOW_CHECK_USE_LAST_N_TASKS - -#define SLOW_CHECK_USE_LAST_N_TASKS_COUNT 512 +#ifndef SIM_ON +#define SCHEDULER_GET_LAST_N_TASKS +#endif -#if defined(SLOW_CHECK_USE_LAST_N_TASKS) -// Must be a 32 bit timer and not be the same as the scheduler timer -extern TIM_TypeDef* perf_timer; +#if !defined(SCHEDULER_GET_LAST_N_TASKS) && !defined(SLOW_CHECK_USE_READY_BITMAP) +#define SLOW_CHECK_USE_READY_BITMAP #endif +#define SCHEDULER_GET_LAST_N_TASKS_COUNT 512 + extern TIM_TypeDef* Scheduler_global_timer; void Scheduler_global_timer_callback(void* raw); void Scheduler_start(void); @@ -48,8 +48,12 @@ struct Scheduler { // if it isn't it could theoretically be used as an id in set_timeout static constexpr uint32_t INVALID_ID = 2 * kMaxTasks; - // temporary, will be removed - [[deprecated]] static inline void start() {} + /* gets and checks the performance gathering requirements + * @param tim32bit: A timer or null if not gathering perf info (preferrably 32 bit) + * @return If the given arguments are correct + */ + static bool init_perf(TIM_TypeDef* tim32bit); + static void update(); static uint64_t get_global_tick(); diff --git a/Src/HALAL/Services/Communication/UART/UART.cpp b/Src/HALAL/Services/Communication/UART/UART.cpp index 7772626f1..44cf49e8e 100644 --- a/Src/HALAL/Services/Communication/UART/UART.cpp +++ b/Src/HALAL/Services/Communication/UART/UART.cpp @@ -64,6 +64,10 @@ bool UART::transmit_polling(uint8_t id, uint8_t data) { } bool UART::transmit_polling(uint8_t id, span data) { + return UART::transmit_polling(id, data.data(), data.size()); +} + +bool UART::transmit_polling(uint8_t id, uint8_t *data, size_t length) { if (not UART::registered_uart.contains(id)) return false; // TODO: Error handler @@ -72,7 +76,7 @@ bool UART::transmit_polling(uint8_t id, span data) { if ((handle->ErrorCode & TXBUSYMASK) == 1) return false; - if (HAL_UART_Transmit(handle, data.data(), data.size(), 10) != HAL_OK) { + if (HAL_UART_Transmit(handle, data, length, 10) != HAL_OK) { return false; // TODO: Warning, Error during transmision } diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 6ade7f092..9132a6aa4 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -31,22 +31,22 @@ uint64_t Scheduler::global_tick_us_{0}; uint32_t Scheduler::current_interval_us_{0}; uint16_t Scheduler::timeout_idx_{1}; -#if (SLOW_CHECK_USE_LAST_N_TASKS_COUNT & (SLOW_CHECK_USE_LAST_N_TASKS_COUNT - 1)) != 0 +#if (SCHEDULER_GET_LAST_N_TASKS_COUNT & (SCHEDULER_GET_LAST_N_TASKS_COUNT - 1)) != 0 // NOTE: Performance: this is to use an and instead of a mod when storing the data -#error SLOW_CHECK_USE_LAST_N_TASKS_COUNT must be a power of 2 +#error SCHEDULER_GET_LAST_N_TASKS_COUNT must be a power of 2 #endif #if defined(SLOW_CHECK_USE_READY_BITMAP) uint16_t failing_id = Scheduler::INVALID_ID; -#elif defined(SLOW_CHECK_USE_LAST_N_TASKS) +#elif defined(SCHEDULER_GET_LAST_N_TASKS) struct TaskTimeInfo { uint16_t id; uint32_t start_time; uint32_t end_time; }; -TaskTimeInfo time_info[SLOW_CHECK_USE_LAST_N_TASKS_COUNT]{}; -#if SLOW_CHECK_USE_LAST_N_TASKS_COUNT > 65536 +TaskTimeInfo time_info[SCHEDULER_GET_LAST_N_TASKS_COUNT]{}; +#if SCHEDULER_GET_LAST_N_TASKS_COUNT > 65536 #error Use a uint32_t instead and remove these lines #endif uint16_t current_time_info{0}; @@ -99,6 +99,22 @@ void Scheduler_start(void) { Scheduler::schedule_next_interval(); } +bool Scheduler::init_perf(TIM_TypeDef* tim32bit) +{ +#ifdef SCHEDULER_GET_LAST_N_TASKS + if (!tim32bit) { + return false; + } + + perf_timer = tim32bit; + + return true; +#else + (void)tim32bit; + return true; +#endif +} + void Scheduler::update() { #ifdef SLOW_CHECK_USE_READY_BITMAP // NOTE: Only _one_ id will be shown per call to update() @@ -113,17 +129,17 @@ void Scheduler::update() { Task& task = tasks_[bit_index]; -#if defined(SLOW_CHECK_USE_LAST_N_TASKS) - TaskTimeInfo *info = time_info + current_time_info; +#if defined(SCHEDULER_GET_LAST_N_TASKS) + TaskTimeInfo* info = time_info + current_time_info; info->id = bit_index; info->start_time = perf_timer->CNT; #endif task.callback(); -#if defined(SLOW_CHECK_USE_LAST_N_TASKS) +#if defined(SCHEDULER_GET_LAST_N_TASKS) info->end_time = perf_timer->CNT; - current_time_info = (current_time_info + 1) & SLOW_CHECK_USE_LAST_N_TASKS_COUNT; + current_time_info = (current_time_info + 1) & SCHEDULER_GET_LAST_N_TASKS_COUNT; #endif SchedLock(); From 513aa56ea16ca47439568e06a961d2c3105ea8ac Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 13 May 2026 19:39:11 +0200 Subject: [PATCH 3/7] setup uart usage --- Inc/HALAL/Services/Time/Scheduler.hpp | 8 +++++--- Src/HALAL/Services/Time/Scheduler.cpp | 18 +++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 36bb55b1c..c75d323c3 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -17,7 +17,7 @@ #endif #include "stm32h7xx_ll_tim_wrapper.h" -#include "HALAL/Models/Packets/Packet.hpp" +#include "HALAL/Services/Communication/UART/UART.hpp" #include #include @@ -35,7 +35,9 @@ #define SLOW_CHECK_USE_READY_BITMAP #endif -#define SCHEDULER_GET_LAST_N_TASKS_COUNT 512 +#if !defined(SCHEDULER_GET_LAST_N_TASKS_COUNT) +#define SCHEDULER_GET_LAST_N_TASKS_COUNT 16 +#endif extern TIM_TypeDef* Scheduler_global_timer; void Scheduler_global_timer_callback(void* raw); @@ -52,7 +54,7 @@ struct Scheduler { * @param tim32bit: A timer or null if not gathering perf info (preferrably 32 bit) * @return If the given arguments are correct */ - static bool init_perf(TIM_TypeDef* tim32bit); + static bool init_perf(TIM_TypeDef* tim32bit, UART::Peripheral* uart); static void update(); static uint64_t get_global_tick(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9132a6aa4..6933a7083 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -52,7 +52,8 @@ TaskTimeInfo time_info[SCHEDULER_GET_LAST_N_TASKS_COUNT]{}; uint16_t current_time_info{0}; // Must be a 32 bit timer and not be the same as the scheduler timer -TIM_TypeDef *perf_timer; +TIM_TypeDef *perf_timer{nullptr}; +uint8_t uart_id{0}; #endif // ---------------------------- @@ -99,7 +100,7 @@ void Scheduler_start(void) { Scheduler::schedule_next_interval(); } -bool Scheduler::init_perf(TIM_TypeDef* tim32bit) +bool Scheduler::init_perf(TIM_TypeDef* tim32bit, UART::Peripheral* uart) { #ifdef SCHEDULER_GET_LAST_N_TASKS if (!tim32bit) { @@ -108,9 +109,12 @@ bool Scheduler::init_perf(TIM_TypeDef* tim32bit) perf_timer = tim32bit; + uart_id = UART::inscribe(*uart); + return true; #else (void)tim32bit; + (void)uart; return true; #endif } @@ -122,6 +126,8 @@ void Scheduler::update() { WARNING("Too slow, could not execute task %u in time", failing_id); failing_id = Scheduler::INVALID_ID; } +#elif defined(SCHEDULER_GET_LAST_N_TASKS) + current_time_info = 0; #endif while (ready_bitmap_ != 0u) { @@ -139,7 +145,7 @@ void Scheduler::update() { #if defined(SCHEDULER_GET_LAST_N_TASKS) info->end_time = perf_timer->CNT; - current_time_info = (current_time_info + 1) & SCHEDULER_GET_LAST_N_TASKS_COUNT; + current_time_info = current_time_info + 1; #endif SchedLock(); @@ -149,6 +155,12 @@ void Scheduler::update() { } SchedUnlock(); } + +#if defined(SCHEDULER_GET_LAST_N_TASKS) + if (UART::transmit_polling(uart_id, (uint8_t*)&time_info, sizeof(TaskTimeInfo)*current_time_info)) { + WARNING("UART Error while trying to transmit timing info"); + } +#endif } uint64_t Scheduler::get_global_tick() { From aa5c0cc2e8d18aa8bf4759b3901877f65c1abb54 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 13 May 2026 19:40:05 +0200 Subject: [PATCH 4/7] 16 default tasks ---> 64 --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index c75d323c3..0ce07924d 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -36,7 +36,7 @@ #endif #if !defined(SCHEDULER_GET_LAST_N_TASKS_COUNT) -#define SCHEDULER_GET_LAST_N_TASKS_COUNT 16 +#define SCHEDULER_GET_LAST_N_TASKS_COUNT 64 #endif extern TIM_TypeDef* Scheduler_global_timer; From b9b09c3085aaab7fa6d6b9097d0a7602bdae0f24 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 13 May 2026 20:14:21 +0200 Subject: [PATCH 5/7] formatting --- Inc/HALAL/Services/Communication/UART/UART.hpp | 2 +- Src/HALAL/Services/Communication/UART/UART.cpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Services/Communication/UART/UART.hpp b/Inc/HALAL/Services/Communication/UART/UART.hpp index cecce6603..164f48c86 100644 --- a/Inc/HALAL/Services/Communication/UART/UART.hpp +++ b/Inc/HALAL/Services/Communication/UART/UART.hpp @@ -168,7 +168,7 @@ class UART { * @return bool Returns true if the packet has been send successfully. * Returns false if the UART is busy or a problem has occurred. */ - static bool transmit_polling(uint8_t id, uint8_t *data, size_t length); + static bool transmit_polling(uint8_t id, uint8_t* data, size_t length); /** * @brief This method request the receive of size bytes diff --git a/Src/HALAL/Services/Communication/UART/UART.cpp b/Src/HALAL/Services/Communication/UART/UART.cpp index 44cf49e8e..a070a4a0d 100644 --- a/Src/HALAL/Services/Communication/UART/UART.cpp +++ b/Src/HALAL/Services/Communication/UART/UART.cpp @@ -67,7 +67,7 @@ bool UART::transmit_polling(uint8_t id, span data) { return UART::transmit_polling(id, data.data(), data.size()); } -bool UART::transmit_polling(uint8_t id, uint8_t *data, size_t length) { +bool UART::transmit_polling(uint8_t id, uint8_t* data, size_t length) { if (not UART::registered_uart.contains(id)) return false; // TODO: Error handler diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 6933a7083..67f9b6db7 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -52,7 +52,7 @@ TaskTimeInfo time_info[SCHEDULER_GET_LAST_N_TASKS_COUNT]{}; uint16_t current_time_info{0}; // Must be a 32 bit timer and not be the same as the scheduler timer -TIM_TypeDef *perf_timer{nullptr}; +TIM_TypeDef* perf_timer{nullptr}; uint8_t uart_id{0}; #endif @@ -100,8 +100,7 @@ void Scheduler_start(void) { Scheduler::schedule_next_interval(); } -bool Scheduler::init_perf(TIM_TypeDef* tim32bit, UART::Peripheral* uart) -{ +bool Scheduler::init_perf(TIM_TypeDef* tim32bit, UART::Peripheral* uart) { #ifdef SCHEDULER_GET_LAST_N_TASKS if (!tim32bit) { return false; @@ -157,7 +156,11 @@ void Scheduler::update() { } #if defined(SCHEDULER_GET_LAST_N_TASKS) - if (UART::transmit_polling(uart_id, (uint8_t*)&time_info, sizeof(TaskTimeInfo)*current_time_info)) { + if (UART::transmit_polling( + uart_id, + (uint8_t*)&time_info, + sizeof(TaskTimeInfo) * current_time_info + )) { WARNING("UART Error while trying to transmit timing info"); } #endif From d666e01934b7806962df000d33ca1640544045e3 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 13 May 2026 20:16:01 +0200 Subject: [PATCH 6/7] dummy for compiling tests --- Inc/HALAL/Services/Time/Scheduler.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 0ce07924d..4a453c13c 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -29,6 +29,13 @@ #ifndef SIM_ON #define SCHEDULER_GET_LAST_N_TASKS +#else +struct UART { + struct Peripheral { + uint8_t ignore0; + }; + uint8_t ignore1; +}; #endif #if !defined(SCHEDULER_GET_LAST_N_TASKS) && !defined(SLOW_CHECK_USE_READY_BITMAP) From 005868dcc659bec4169d8eed79f651b8c95a2aa4 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 13 May 2026 20:26:38 +0200 Subject: [PATCH 7/7] formatting --- Inc/HALAL/Services/Time/Scheduler.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 4a453c13c..b4c97afea 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -31,10 +31,10 @@ #define SCHEDULER_GET_LAST_N_TASKS #else struct UART { - struct Peripheral { - uint8_t ignore0; - }; - uint8_t ignore1; + struct Peripheral { + uint8_t ignore0; + }; + uint8_t ignore1; }; #endif