diff --git a/can_bus/hexray/CRIT/CRIT_tx.json b/can_bus/hexray/CRIT/CRIT_tx.json index 32e5cfbbe0..5837a20639 100644 --- a/can_bus/hexray/CRIT/CRIT_tx.json +++ b/can_bus/hexray/CRIT/CRIT_tx.json @@ -192,6 +192,24 @@ "min": 0, "max": 100, "unit": "%" + }, + "TaskRun10HzCpuUsageMax": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRun10HzCpuUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRun10HzStackUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" } }, "data_capture": { diff --git a/can_bus/hexray/FSM/FSM_tx.json b/can_bus/hexray/FSM/FSM_tx.json index e2b4345701..8b86ea8489 100644 --- a/can_bus/hexray/FSM/FSM_tx.json +++ b/can_bus/hexray/FSM/FSM_tx.json @@ -331,6 +331,24 @@ "min": 0, "max": 100, "unit": "%" + }, + "TaskRunImuCpuUsageMax": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunImuCpuUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunImuStackUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" } }, "data_capture": { diff --git a/can_bus/hexray/RSM/RSM_tx.json b/can_bus/hexray/RSM/RSM_tx.json index abc9e7aad5..d94e75de79 100644 --- a/can_bus/hexray/RSM/RSM_tx.json +++ b/can_bus/hexray/RSM/RSM_tx.json @@ -291,6 +291,24 @@ "min": 0, "max": 100, "unit": "%" + }, + "TaskRunImuCpuUsageMax": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunImuCpuUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunImuStackUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" } }, "data_capture": { diff --git a/can_bus/hexray/VC/VC_tx.json b/can_bus/hexray/VC/VC_tx.json index b551a1508e..5911ffc9f6 100644 --- a/can_bus/hexray/VC/VC_tx.json +++ b/can_bus/hexray/VC/VC_tx.json @@ -1149,6 +1149,42 @@ "min": 0, "max": 100, "unit": "%" + }, + "TaskRunImuCpuUsageMax": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunImuCpuUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunImuStackUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunSbgEllipseCpuUsageMax": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunSbgEllipseCpuUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" + }, + "TaskRunSbgEllipseStackUsage": { + "resolution": 0.1, + "min": 0, + "max": 100, + "unit": "%" } }, "data_capture": { diff --git a/firmware/hexray/BMS/src/tasks.cpp b/firmware/hexray/BMS/src/tasks.cpp index e256462084..f0de8a94ea 100644 --- a/firmware/hexray/BMS/src/tasks.cpp +++ b/firmware/hexray/BMS/src/tasks.cpp @@ -354,6 +354,10 @@ void tasks_init() jobs_init(); BMS_StartAllTasks(); + if (static_cast(uxTaskGetNumberOfTasks()) != TASK_COUNT) + { + LOG_ERROR("Amount of tasks OS is handling does not match TASK_COUNT"); + } osKernelStart(); Error_Handler(); } diff --git a/firmware/hexray/CRIT/src/tasks.cpp b/firmware/hexray/CRIT/src/tasks.cpp index b2bdf749f1..90d9fde535 100644 --- a/firmware/hexray/CRIT/src/tasks.cpp +++ b/firmware/hexray/CRIT/src/tasks.cpp @@ -18,7 +18,7 @@ #include "hw_bootup.hpp" #include "hw_runTimeStat.hpp" -static constexpr size_t TASK_COUNT = 5; +static constexpr size_t TASK_COUNT = 6; [[noreturn]] static void tasks_run1Hz(void *arg); [[noreturn]] static void tasks_run100Hz(void *arg); [[noreturn]] static void tasks_run10Hz(void *arg); @@ -37,7 +37,7 @@ static hw::rtos::StaticTask::StaticTaskStack<512> TaskCanTxStack; static hw::rtos::StaticTask Task1kHz(osPriorityRealtime, "Task1kHz", tasks_run1kHz, Task1kHzStack); static hw::rtos::StaticTask Task1Hz(osPriorityAboveNormal, "Task1Hz", tasks_run1Hz, Task1HzStack); static hw::rtos::StaticTask Task100Hz(osPriorityHigh, "Task100Hz", tasks_run100Hz, Task100HzStack); -static hw::rtos::StaticTask Task10Hz(osPriorityHigh, "Task100Hz", tasks_run10Hz, Task10HzStack); +static hw::rtos::StaticTask Task10Hz(osPriorityHigh, "Task10Hz", tasks_run10Hz, Task10HzStack); static hw::rtos::StaticTask TaskCanRx(osPriorityNormal, "TaskCanRx", tasks_runCanRx, TaskCanRxStack); static hw::rtos::StaticTask TaskCanTx(osPriorityNormal, "TaskCanTx", tasks_runCanTx, TaskCanTxStack); @@ -77,6 +77,12 @@ static hw::runtimeStat::monitor runtimeMonitor( app::can_tx::CRIT_TaskRunCanTxCpuUsageMax_set, app::can_tx::CRIT_TaskRunCanTxStackUsage_set, }, + { + Task10Hz, + app::can_tx::CRIT_TaskRun10HzCpuUsage_set, + app::can_tx::CRIT_TaskRun10HzCpuUsageMax_set, + app::can_tx::CRIT_TaskRun10HzStackUsage_set, + }, } }); static hw::watchdog::monitor monitor{ @@ -246,6 +252,10 @@ void tasks_init() jobs_init(); CRIT_StartAllTasks(); + if (static_cast(uxTaskGetNumberOfTasks()) != TASK_COUNT) + { + LOG_ERROR("Amount of tasks OS is handling does not match TASK_COUNT"); + } osKernelStart(); forever {} } diff --git a/firmware/hexray/DAM/src/tasks.cpp b/firmware/hexray/DAM/src/tasks.cpp index 594b90c3cc..ef01767491 100644 --- a/firmware/hexray/DAM/src/tasks.cpp +++ b/firmware/hexray/DAM/src/tasks.cpp @@ -425,6 +425,10 @@ void tasks_init() jobs_init(); DAM_StartAllTasks(); + if (static_cast(uxTaskGetNumberOfTasks()) != TASK_COUNT) + { + LOG_ERROR("Amount of tasks OS is handling does not match TASK_COUNT"); + } osKernelStart(); forever {} } diff --git a/firmware/hexray/FSM/src/tasks.cpp b/firmware/hexray/FSM/src/tasks.cpp index 1881125b5a..973a256628 100644 --- a/firmware/hexray/FSM/src/tasks.cpp +++ b/firmware/hexray/FSM/src/tasks.cpp @@ -19,7 +19,7 @@ #include "hw_adcs.hpp" #include "hw_runTimeStat.hpp" -constexpr size_t TASK_COUNT = 5; +constexpr size_t TASK_COUNT = 6; [[noreturn]] static void tasks_run1Hz(void *arg); [[noreturn]] static void tasks_run100Hz(void *arg); [[noreturn]] static void tasks_run1kHz(void *arg); @@ -42,7 +42,7 @@ static hw::rtos::StaticTask TaskImu(osPriorityHigh, "TaskImu", tasks_runImu, Tas static hw::rtos::StaticTask TaskCanTx(osPriorityNormal, "TaskCanTx", tasks_runCanTx, TaskCanTxStack); static hw::rtos::StaticTask TaskCanRx(osPriorityNormal, "TaskCanRx", tasks_runCanRx, TaskCanRxStack); -static hw::runtimeStat::monitor<5> runtimeMonitor{ +static hw::runtimeStat::monitor runtimeMonitor{ { app::can_tx::FSM_CoreCpuUsage_set, app::can_tx::FSM_CoreCpuUsageMax_set }, { { { Task1kHz, @@ -73,6 +73,12 @@ static hw::runtimeStat::monitor<5> runtimeMonitor{ app::can_tx::FSM_TaskRunCanRxCpuUsage_set, app::can_tx::FSM_TaskRunCanRxCpuUsageMax_set, app::can_tx::FSM_TaskRunCanRxStackUsage_set, + }, + { + TaskImu, + app::can_tx::FSM_TaskRunImuCpuUsage_set, + app::can_tx::FSM_TaskRunImuCpuUsageMax_set, + app::can_tx::FSM_TaskRunImuStackUsage_set, } } }, }; @@ -248,6 +254,10 @@ void tasks_preInit() jobs_init(); FSM_StartAllTasks(); + if (static_cast(uxTaskGetNumberOfTasks()) != TASK_COUNT) + { + LOG_ERROR("Amount of tasks OS is handling does not match TASK_COUNT"); + } osKernelStart(); forever {} } diff --git a/firmware/hexray/RSM/src/tasks.cpp b/firmware/hexray/RSM/src/tasks.cpp index 29b0309e6d..c9ba5342c9 100644 --- a/firmware/hexray/RSM/src/tasks.cpp +++ b/firmware/hexray/RSM/src/tasks.cpp @@ -22,7 +22,7 @@ #include "hw_bootup.hpp" #include "hw_runTimeStat.hpp" -constexpr size_t TASK_COUNT = 5; +constexpr size_t TASK_COUNT = 6; [[noreturn]] static void tasks_run1Hz(void *arg); [[noreturn]] static void tasks_run100Hz(void *arg); [[noreturn]] static void tasks_run1kHz(void *arg); @@ -57,7 +57,9 @@ static hw::runtimeStat::monitor runtimeMonitor{ { TaskCanRx, app::can_tx::RSM_TaskRunCanRxCpuUsage_set, app::can_tx::RSM_TaskRunCanRxCpuUsageMax_set, app::can_tx::RSM_TaskRunCanRxStackUsage_set }, { TaskCanTx, app::can_tx::RSM_TaskRunCanTxCpuUsage_set, app::can_tx::RSM_TaskRunCanTxCpuUsageMax_set, - app::can_tx::RSM_TaskRunCanTxStackUsage_set } }, + app::can_tx::RSM_TaskRunCanTxStackUsage_set }, + { TaskImu, app::can_tx::RSM_TaskRunImuCpuUsage_set, app::can_tx::RSM_TaskRunImuCpuUsageMax_set, + app::can_tx::RSM_TaskRunImuStackUsage_set } }, }, }; @@ -229,6 +231,10 @@ void tasks_init() jobs_init(); RSM_StartAllTasks(); + if (static_cast(uxTaskGetNumberOfTasks()) != TASK_COUNT) + { + LOG_ERROR("Amount of tasks OS is handling does not match TASK_COUNT"); + } osKernelStart(); forever {} } diff --git a/firmware/hexray/VC/src/tasks.cpp b/firmware/hexray/VC/src/tasks.cpp index 7d9d268789..c66d45d0de 100644 --- a/firmware/hexray/VC/src/tasks.cpp +++ b/firmware/hexray/VC/src/tasks.cpp @@ -38,7 +38,7 @@ [[noreturn]] static void tasks_sbgEllipse(void *arg); // Define the task with StaticTask Class -constexpr size_t TASK_COUNT = 7; // IMU, Batt Mon, Power Mon ADD +constexpr size_t TASK_COUNT = 9; // every task VC_StartAllTasks() starts static hw::rtos::StaticTask::StaticTaskStack<8096> Task100HzStack; static hw::rtos::StaticTask::StaticTaskStack<512> Task1kHzStack; static hw::rtos::StaticTask::StaticTaskStack<512> Task1HzStack; @@ -80,8 +80,13 @@ static hw::runtimeStat::monitor runtimeMonitor{ app::can_tx::VC_TaskRunCan2TxStackUsage_set }, { TaskPowerMonitoring, app::can_tx::VC_TaskRunPowerMonitoringCpuUsage_set, app::can_tx::VC_TaskRunPowerMonitoringCpuUsageMax_set, - app::can_tx::VC_TaskRunPowerMonitoringStackUsage_set } }, - // Battery Monitoring and IMU... + app::can_tx::VC_TaskRunPowerMonitoringStackUsage_set }, + { TaskImu, app::can_tx::VC_TaskRunImuCpuUsage_set, app::can_tx::VC_TaskRunImuCpuUsageMax_set, + app::can_tx::VC_TaskRunImuStackUsage_set }, + { TaskSbgEllipse, app::can_tx::VC_TaskRunSbgEllipseCpuUsage_set, + app::can_tx::VC_TaskRunSbgEllipseCpuUsageMax_set, + app::can_tx::VC_TaskRunSbgEllipseStackUsage_set } }, + // TaskBatteryMonitoring is declared but not started, so it is deliberately not registered here. }, }; @@ -101,7 +106,7 @@ void tasks_run1Hz(void *arg) { jobs_run1Hz_tick(); watchdog1hz.checkIn(); - // runtimeMonitor.checkin(); + runtimeMonitor.checkin(); start_ticks += period_ms; io::time::delayUntil(start_ticks); osDelayUntil(start_ticks); @@ -308,18 +313,6 @@ void tasks_init() hw::bootup::setBootRequest(boot_request); } - // TODO this should surely be managed by the power manager?? - // dam_en.writePin(true); - // rsm_en.writePin(true); - // front_en.writePin(true); - // bms_en.writePin(true); - // rl_pump_en.writePin(true); - // rr_pump_en.writePin(true); - // f_inv_en.writePin(true); - // r_inv_en.writePin(true); - // r_rad_fan_en.writePin(true); - // l_rad_fan_en.writePin(true); - // misc_fuse_en.writePin(true); ResetReason reason = hw::resetReason::get(); app::can_tx::VC_ResetReason_set(static_cast(reason)); if (reason == RESET_REASON_WATCHDOG) @@ -331,6 +324,11 @@ void tasks_init() jobs_init(); adcChipsInit(); VC_StartAllTasks(); + if (static_cast(uxTaskGetNumberOfTasks()) != TASK_COUNT) + { + LOG_ERROR("Amount of tasks OS is handling does not match TASK_COUNT"); + assert(false); + } osKernelStart(); forever {} } diff --git a/firmware/shared/srcpp/hw/hw_runTimeStat.hpp b/firmware/shared/srcpp/hw/hw_runTimeStat.hpp index 7fc0b6c4f7..59a29ae4a6 100644 --- a/firmware/shared/srcpp/hw/hw_runTimeStat.hpp +++ b/firmware/shared/srcpp/hw/hw_runTimeStat.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -10,14 +9,16 @@ #endif #include "hw_hal.hpp" +#include "hw_rtosTaskHandler.hpp" + #ifdef STM32F412Rx #include "stm32f4xx_hal_tim.h" #elifdef STM32H562xx #include "stm32h5xx_hal_tim.h" #elifdef STM32H733xx +#include "stm32h7xx_hal_tim.h" #endif -#include "hw_rtosTaskHandler.hpp" #include "io_log.hpp" namespace hw::runtimeStat @@ -50,20 +51,21 @@ template class monitor void (*cpu_usage_max_setter)(float); void (*stack_usage_max_setter)(float); }; + + // IDLE and Tmr Svc are created by the scheduler itself, so the OS always reports TaskCount + 2 tasks. + // Every board must register every task it starts; tasks_init() checks that at startup. static constexpr size_t NUM_FT_TASKS = 2U; static constexpr size_t NUM_TOTAL_TASKS = NUM_FT_TASKS + TaskCount; - static constexpr size_t IDLE_TASK_INDEX = NUM_TOTAL_TASKS - 2; - static constexpr size_t TMR_SVC_INDEX = NUM_TOTAL_TASKS - 1; - std::array _tasks_info; - CpuInfoBroadcasters _cpu_info; + std::array _tasks_info; + CpuInfoBroadcasters _cpu_info; struct TaskData { float max_cpu_usage = 0.0f; }; - mutable std::array _tasks_data{}; - mutable float max_cpu_usage = 0.0f; + mutable std::array _tasks_data{}; + mutable float max_cpu_usage = 0.0f; public: monitor(const CpuInfoBroadcasters c, const std::array tasks) : _cpu_info(c) @@ -84,83 +86,94 @@ template class monitor .stack_usage_max_setter = tasks[i].stack_usage_max_setter, }; } - std::sort( - _tasks_info.begin(), _tasks_info.begin() + TaskCount, - [](const TaskInfoInternal &a, const TaskInfoInternal &b) { return a.t->id() < b.t->id(); }); - - // mi bombo - _tasks_info[IDLE_TASK_INDEX] = { - .cpu_usage_setter = nullptr, - .cpu_usage_max_setter = nullptr, - .stack_usage_max_setter = nullptr, - }; - _tasks_info[TMR_SVC_INDEX] = { - .cpu_usage_setter = nullptr, - .cpu_usage_max_setter = nullptr, - .stack_usage_max_setter = nullptr, - }; } /** - * use this function to update the runtime statistics + * Join between two tables runTimeStats and _tasks_info + * runTimeStats: filled by the OS and holds measurements about stack usage and task runtime + * _tasks_info: routes runTimeStats, which CAN setter each task's number goes to */ void checkin() const { - /* Get the task IDLE handle for processing the time spend outside of idle task*/ + // 1. Get shi, takes results from the OS and fills it into the runTimeStats array (of type TaskStatus_t) std::array runTimeStats{}; - uint32_t ulTotalRunTime; - const uint32_t arraySize = - uxTaskGetSystemState(runTimeStats.data(), static_cast(NUM_TOTAL_TASKS), &ulTotalRunTime); + uint32_t ulTotalRunTime = 0; + const uint32_t arraySize = uxTaskGetSystemState( + runTimeStats.data(), static_cast(NUM_TOTAL_TASKS), &ulTotalRunTime); + if (arraySize == 0) { + // The OS is running more tasks than NUM_TOTAL_TASKS: one was started but never registered LOG_ERROR("TaskGetSystemState failed"); return; } - if (arraySize != NUM_TOTAL_TASKS) + if (ulTotalRunTime == 0) { - LOG_ERROR("TaskGetSystemState returned unexpected number of tasks: %lu", arraySize); + // No profiling time base yet, so every percentage below would be a divide by zero + LOG_ERROR("Run time counter is 0, is configGENERATE_RUN_TIME_STATS enabled?"); return; } - std::sort( - runTimeStats.begin(), runTimeStats.end(), - [](const TaskStatus_t &a, const TaskStatus_t &b) { return a.xTaskNumber < b.xTaskNumber; }); - - /* + /* 2. IDLE Extraction, grabs the idle task's run-time counter * Given each task that we get from the following getsystemstate call we are gonna calculate the * cpu usage and stack usage */ - const TaskStatus_t &idleTaskStatus = runTimeStats[IDLE_TASK_INDEX]; - assert(idleTaskStatus.xTaskNumber == IDLE_TASK_INDEX + 1); - assert(strcmp(idleTaskStatus.pcTaskName, "IDLE") == 0); - uint32_t idle_counter = idleTaskStatus.ulRunTimeCounter; - // Calculate total current cpu usage and max cpu usage - const float cpu_usage = (1.0f - static_cast(idle_counter) / static_cast(ulTotalRunTime)) * 100; + TaskHandle_t idle_handle = xTaskGetIdleTaskHandle(); + uint32_t idle_index ; + for (idle_index = 0; idle_index < arraySize; idle_index++) + { + if (runTimeStats[idle_index].xHandle == idle_handle) break; + } + if (idle_index == arraySize) + { + LOG_ERROR("IDLE task not found in taskgetsystemstate results"); + return; + } + uint32_t idle_counter = runTimeStats[idle_index].ulRunTimeCounter; + + // 3. Calculate total current cpu usage and max cpu usage + const float cpu_usage = (1.0f - static_cast(idle_counter) / static_cast(ulTotalRunTime)) * 100.0f; _cpu_info.cpu_usage_setter(cpu_usage); max_cpu_usage = std::max(max_cpu_usage, cpu_usage); _cpu_info.cpu_usage_max_setter(max_cpu_usage); - for (uint32_t task = 0; task < NUM_TOTAL_TASKS - NUM_FT_TASKS; task++) + /* 4. Match every registered task to its measurement by handle + * task: indexes our own list + * stat_index: indexes the OS table + */ + for (uint32_t task = 0; task < TaskCount; task++) { - // get the idle time that we need to calculate the cpu usage associated - if (idle_counter + runTimeStats[task].ulRunTimeCounter != 0) + // For each task check to see its handle and see if runTimeStats has the same + const auto handle = _tasks_info[task].t->id(); + + uint32_t stat_index; + for (stat_index = 0; stat_index < arraySize; stat_index++) { - assert(_tasks_info[task].t->id() == runTimeStats[task].xHandle); - // Calculate current cpu usage - const float task_cpu_usage = static_cast(runTimeStats[task].ulRunTimeCounter) / - static_cast(idle_counter + runTimeStats[task].ulRunTimeCounter) * - 100; - _tasks_info[task].cpu_usage_setter(task_cpu_usage); - - // Calculate the max cpu usage - _tasks_data[task].max_cpu_usage = std::max(_tasks_data[task].max_cpu_usage, task_cpu_usage); - _tasks_info[task].cpu_usage_max_setter(_tasks_data[task].max_cpu_usage); + if (runTimeStats[stat_index].xHandle == handle) + { + break; + } } + if (stat_index == arraySize) + { + LOG_ERROR("Registered task %lu missing from taskgetsystemstate results", task); + continue; + } + TaskStatus_t &status = runTimeStats[stat_index]; + + // Calculate current cpu usage + const float task_cpu_usage = + static_cast(status.ulRunTimeCounter) / static_cast(ulTotalRunTime) * 100.0f; + _tasks_info[task].cpu_usage_setter(task_cpu_usage); + + // Calculate the max cpu usage + _tasks_data[task].max_cpu_usage = std::max(_tasks_data[task].max_cpu_usage, task_cpu_usage); + _tasks_info[task].cpu_usage_max_setter(_tasks_data[task].max_cpu_usage); // Calculate max stack usage - const float max_stack_usage = (1 - static_cast(runTimeStats[task].usStackHighWaterMark) / - static_cast(_tasks_info[task].t->stackSize())) * - 100; + const float max_stack_usage = (1.0f - static_cast(status.usStackHighWaterMark) / + static_cast(_tasks_info[task].t->stackSize())) * + 100.0f; _tasks_info[task].stack_usage_max_setter(max_stack_usage); } } diff --git a/firmware/third_party/freertos/config/FreeRTOSConfig.h b/firmware/third_party/freertos/config/FreeRTOSConfig.h index 41ab4a63b4..90f707c01b 100644 --- a/firmware/third_party/freertos/config/FreeRTOSConfig.h +++ b/firmware/third_party/freertos/config/FreeRTOSConfig.h @@ -31,6 +31,6 @@ extern "C" } #endif #define configUSE_TRACE_FACILITY 1 -#define configGENERATE_RUN_TIME_STATS 0 +#define configGENERATE_RUN_TIME_STATS 1 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS configureTimerForRunTimeStats #define portGET_RUN_TIME_COUNTER_VALUE getRunTimeCounterValue \ No newline at end of file