From 75be23eca28a27f0283c0dd7f9d1ddd746fb0d92 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Tue, 19 Aug 2025 23:45:40 +0200 Subject: [PATCH] Basic CPU affinity configuration --- Documentation/ideas.md | 1 - Tactility/Source/app/boot/Boot.cpp | 8 +- .../Source/app/i2cscanner/I2cScanner.cpp | 4 +- Tactility/Source/lvgl/EspLvglPort.cpp | 8 +- Tactility/Source/lvgl/Lvgl.cpp | 1 - .../service/screenshot/ScreenshotTask.cpp | 6 +- TactilityCore/Include/Tactility/CpuAffinity.h | 27 ++++++ TactilityCore/Include/Tactility/Timer.h | 2 +- TactilityCore/Source/CpuAffinity.cpp | 85 +++++++++++++++++++ TactilityCore/Source/Timer.cpp | 2 +- 10 files changed, 130 insertions(+), 14 deletions(-) create mode 100644 TactilityCore/Include/Tactility/CpuAffinity.h create mode 100644 TactilityCore/Source/CpuAffinity.cpp diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 899531c5..ebb5f7ba 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -13,7 +13,6 @@ - Mutex: Implement give/take from ISR support (works only for non-recursive ones) - Extend unPhone power driver: add charging status, usb connection status, etc. - Expose app::Paths to TactilityC -- Make a ledger for setting CPU affinity of various services and tasks - CrashHandler: use "corrupted" flag - CrashHandler: process other types of crashes (WDT?) - Call tt::lvgl::isSyncSet after HAL init and show an error (and crash?) when it is not set. diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 8dbee6f9..9f8f85f3 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -11,6 +11,7 @@ #include #include +#include #ifdef ESP_PLATFORM #include "Tactility/app/crashdiagnostics/CrashDiagnostics.h" @@ -30,7 +31,12 @@ static std::shared_ptr getHalDisplay() { class BootApp : public App { - Thread thread = Thread("boot", 4096, [] { return bootThreadCallback(); }); + Thread thread = Thread( + "boot", + 4096, + [] { return bootThreadCallback(); }, + getCpuAffinityConfiguration().system + ); static void setupDisplay() { const auto hal_display = getHalDisplay(); diff --git a/Tactility/Source/app/i2cscanner/I2cScanner.cpp b/Tactility/Source/app/i2cscanner/I2cScanner.cpp index 67250b78..8c4c977e 100644 --- a/Tactility/Source/app/i2cscanner/I2cScanner.cpp +++ b/Tactility/Source/app/i2cscanner/I2cScanner.cpp @@ -24,8 +24,6 @@ extern const AppManifest manifest; class I2cScannerApp : public App { -private: - // Core Mutex mutex = Mutex(Mutex::Type::Recursive); std::unique_ptr scanTimer = nullptr; @@ -286,7 +284,7 @@ void I2cScannerApp::startScanning() { lv_obj_clean(scanListWidget); scanState = ScanStateScanning; - scanTimer = std::make_unique(Timer::Type::Once, [](){ + scanTimer = std::make_unique(Timer::Type::Once, []{ onScanTimerCallback(); }); scanTimer->start(10); diff --git a/Tactility/Source/lvgl/EspLvglPort.cpp b/Tactility/Source/lvgl/EspLvglPort.cpp index f7f0f945..f4ce55e6 100644 --- a/Tactility/Source/lvgl/EspLvglPort.cpp +++ b/Tactility/Source/lvgl/EspLvglPort.cpp @@ -2,23 +2,23 @@ #include #include +#include #include // LVGL // The minimum task stack seems to be about 3500, but that crashes the wifi app in some scenarios // At 8192, it sometimes crashes when wifi-auto enables and is busy connecting and then you open WifiManage #define TDECK_LVGL_TASK_STACK_DEPTH 9216 -#define TAG "lvgl" +auto constexpr TAG = "lvgl"; namespace tt::lvgl { bool initEspLvglPort() { TT_LOG_D(TAG, "Port init"); - static lv_disp_t* display = nullptr; const lvgl_port_cfg_t lvgl_cfg = { .task_priority = static_cast(Thread::Priority::Critical), .task_stack = TDECK_LVGL_TASK_STACK_DEPTH, - .task_affinity = 1, // -1 = disabled, 0 = core 1, 1 = core 2 + .task_affinity = getCpuAffinityConfiguration().graphics, .task_max_sleep_ms = 500, .timer_period_ms = 5 }; @@ -28,7 +28,7 @@ bool initEspLvglPort() { return false; } - tt::lvgl::syncSet(&lvgl_port_lock, &lvgl_port_unlock); + syncSet(&lvgl_port_lock, &lvgl_port_unlock); return true; } diff --git a/Tactility/Source/lvgl/Lvgl.cpp b/Tactility/Source/lvgl/Lvgl.cpp index 4bdf8f22..54777efe 100644 --- a/Tactility/Source/lvgl/Lvgl.cpp +++ b/Tactility/Source/lvgl/Lvgl.cpp @@ -13,7 +13,6 @@ #endif #include -#include #include #include #include diff --git a/Tactility/Source/service/screenshot/ScreenshotTask.cpp b/Tactility/Source/service/screenshot/ScreenshotTask.cpp index 8ce2a361..4780c528 100644 --- a/Tactility/Source/service/screenshot/ScreenshotTask.cpp +++ b/Tactility/Source/service/screenshot/ScreenshotTask.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace tt::service::screenshot { @@ -109,10 +110,11 @@ void ScreenshotTask::taskStart() { thread = new Thread( "screenshot", 8192, - [this]() { + [this] { this->taskMain(); return 0; - } + }, + getCpuAffinityConfiguration().graphics ); thread->start(); } diff --git a/TactilityCore/Include/Tactility/CpuAffinity.h b/TactilityCore/Include/Tactility/CpuAffinity.h new file mode 100644 index 00000000..1408a3d5 --- /dev/null +++ b/TactilityCore/Include/Tactility/CpuAffinity.h @@ -0,0 +1,27 @@ +#pragma once + +#include "RtosCompat.h" + +namespace tt { + +typedef portBASE_TYPE CpuAffinity; + +constexpr static CpuAffinity None = -1; + +/** + * Determines the preferred affinity for certain (sub)systems. + */ +struct CpuAffinityConfiguration { + CpuAffinity system; + CpuAffinity graphics; // Display, LVGL + CpuAffinity wifi; + CpuAffinity mainDispatcher; + CpuAffinity apps; + CpuAffinity timer; // Tactility Timer (based on FreeRTOS) +}; + +void setCpuAffinityConfiguration(const CpuAffinityConfiguration& config); + +const CpuAffinityConfiguration& getCpuAffinityConfiguration(); + +} diff --git a/TactilityCore/Include/Tactility/Timer.h b/TactilityCore/Include/Tactility/Timer.h index 285b5ea3..2d58bf69 100644 --- a/TactilityCore/Include/Tactility/Timer.h +++ b/TactilityCore/Include/Tactility/Timer.h @@ -18,7 +18,7 @@ public: private: struct TimerHandleDeleter { - void operator()(TimerHandle_t handleToDelete) { + void operator()(TimerHandle_t handleToDelete) const { xTimerDelete(handleToDelete, portMAX_DELAY); } }; diff --git a/TactilityCore/Source/CpuAffinity.cpp b/TactilityCore/Source/CpuAffinity.cpp new file mode 100644 index 00000000..290c1df6 --- /dev/null +++ b/TactilityCore/Source/CpuAffinity.cpp @@ -0,0 +1,85 @@ +#include "Tactility/CpuAffinity.h" + +#include + +namespace tt { + +#ifdef ESP_PLATFORM + +static CpuAffinity getEspWifiAffinity() { +#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 + return 0; +#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1) + return 1; +#endif +} + +// Warning: Must watch ESP WiFi, as this task is used by WiFi +static CpuAffinity getEspMainSchedulerAffinity() { +#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0 + return 0; +#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1) + return 1; +#endif +} + +static CpuAffinity getFreeRtosTimerAffinity() { +#if defined(CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY) + return None; +#elif defined(CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU0) + return 0; +#elif defined(CONFIG_FREERTOS_TIMER_TASK_AFFINITY_CPU1) + return 1; +#else + static_assert(false); +#endif +} + +#if CONFIG_FREERTOS_NUMBER_OF_CORES == 1 +static const CpuAffinityConfiguration esp = { + .system = 0, + .graphics = 0, + .wifi = 0, + .mainDispatcher = 0, + .apps = 0, + .timer = getFreeRtosTimerAffinity() +}; +#elif CONFIG_FREERTOS_NUMBER_OF_CORES == 2 +static const CpuAffinityConfiguration esp = { + .system = 0, + .graphics = 1, + .wifi = getEspWifiAffinity(), + .mainDispatcher = getEspMainSchedulerAffinity(), + .apps = 1, + .timer = getFreeRtosTimerAffinity() +}; +#endif + +#else + +static const CpuAffinityConfiguration simulator = { + .system = None, + .graphics = None, + .wifi = None, + .mainDispatcher = 0, + .apps = None, + .timer = None +}; + +#endif + +const CpuAffinityConfiguration& getCpuAffinityConfiguration() { +#ifdef ESP_PLATFORM + +#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2 + // WiFi uses the main dispatcher to defer operations in the background + assert(esp.wifi == esp.mainDispatcher); +#endif // CORES + return esp; + +#else + return simulator; +#endif +} + +} diff --git a/TactilityCore/Source/Timer.cpp b/TactilityCore/Source/Timer.cpp index 1ce15502..7478ee0c 100644 --- a/TactilityCore/Source/Timer.cpp +++ b/TactilityCore/Source/Timer.cpp @@ -13,7 +13,7 @@ void Timer::onCallback(TimerHandle_t hTimer) { } } -static inline TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCallbackFunction_t callback) { +static TimerHandle_t createTimer(Timer::Type type, void* timerId, TimerCallbackFunction_t callback) { assert(timerId != nullptr); assert(callback != nullptr);