sys_view: Adds heap tracing API

This commit is contained in:
Alexey Gerenkov 2018-12-12 20:35:17 +03:00
parent 335576013e
commit 5ef3a64c00
13 changed files with 399 additions and 12 deletions

View file

@ -13,11 +13,17 @@ if(CONFIG_SYSVIEW_ENABLE)
list(APPEND COMPONENT_SRCS "sys_view/SEGGER/SEGGER_SYSVIEW.c"
"sys_view/Sample/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c"
"sys_view/Sample/OS/SEGGER_SYSVIEW_FreeRTOS.c"
"sys_view/esp32/SEGGER_RTT_esp32.c")
"sys_view/esp32/SEGGER_RTT_esp32.c"
"sys_view/ext/heap_trace_module.c"
"sys_view/ext/logging.c")
endif()
if(CONFIG_HEAP_TRACING_TOHOST)
list(APPEND COMPONENT_SRCS "heap_trace_tohost.c")
endif()
set(COMPONENT_REQUIRES)
set(COMPONENT_PRIV_REQUIRES)
set(COMPONENT_PRIV_REQUIRES heap)
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
register_component()

View file

@ -107,6 +107,14 @@ menu "Application Level Tracing"
help
Configures maximum supported tasks in sysview debug
config SYSVIEW_BUF_WAIT_TMO
int "Trace buffer wait timeout"
depends on SYSVIEW_ENABLE
default 500
help
Configures timeout (in us) to wait for free space in trace buffer.
Set to -1 to wait forever and avoid lost events.
config SYSVIEW_EVT_OVERFLOW_ENABLE
bool "Trace Buffer Overflow Event"
depends on SYSVIEW_ENABLE

View file

@ -23,7 +23,8 @@ COMPONENT_SRCDIRS += \
sys_view/SEGGER \
sys_view/Sample/OS \
sys_view/Sample/Config \
sys_view/esp32
sys_view/esp32 \
sys_view/ext
else
COMPONENT_SRCDIRS += gcov
endif

View file

@ -0,0 +1,114 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <sdkconfig.h>
#define HEAP_TRACE_SRCFILE /* don't warn on inclusion here */
#include "esp_heap_trace.h"
#undef HEAP_TRACE_SRCFILE
#if CONFIG_SYSVIEW_ENABLE
#include "esp_app_trace.h"
#include "esp_sysview_trace.h"
#endif
#define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
#ifdef CONFIG_HEAP_TRACING_TOHOST
#if !CONFIG_SYSVIEW_ENABLE
#error None of the heap tracing backends is enabled! You must enable SystemView compatible tracing to use this feature.
#endif
static bool s_tracing;
esp_err_t heap_trace_init_tohost()
{
if (s_tracing) {
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}
esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
{
#if CONFIG_SYSVIEW_ENABLE
esp_err_t ret = esp_sysview_heap_trace_start((uint32_t)-1);
if (ret != ESP_OK) {
return ret;
}
#endif
s_tracing = true;
return ESP_OK;
}
esp_err_t heap_trace_stop(void)
{
esp_err_t ret = ESP_ERR_NOT_SUPPORTED;
#if CONFIG_SYSVIEW_ENABLE
ret = esp_sysview_heap_trace_stop();
#endif
s_tracing = false;
return ret;
}
esp_err_t heap_trace_resume(void)
{
return heap_trace_start(HEAP_TRACE_ALL);
}
size_t heap_trace_get_count(void)
{
return 0;
}
esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
{
return ESP_ERR_NOT_SUPPORTED;
}
void heap_trace_dump(void)
{
return;
}
/* Add a new allocation to the heap trace records */
static IRAM_ATTR void record_allocation(const heap_trace_record_t *record)
{
if (!s_tracing) {
return;
}
#if CONFIG_SYSVIEW_ENABLE
esp_sysview_heap_trace_alloc(record->address, record->size, record->alloced_by);
#endif
}
/* record a free event in the heap trace log
For HEAP_TRACE_ALL, this means filling in the freed_by pointer.
For HEAP_TRACE_LEAKS, this means removing the record from the log.
*/
static IRAM_ATTR void record_free(void *p, void **callers)
{
if (!s_tracing) {
return;
}
#if CONFIG_SYSVIEW_ENABLE
esp_sysview_heap_trace_free(p, callers);
#endif
}
#include "heap_trace.inc"
#endif /*CONFIG_HEAP_TRACING_TOHOST*/

View file

@ -0,0 +1,80 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ESP_SYSVIEW_TRACE_H_
#define ESP_SYSVIEW_TRACE_H_
#include <stdarg.h>
#include "esp_err.h"
#include "SEGGER_RTT.h" // SEGGER_RTT_ESP32_Flush
#include "esp_app_trace_util.h" // ESP_APPTRACE_TMO_INFINITE
/**
* @brief Flushes remaining data in SystemView trace buffer to host.
*
* @param tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
*
* @return ESP_OK.
*/
static inline esp_err_t esp_sysview_flush(uint32_t tmo)
{
SEGGER_RTT_ESP32_Flush(0, tmo);
return ESP_OK;
}
/**
* @brief vprintf-like function to sent log messages to the host.
*
* @param format Address of format string.
* @param args List of arguments.
*
* @return Number of bytes written.
*/
int esp_sysview_vprintf(const char * format, va_list args);
/**
* @brief Starts SystemView heap tracing.
*
* @param tmo Timeout (in us) to wait for the host to be connected. Use -1 to wait forever.
*
* @return ESP_OK on success, ESP_ERR_TIMEOUT if operation has been timed out.
*/
esp_err_t esp_sysview_heap_trace_start(uint32_t tmo);
/**
* @brief Stops SystemView heap tracing.
*
* @return ESP_OK.
*/
esp_err_t esp_sysview_heap_trace_stop(void);
/**
* @brief Sends heap allocation event to the host.
*
* @param addr Address of allocated block.
* @param size Size of allocated block.
* @param callers Pointer to array with callstack addresses.
* Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.
*/
void esp_sysview_heap_trace_alloc(void *addr, uint32_t size, const void *callers);
/**
* @brief Sends heap de-allocation event to the host.
*
* @param addr Address of de-allocated block.
* @param callers Pointer to array with callstack addresses.
* Array size must be CONFIG_HEAP_TRACING_STACK_DEPTH.
*/
void esp_sysview_heap_trace_free(void *addr, const void *callers);
#endif //ESP_SYSVIEW_TRACE_H_

View file

@ -1,7 +1,12 @@
[mapping]
archive: libapp_trace.a
entries:
* (noflash)
app_trace (noflash)
app_trace_util (noflash)
SEGGER_SYSVIEW (noflash)
SEGGER_RTT_esp32 (noflash)
SEGGER_SYSVIEW_Config_FreeRTOS (noflash)
SEGGER_SYSVIEW_FreeRTOS (noflash)
[mapping]
archive: libdriver.a

View file

@ -160,6 +160,7 @@ unsigned SEGGER_RTT_WriteSkipNoLock (unsigned BufferIndex, const voi
unsigned SEGGER_RTT_WriteString (unsigned BufferIndex, const char* s);
void SEGGER_RTT_WriteWithOverwriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes);
void SEGGER_RTT_ESP32_FlushNoLock (unsigned long min_sz, unsigned long tmo);
void SEGGER_RTT_ESP32_Flush (unsigned long min_sz, unsigned long tmo);
//
// Function macro for performance optimization
//

View file

@ -1689,6 +1689,10 @@ void SEGGER_SYSVIEW_Stop(void) {
RECORD_END();
}
U8 SEGGER_SYSVIEW_Started(void) {
return _SYSVIEW_Globals.EnableState;
}
/*********************************************************************
*
* SEGGER_SYSVIEW_GetSysDesc()
@ -2678,7 +2682,7 @@ void SEGGER_SYSVIEW_ErrorfTarget(const char* s, ...) {
void SEGGER_SYSVIEW_Print(const char* s) {
U8* pPayload;
U8* pPayloadStart;
RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN);
RECORD_START(SEGGER_SYSVIEW_INFO_SIZE + 2 * SEGGER_SYSVIEW_QUANTA_U32 + SEGGER_SYSVIEW_MAX_STRING_LEN + 3/*1 or 3 bytes for string length*/);
//
pPayload = _EncodeStr(pPayloadStart, s, SEGGER_SYSVIEW_MAX_STRING_LEN);
ENCODE_U32(pPayload, SEGGER_SYSVIEW_LOG);

View file

@ -230,6 +230,8 @@ void SEGGER_SYSVIEW_GetSysDesc (void);
void SEGGER_SYSVIEW_SendTaskList (void);
void SEGGER_SYSVIEW_SendTaskInfo (const SEGGER_SYSVIEW_TASKINFO* pInfo);
void SEGGER_SYSVIEW_SendSysDesc (const char* sSysDesc);
// Checks whether tracing has been started
U8 SEGGER_SYSVIEW_Started(void);
/*********************************************************************
*

View file

@ -16,6 +16,7 @@
#include "freertos/FreeRTOS.h"
#include "SEGGER_RTT.h"
#include "SEGGER_SYSVIEW.h"
#include "SEGGER_SYSVIEW_Conf.h"
#include "esp32/rom/ets_sys.h"
#include "esp_app_trace.h"
@ -27,8 +28,12 @@ const static char *TAG = "segger_rtt";
// size of down channel data buf
#define SYSVIEW_DOWN_BUF_SIZE 32
#define SEGGER_HOST_WAIT_TMO 500 //us
#define SEGGER_STOP_WAIT_TMO 1000000 //us
#if CONFIG_SYSVIEW_BUF_WAIT_TMO == -1
#define SEGGER_HOST_WAIT_TMO ESP_APPTRACE_TMO_INFINITE
#else
#define SEGGER_HOST_WAIT_TMO CONFIG_SYSVIEW_BUF_WAIT_TMO
#endif
static uint8_t s_events_buf[SYSVIEW_EVENTS_BUF_SZ];
static uint16_t s_events_buf_filled;
@ -57,9 +62,12 @@ static uint8_t s_down_buf[SYSVIEW_DOWN_BUF_SIZE];
*/
void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
{
esp_err_t res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, tmo);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res);
esp_err_t res;
if (s_events_buf_filled > 0) {
res = esp_apptrace_write(ESP_APPTRACE_DEST_TRAX, s_events_buf, s_events_buf_filled, tmo);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Failed to flush buffered events (%d)!\n", res);
}
}
// flush even if we failed to write buffered events, because no new events will be sent after STOP
res = esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, min_sz, tmo);
@ -69,6 +77,27 @@ void SEGGER_RTT_ESP32_FlushNoLock(unsigned long min_sz, unsigned long tmo)
s_events_buf_filled = 0;
}
/*********************************************************************
*
* SEGGER_RTT_ESP32_Flush()
*
* Function description
* Flushes buffered events.
*
* Parameters
* min_sz Threshold for flushing data. If current filling level is above this value, data will be flushed. TRAX destinations only.
* tmo Timeout for operation (in us). Use ESP_APPTRACE_TMO_INFINITE to wait indefinetly.
*
* Return value
* None.
*/
void SEGGER_RTT_ESP32_Flush(unsigned long min_sz, unsigned long tmo)
{
SEGGER_SYSVIEW_LOCK();
SEGGER_RTT_ESP32_FlushNoLock(min_sz, tmo);
SEGGER_SYSVIEW_UNLOCK();
}
/*********************************************************************
*
* SEGGER_RTT_ReadNoLock()

View file

@ -0,0 +1,100 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <sdkconfig.h>
#include "SEGGER_SYSVIEW.h"
#include "SEGGER_RTT.h"
#include "esp_app_trace.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
const static char *TAG = "sysview_heap_trace";
#ifdef CONFIG_HEAP_TRACING_STACK_DEPTH
#define CALLSTACK_SIZE CONFIG_HEAP_TRACING_STACK_DEPTH
#else
#define CALLSTACK_SIZE 0
#endif
static SEGGER_SYSVIEW_MODULE s_esp_sysview_heap_module = {
.sModule = "ESP32 SystemView Heap Tracing Module",
.NumEvents = 2,
};
static bool s_mod_registered;
esp_err_t esp_sysview_heap_trace_start(uint32_t tmo)
{
uint32_t tmo_ticks = tmo/(1000*portTICK_PERIOD_MS);
ESP_EARLY_LOGV(TAG, "%s", __func__);
do {
if (tmo != (uint32_t)-1) {
// Currently timeout implementation is simple and has granularity of 1 OS tick,
// so just count down the number of times to call vTaskDelay
if (tmo_ticks-- == 0) {
return ESP_ERR_TIMEOUT;
}
}
vTaskDelay(1);
} while(!SEGGER_SYSVIEW_Started());
SEGGER_SYSVIEW_RegisterModule(&s_esp_sysview_heap_module);
s_mod_registered = true;
return ESP_OK;
}
esp_err_t esp_sysview_heap_trace_stop(void)
{
ESP_EARLY_LOGV(TAG, "%s", __func__);
SEGGER_RTT_ESP32_Flush(0, ESP_APPTRACE_TMO_INFINITE);
return ESP_OK;
}
void esp_sysview_heap_trace_alloc(const void *addr, uint32_t size, const void *callers)
{
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + (2+CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];
U8* pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
U32 *calls = (U32 *)callers;
if (!s_mod_registered) {
return;
}
ESP_EARLY_LOGV(TAG, "%s %p %lu", __func__, addr, size);
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, size);
for (int i = 0; i < CALLSTACK_SIZE; i++) {
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);
}
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 0);
}
void esp_sysview_heap_trace_free(const void *addr, const void *callers)
{
U8 aPacket[SEGGER_SYSVIEW_INFO_SIZE + (1+CALLSTACK_SIZE)*SEGGER_SYSVIEW_QUANTA_U32];
U8* pPayload = SEGGER_SYSVIEW_PREPARE_PACKET(aPacket);
U32 *calls = (U32 *)callers;
if (!s_mod_registered) {
return;
}
ESP_EARLY_LOGV(TAG, "%s %p", __func__, addr);
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, (U32)addr);
for (int i = 0; i < CALLSTACK_SIZE; i++) {
pPayload = SEGGER_SYSVIEW_EncodeU32(pPayload, calls[i]);
}
SEGGER_SYSVIEW_SendPacket(&aPacket[0], pPayload, s_esp_sysview_heap_module.EventOffset + 1);
}

View file

@ -0,0 +1,34 @@
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdarg.h>
#include <sdkconfig.h>
#include "SEGGER_SYSVIEW_Int.h"
#include "freertos/FreeRTOS.h"
static portMUX_TYPE s_log_mutex = portMUX_INITIALIZER_UNLOCKED;
int esp_sysview_vprintf(const char * format, va_list args)
{
static char log_buffer[SEGGER_SYSVIEW_MAX_STRING_LEN];
portENTER_CRITICAL(&s_log_mutex);
size_t len = vsnprintf(log_buffer, sizeof(log_buffer), format, args);
if (len > sizeof(log_buffer) - 1) {
log_buffer[sizeof(log_buffer - 1)] = 0;
}
SEGGER_SYSVIEW_Print(log_buffer);
portEXIT_CRITICAL(&s_log_mutex);
return len;
}

View file

@ -198,9 +198,12 @@ void app_main()
#if CONFIG_SYSVIEW_ENABLE && CONFIG_USE_CUSTOM_EVENT_ID
// Currently OpenOCD does not support requesting module info from target. So do the following...
// Give SystemView tracing module some time to handle START command from host,
// after that data can be sent to the host using onboard API, so user module description does not need to be requested by OpenOCD itself.
vTaskDelay(1);
// Wait untill SystemView module receives START command from host,
// after that data can be sent to the host using onboard API,
// so user module description does not need to be requested by OpenOCD itself.
while(!SEGGER_SYSVIEW_Started()) {
vTaskDelay(1);
}
SEGGER_SYSVIEW_RegisterModule(&s_example_sysview_module);
#endif