From f5b297a654e605654aa378fed73c6c2077ed67ea Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 29 Jun 2021 13:12:01 +0300 Subject: [PATCH] gcov: add gcov callback into the ipc task --- components/app_trace/CMakeLists.txt | 3 +- components/app_trace/gcov/gcov_rtio.c | 26 +++++++++++--- components/esp_common/src/dbg_stubs.c | 1 + components/esp_ipc/ipc.c | 49 ++++++++++++++++++++++----- 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/components/app_trace/CMakeLists.txt b/components/app_trace/CMakeLists.txt index e54533a468..20b8277c08 100644 --- a/components/app_trace/CMakeLists.txt +++ b/components/app_trace/CMakeLists.txt @@ -30,7 +30,8 @@ endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "${include_dirs}" - PRIV_REQUIRES soc + PRIV_INCLUDE_DIRS "${priv_include_dirs}" + PRIV_REQUIRES soc esp_ipc LDFRAGMENTS linker.lf) diff --git a/components/app_trace/gcov/gcov_rtio.c b/components/app_trace/gcov/gcov_rtio.c index dcfdf23a2d..f789a004f9 100644 --- a/components/app_trace/gcov/gcov_rtio.c +++ b/components/app_trace/gcov/gcov_rtio.c @@ -24,6 +24,7 @@ #include "esp_app_trace.h" #include "esp_freertos_hooks.h" #include "esp_private/dbg_stubs.h" +#include "esp_ipc.h" #include "hal/wdt_hal.h" #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/libc_stubs.h" @@ -49,6 +50,8 @@ void gcov_dump_task(void *pvParameter) int dump_result = 0; bool *running = (bool *)pvParameter; + ESP_EARLY_LOGV(TAG, "%s stack use in %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL)); + ESP_EARLY_LOGV(TAG, "Alloc apptrace down buf %d bytes", ESP_GCOV_DOWN_BUF_SIZE); void *down_buf = malloc(ESP_GCOV_DOWN_BUF_SIZE); if (down_buf == NULL) { @@ -81,14 +84,25 @@ gcov_exit: if (running) { *running = false; } + + ESP_EARLY_LOGV(TAG, "%s stack use out %d", __FUNCTION__, uxTaskGetStackHighWaterMark(NULL)); + vTaskDelete(NULL); } -static void gcov_create_task_hook(void) +void gcov_create_task(void *arg) { + ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__); + xTaskCreatePinnedToCore(&gcov_dump_task, "gcov_dump_task", 2048, (void *)&s_gcov_task_running, configMAX_PRIORITIES - 1, NULL, 0); +} + +void gcov_create_task_tick_hook(void) +{ + extern esp_err_t esp_ipc_start_gcov_from_isr(uint32_t cpu_id, esp_ipc_func_t func, void* arg); if (s_create_gcov_task) { - xTaskCreatePinnedToCore(&gcov_dump_task, "gcov_dump_task", 2048, &s_gcov_task_running, configMAX_PRIORITIES - 1, NULL, 0); - s_create_gcov_task = false; + if (esp_ipc_start_gcov_from_isr(xPortGetCoreID(), &gcov_create_task, NULL) == ESP_OK) { + s_create_gcov_task = false; + } } } @@ -114,19 +128,21 @@ int gcov_rtio_atexit(void (*function)(void) __attribute__ ((unused))) if (esp_dbg_stub_entry_get(ESP_DBG_STUB_CAPABILITIES, &capabilities) == ESP_OK) { esp_dbg_stub_entry_set(ESP_DBG_STUB_CAPABILITIES, capabilities | ESP_DBG_STUB_CAP_GCOV_TASK); } - esp_register_freertos_tick_hook(gcov_create_task_hook); + esp_register_freertos_tick_hook(gcov_create_task_tick_hook); return ESP_OK; } void esp_gcov_dump(void) { + ESP_EARLY_LOGV(TAG, "%s", __FUNCTION__); + while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) { vTaskDelay(pdMS_TO_TICKS(10)); } /* We are not in isr context here. Waiting for the completion is safe */ - s_create_gcov_task = true; s_gcov_task_running = true; + s_create_gcov_task = true; while (s_gcov_task_running) { vTaskDelay(pdMS_TO_TICKS(10)); } diff --git a/components/esp_common/src/dbg_stubs.c b/components/esp_common/src/dbg_stubs.c index e4c65c22e2..a1740c23e6 100644 --- a/components/esp_common/src/dbg_stubs.c +++ b/components/esp_common/src/dbg_stubs.c @@ -82,6 +82,7 @@ void esp_dbg_stubs_init(void) ESP_LOGV(TAG, "%s stubs %x", __func__, eri_read(ESP_DBG_STUBS_TRAX_REG)); } +// TODO: add lock mechanism. Not now but in the future ESP_DBG_STUB_CAPABILITIES can be set from different places. esp_err_t esp_dbg_stub_entry_set(esp_dbg_stub_id_t id, uint32_t entry) { if (id < ESP_DBG_STUB_ENTRY_FIRST || id >= ESP_DBG_STUB_ENTRY_MAX) { diff --git a/components/esp_ipc/ipc.c b/components/esp_ipc/ipc.c index 4ec94b16ec..e011c04b84 100644 --- a/components/esp_ipc/ipc.c +++ b/components/esp_ipc/ipc.c @@ -28,7 +28,7 @@ static TaskHandle_t s_ipc_task_handle[portNUM_PROCESSORS]; static SemaphoreHandle_t s_ipc_mutex[portNUM_PROCESSORS]; // This mutex is used as a global lock for esp_ipc_* APIs static SemaphoreHandle_t s_ipc_sem[portNUM_PROCESSORS]; // Two semaphores used to wake each of ipc tasks static SemaphoreHandle_t s_ipc_ack[portNUM_PROCESSORS]; // Semaphore used to acknowledge that task was woken up, - // or function has finished running + // or function has finished running static volatile esp_ipc_func_t s_func[portNUM_PROCESSORS]; // Function which should be called by high priority task static void * volatile s_func_arg[portNUM_PROCESSORS]; // Argument to pass into s_func typedef enum { @@ -40,6 +40,11 @@ static volatile esp_ipc_wait_t s_ipc_wait[portNUM_PROCESSORS];// This variable t // s_ipc_ack semaphore: before s_func is called, or // after it returns +#if CONFIG_APPTRACE_GCOV_ENABLE +static volatile esp_ipc_func_t s_gcov_func = NULL; // Gcov dump starter function which should be called by high priority task +static void * volatile s_gcov_func_arg; // Argument to pass into s_gcov_func +#endif + static void IRAM_ATTR ipc_task(void* arg) { const int cpuid = (int) arg; @@ -53,16 +58,26 @@ static void IRAM_ATTR ipc_task(void* arg) abort(); } - esp_ipc_func_t func = s_func[cpuid]; - void* arg = s_func_arg[cpuid]; +#if CONFIG_APPTRACE_GCOV_ENABLE + if (s_gcov_func) { + (*s_gcov_func)(s_gcov_func_arg); + s_gcov_func = NULL; + } +#endif + if (s_func[cpuid]) { + esp_ipc_func_t func = s_func[cpuid]; + void* arg = s_func_arg[cpuid]; - if (s_ipc_wait[cpuid] == IPC_WAIT_FOR_START) { - xSemaphoreGive(s_ipc_ack[cpuid]); - } - (*func)(arg); - if (s_ipc_wait[cpuid] == IPC_WAIT_FOR_END) { - xSemaphoreGive(s_ipc_ack[cpuid]); + if (s_ipc_wait[cpuid] == IPC_WAIT_FOR_START) { + xSemaphoreGive(s_ipc_ack[cpuid]); + } + (*func)(arg); + if (s_ipc_wait[cpuid] == IPC_WAIT_FOR_END) { + xSemaphoreGive(s_ipc_ack[cpuid]); + } + s_func[cpuid] = NULL; } + } // TODO: currently this is unreachable code. Introduce esp_ipc_uninit // function which will signal to both tasks that they can shut down. @@ -87,6 +102,7 @@ static void esp_ipc_init(void) __attribute__((constructor)); static void esp_ipc_init(void) { char task_name[15]; + for (int i = 0; i < portNUM_PROCESSORS; ++i) { snprintf(task_name, sizeof(task_name), "ipc%d", i); s_ipc_mutex[i] = xSemaphoreCreateMutex(); @@ -143,3 +159,18 @@ esp_err_t esp_ipc_call_blocking(uint32_t cpu_id, esp_ipc_func_t func, void* arg) { return esp_ipc_call_and_wait(cpu_id, func, arg, IPC_WAIT_FOR_END); } + +// currently this is only called from gcov component +#if CONFIG_APPTRACE_GCOV_ENABLE +esp_err_t esp_ipc_start_gcov_from_isr(uint32_t cpu_id, esp_ipc_func_t func, void* arg) +{ + if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { + return ESP_ERR_INVALID_STATE; + } + s_gcov_func = func; + s_gcov_func_arg = arg; + xSemaphoreGiveFromISR(s_ipc_sem[cpu_id], NULL); + + return ESP_OK; +} +#endif