gcov: add gcov callback into the ipc task

This commit is contained in:
Erhan Kurubas 2021-06-29 13:12:01 +03:00
parent 49942a9468
commit fd8b943619
4 changed files with 63 additions and 16 deletions

View File

@ -30,7 +30,7 @@ endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
PRIV_REQUIRES soc
PRIV_REQUIRES soc esp_ipc
LDFRAGMENTS linker.lf)

View File

@ -24,7 +24,8 @@
#include "esp_app_trace.h"
#include "esp_freertos_hooks.h"
#include "esp_private/dbg_stubs.h"
#include "hal/timer_ll.h"
#include "esp_ipc.h"
#include "hal/wdt_hal.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/libc_stubs.h"
#elif CONFIG_IDF_TARGET_ESP32S2BETA
@ -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));
}

View File

@ -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) {

View File

@ -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 uint32_t cpuid = (uint32_t) 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();
@ -144,3 +160,17 @@ 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