From 13df59f80687b845d103776fd8fb624b827bd383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96ster?= Date: Sun, 31 Aug 2025 22:54:57 +0300 Subject: [PATCH] Make performance profiling configurable from webserver --- Software/Software.ino | 87 +++++++++---------- Software/USER_SETTINGS.h | 1 - .../comm_contactorcontrol.cpp | 3 +- Software/src/communication/nvm/comm_nvm.cpp | 1 + Software/src/datalayer/datalayer.h | 6 +- Software/src/devboard/utils/time_meas.h | 6 -- .../src/devboard/webserver/settings_html.cpp | 7 ++ Software/src/devboard/webserver/webserver.cpp | 37 ++++---- 8 files changed, 74 insertions(+), 74 deletions(-) diff --git a/Software/Software.ino b/Software/Software.ino index bfd3ceab..98fe5f8e 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -42,10 +42,11 @@ const char* version_number = "9.0.RC5experimental"; volatile unsigned long currentMillis = 0; unsigned long previousMillis10ms = 0; unsigned long previousMillisUpdateVal = 0; -#ifdef FUNCTION_TIME_MEASUREMENT // Task time measurement for debugging MyTimer core_task_timer_10s(INTERVAL_10_S); -#endif +uint64_t start_time_10ms = 0; +uint64_t start_time_values = 0; +uint64_t start_time_cantx = 0; TaskHandle_t main_loop_task; TaskHandle_t connectivity_loop_task; TaskHandle_t logging_loop_task; @@ -248,24 +249,24 @@ void core_loop(void*) { set_event(EVENT_TASK_OVERRUN, (currentMillis - previousMillis10ms)); } previousMillis10ms = currentMillis; -#ifdef FUNCTION_TIME_MEASUREMENT - START_TIME_MEASUREMENT(time_10ms); -#endif + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(10ms); + } led_exe(); handle_contactors(); // Take care of startup precharge/contactor closing #ifdef PRECHARGE_CONTROL handle_precharge_control(currentMillis); #endif // PRECHARGE_CONTROL -#ifdef FUNCTION_TIME_MEASUREMENT - END_TIME_MEASUREMENT_MAX(time_10ms, datalayer.system.status.time_10ms_us); -#endif + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(10ms, datalayer.system.status.time_10ms_us); + } } if (currentMillis - previousMillisUpdateVal >= INTERVAL_1_S) { previousMillisUpdateVal = currentMillis; // Order matters on the update_loop! -#ifdef FUNCTION_TIME_MEASUREMENT - START_TIME_MEASUREMENT(time_values); -#endif + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(values); + } update_pause_state(); // Check if we are OK to send CAN or need to pause // Fetch battery values @@ -285,48 +286,46 @@ void core_loop(void*) { inverter->update_values(); } -#ifdef FUNCTION_TIME_MEASUREMENT - END_TIME_MEASUREMENT_MAX(time_values, datalayer.system.status.time_values_us); -#endif + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(values, datalayer.system.status.time_values_us); + } + } + if (datalayer.system.info.performance_measurement_active) { + START_TIME_MEASUREMENT(cantx); } -#ifdef FUNCTION_TIME_MEASUREMENT - START_TIME_MEASUREMENT(cantx); -#endif // Let all transmitter objects send their messages for (auto& transmitter : transmitters) { transmitter->transmit(currentMillis); } -#ifdef FUNCTION_TIME_MEASUREMENT - END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); - END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); -#endif -#ifdef FUNCTION_TIME_MEASUREMENT - if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) { - // Update worst case total time - datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us; - // Record snapshots of task times - datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us; - datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us; - datalayer.system.status.time_snap_values_us = datalayer.system.status.time_values_us; - datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us; - datalayer.system.status.time_snap_ota_us = datalayer.system.status.time_ota_us; - } + if (datalayer.system.info.performance_measurement_active) { + END_TIME_MEASUREMENT_MAX(cantx, datalayer.system.status.time_cantx_us); + END_TIME_MEASUREMENT_MAX(all, datalayer.system.status.core_task_10s_max_us); + if (datalayer.system.status.core_task_10s_max_us > datalayer.system.status.core_task_max_us) { + // Update worst case total time + datalayer.system.status.core_task_max_us = datalayer.system.status.core_task_10s_max_us; + // Record snapshots of task times + datalayer.system.status.time_snap_comm_us = datalayer.system.status.time_comm_us; + datalayer.system.status.time_snap_10ms_us = datalayer.system.status.time_10ms_us; + datalayer.system.status.time_snap_values_us = datalayer.system.status.time_values_us; + datalayer.system.status.time_snap_cantx_us = datalayer.system.status.time_cantx_us; + datalayer.system.status.time_snap_ota_us = datalayer.system.status.time_ota_us; + } - datalayer.system.status.core_task_max_us = - MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us); - if (core_task_timer_10s.elapsed()) { - datalayer.system.status.time_ota_us = 0; - datalayer.system.status.time_comm_us = 0; - datalayer.system.status.time_10ms_us = 0; - datalayer.system.status.time_values_us = 0; - datalayer.system.status.time_cantx_us = 0; - datalayer.system.status.core_task_10s_max_us = 0; - datalayer.system.status.wifi_task_10s_max_us = 0; - datalayer.system.status.mqtt_task_10s_max_us = 0; + datalayer.system.status.core_task_max_us = + MAX(datalayer.system.status.core_task_10s_max_us, datalayer.system.status.core_task_max_us); + if (core_task_timer_10s.elapsed()) { + datalayer.system.status.time_ota_us = 0; + datalayer.system.status.time_comm_us = 0; + datalayer.system.status.time_10ms_us = 0; + datalayer.system.status.time_values_us = 0; + datalayer.system.status.time_cantx_us = 0; + datalayer.system.status.core_task_10s_max_us = 0; + datalayer.system.status.wifi_task_10s_max_us = 0; + datalayer.system.status.mqtt_task_10s_max_us = 0; + } } -#endif // FUNCTION_TIME_MEASUREMENT esp_task_wdt_reset(); // Reset watchdog to prevent reset vTaskDelayUntil(&xLastWakeTime, xFrequency); } diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index bdef00da..fdf4340b 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -123,7 +123,6 @@ #define WIFIAP //When enabled, the emulator will broadcast its own access point Wifi. Can be used at the same time as a normal Wifi connection to a router. #define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled. #define LOAD_SAVED_SETTINGS_ON_BOOT // Enable this line to read settings stored via the webserver on boot (overrides Wifi credentials set here) -//#define FUNCTION_TIME_MEASUREMENT // Enable this to record execution times and present them in the web UI (WARNING, raises CPU load, do not use for production) /* MQTT options */ // #define MQTT // Enable this line to enable MQTT diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index 8983807e..c7a0e877 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -297,7 +297,7 @@ void handle_BMSpower() { if (periodic_bms_reset) { // Check if 24 hours have passed since the last power removal - if ((currentTime + bmsResetTimeOffset) - lastPowerRemovalTime >= powerRemovalInterval) { + if (currentTime - lastPowerRemovalTime >= powerRemovalInterval) { start_bms_reset(); } } @@ -329,7 +329,6 @@ void start_bms_reset() { if (!datalayer.system.status.BMS_reset_in_progress) { lastPowerRemovalTime = currentTime; // Record the time when BMS reset was started // we are now resetting at the correct time. We don't need to offset anymore - bmsResetTimeOffset = 0; // Set a flag to let the rest of the system know we are cutting power to the BMS. // The battery CAN sending routine will then know not to try guto send anything towards battery while active datalayer.system.status.BMS_reset_in_progress = true; diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 3c83f9c2..bd8a8802 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -144,6 +144,7 @@ void init_stored_settings() { remote_bms_reset = settings.getBool("REMBMSRESET", false); use_canfd_as_can = settings.getBool("CANFDASCAN", false); + datalayer.system.info.performance_measurement_active = settings.getBool("PERFPROFILE", false); datalayer.system.info.CAN_usb_logging_active = settings.getBool("CANLOGUSB", false); datalayer.system.info.usb_logging_active = settings.getBool("USBENABLED", false); datalayer.system.info.web_logging_active = settings.getBool("WEBENABLED", false); diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 5ead9832..83649469 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -259,12 +259,13 @@ struct DATALAYER_SYSTEM_INFO_TYPE { bool can_native_send_fail = false; /** bool, MCP2515 CAN failed to send flag */ bool can_2515_send_fail = false; - /** uint16_t, MCP2518 CANFD failed to send flag */ + /** bool, MCP2518 CANFD failed to send flag */ bool can_2518_send_fail = false; + /** bool, determines if detailed performance measurement should be shown on webserver */ + bool performance_measurement_active = false; }; struct DATALAYER_SYSTEM_STATUS_TYPE { -#ifdef FUNCTION_TIME_MEASUREMENT /** Core task measurement variable */ int64_t core_task_max_us = 0; /** Core task measurement variable, reset each 10 seconds */ @@ -305,7 +306,6 @@ struct DATALAYER_SYSTEM_STATUS_TYPE { * This will show the performance of CAN TX when the total time reached a new worst case */ int64_t time_snap_cantx_us = 0; -#endif /** uint8_t */ /** A counter set each time a new message comes from inverter. * This value then gets decremented every second. Incase we reach 0 diff --git a/Software/src/devboard/utils/time_meas.h b/Software/src/devboard/utils/time_meas.h index 30f1e5eb..df2c8b0c 100644 --- a/Software/src/devboard/utils/time_meas.h +++ b/Software/src/devboard/utils/time_meas.h @@ -7,7 +7,6 @@ /** Start time measurement in microseconds * Input parameter must be a unique "tag", e.g: START_TIME_MEASUREMENT(wifi); */ -#ifdef FUNCTION_TIME_MEASUREMENT #define START_TIME_MEASUREMENT(x) int64_t start_time_##x = esp_timer_get_time() /** End time measurement in microseconds * Input parameters are the unique tag and the name of the ALREADY EXISTING @@ -21,10 +20,5 @@ * This will log the maximum value in the destination variable. */ #define END_TIME_MEASUREMENT_MAX(x, y) y = MAX(y, esp_timer_get_time() - start_time_##x) -#else -#define START_TIME_MEASUREMENT(x) ; -#define END_TIME_MEASUREMENT(x, y) ; -#define END_TIME_MEASUREMENT_MAX(x, y) ; -#endif #endif diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 0a9d4163..62060cfb 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -283,6 +283,10 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti return settings.getBool("WIFIAPENABLED", wifiap_enabled) ? "checked" : ""; } + if (var == "PERFPROFILE") { + return settings.getBool("PERFPROFILE") ? "checked" : ""; + } + if (var == "CANLOGUSB") { return settings.getBool("CANLOGUSB") ? "checked" : ""; } @@ -970,6 +974,9 @@ const char* getCANInterfaceName(CAN_Interface interface) { + + + diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index d9ab1ad3..f0b5c633 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -411,7 +411,7 @@ void init_webserver() { const char* boolSettingNames[] = { "DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED", "REMBMSRESET", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD", "WIFIAPENABLED", "MQTTENABLED", - "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", + "HADISC", "MQTTTOPICS", "INVICNT", "GTWRHD", "DIGITALHVIL", "PERFPROFILE", }; // Handles the form POST from UI to save settings of the common image @@ -914,23 +914,24 @@ String processor(const String& var) { #endif // HW_STARK content += " @ " + String(datalayer.system.info.CPU_temperature, 1) + " °C"; content += "

Uptime: " + get_uptime() + "

"; -#ifdef FUNCTION_TIME_MEASUREMENT - // Load information - content += "

Core task max load: " + String(datalayer.system.status.core_task_max_us) + " us

"; - content += "

Core task max load last 10 s: " + String(datalayer.system.status.core_task_10s_max_us) + " us

"; - content += - "

MQTT function (MQTT task) max load last 10 s: " + String(datalayer.system.status.mqtt_task_10s_max_us) + - " us

"; - content += - "

WIFI function (MQTT task) max load last 10 s: " + String(datalayer.system.status.wifi_task_10s_max_us) + - " us

"; - content += "

Max load @ worst case execution of core task:

"; - content += "

10ms function timing: " + String(datalayer.system.status.time_snap_10ms_us) + " us

"; - content += "

Values function timing: " + String(datalayer.system.status.time_snap_values_us) + " us

"; - content += "

CAN/serial RX function timing: " + String(datalayer.system.status.time_snap_comm_us) + " us

"; - content += "

CAN TX function timing: " + String(datalayer.system.status.time_snap_cantx_us) + " us

"; - content += "

OTA function timing: " + String(datalayer.system.status.time_snap_ota_us) + " us

"; -#endif // FUNCTION_TIME_MEASUREMENT + if (datalayer.system.info.performance_measurement_active) { + // Load information + content += "

Core task max load: " + String(datalayer.system.status.core_task_max_us) + " us

"; + content += + "

Core task max load last 10 s: " + String(datalayer.system.status.core_task_10s_max_us) + " us

"; + content += + "

MQTT function (MQTT task) max load last 10 s: " + String(datalayer.system.status.mqtt_task_10s_max_us) + + " us

"; + content += + "

WIFI function (MQTT task) max load last 10 s: " + String(datalayer.system.status.wifi_task_10s_max_us) + + " us

"; + content += "

Max load @ worst case execution of core task:

"; + content += "

10ms function timing: " + String(datalayer.system.status.time_snap_10ms_us) + " us

"; + content += "

Values function timing: " + String(datalayer.system.status.time_snap_values_us) + " us

"; + content += "

CAN/serial RX function timing: " + String(datalayer.system.status.time_snap_comm_us) + " us

"; + content += "

CAN TX function timing: " + String(datalayer.system.status.time_snap_cantx_us) + " us

"; + content += "

OTA function timing: " + String(datalayer.system.status.time_snap_ota_us) + " us

"; + } wl_status_t status = WiFi.status(); // Display ssid of network connected to and, if connected to the WiFi, its own IP