Merge branch 'feature/sysview_heap_tracing' into 'master'

SystemView based heap and log tracing

See merge request idf/esp-idf!3952
This commit is contained in:
Ivan Grokhotkov 2019-04-02 09:07:55 +08:00
commit fd91818074
78 changed files with 4515 additions and 3148 deletions

View file

@ -160,5 +160,4 @@ exclude =
components/wifi_provisioning/python/wifi_constants_pb2.py,
examples/provisioning/custom_config/components/custom_provisioning/python/custom_config_pb2.py,
# temporary list (should be empty)
tools/esp_app_trace/pylibelf,
tools/mass_mfg/mfg_gen.py,

View file

@ -643,6 +643,30 @@ test_espcoredump:
- cd components/espcoredump/test/
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_espcoredump.sh
test_logtrace_proc:
<<: *host_test_template
artifacts:
when: on_failure
paths:
- tools/esp_app_trace/test/logtrace/output
- tools/esp_app_trace/test/logtrace/.coverage
expire_in: 1 week
script:
- cd ${IDF_PATH}/tools/esp_app_trace/test/logtrace
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh
test_sysviewtrace_proc:
<<: *host_test_template
artifacts:
when: on_failure
paths:
- tools/esp_app_trace/test/sysview/output
- tools/esp_app_trace/test/sysview/.coverage
expire_in: 1 week
script:
- cd ${IDF_PATH}/tools/esp_app_trace/test/sysview
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test.sh
push_to_github:
stage: deploy
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG

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

@ -929,6 +929,9 @@ esp_err_t esp_apptrace_read(esp_apptrace_dest_t dest, void *buf, uint32_t *size,
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return ESP_ERR_NOT_SUPPORTED;
}
if (buf == NULL || size == NULL || *size == 0) {
return ESP_ERR_INVALID_ARG;
}
//TODO: callback system
esp_apptrace_tmo_init(&tmo, user_tmo);
@ -963,8 +966,10 @@ uint8_t *esp_apptrace_down_buffer_get(esp_apptrace_dest_t dest, uint32_t *size,
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return NULL;
}
if (size == NULL || *size == 0) {
return NULL;
}
// ESP_APPTRACE_LOGE("esp_apptrace_down_buffer_get %d", *size);
esp_apptrace_tmo_init(&tmo, user_tmo);
return hw->get_down_buffer(size, &tmo);
}
@ -985,6 +990,9 @@ esp_err_t esp_apptrace_down_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, u
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return ESP_ERR_NOT_SUPPORTED;
}
if (ptr == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_apptrace_tmo_init(&tmo, user_tmo);
return hw->put_down_buffer(ptr, &tmo);
@ -1007,6 +1015,9 @@ esp_err_t esp_apptrace_write(esp_apptrace_dest_t dest, const void *data, uint32_
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return ESP_ERR_NOT_SUPPORTED;
}
if (data == NULL || size == 0) {
return ESP_ERR_INVALID_ARG;
}
esp_apptrace_tmo_init(&tmo, user_tmo);
ptr = hw->get_up_buffer(size, &tmo);
@ -1040,6 +1051,9 @@ int esp_apptrace_vprintf_to(esp_apptrace_dest_t dest, uint32_t user_tmo, const c
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return ESP_ERR_NOT_SUPPORTED;
}
if (fmt == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_apptrace_tmo_init(&tmo, user_tmo);
ESP_APPTRACE_LOGD("fmt %x", fmt);
@ -1101,6 +1115,9 @@ uint8_t *esp_apptrace_buffer_get(esp_apptrace_dest_t dest, uint32_t size, uint32
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return NULL;
}
if (size == 0) {
return NULL;
}
esp_apptrace_tmo_init(&tmo, user_tmo);
return hw->get_up_buffer(size, &tmo);
@ -1122,6 +1139,9 @@ esp_err_t esp_apptrace_buffer_put(esp_apptrace_dest_t dest, uint8_t *ptr, uint32
ESP_APPTRACE_LOGE("Trace destinations other then TRAX are not supported yet!");
return ESP_ERR_NOT_SUPPORTED;
}
if (ptr == NULL) {
return ESP_ERR_INVALID_ARG;
}
esp_apptrace_tmo_init(&tmo, user_tmo);
return hw->put_up_buffer(ptr, &tmo);

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

@ -145,6 +145,9 @@ void *esp_apptrace_fopen(esp_apptrace_dest_t dest, const char *path, const char
esp_apptrace_fopen_args_t cmd_args;
ESP_EARLY_LOGV(TAG, "esp_apptrace_fopen '%s' '%s'", path, mode);
if (path == NULL || mode == NULL) {
return 0;
}
cmd_args.path = path;
cmd_args.path_len = strlen(path) + 1;
@ -213,6 +216,10 @@ size_t esp_apptrace_fwrite(esp_apptrace_dest_t dest, const void *ptr, size_t siz
ESP_EARLY_LOGV(TAG, "esp_apptrace_fwrite f %p l %d", stream, size*nmemb);
if (ptr == NULL) {
return 0;
}
cmd_args.buf = (void *)ptr;
cmd_args.size = size * nmemb;
cmd_args.file = stream;
@ -248,6 +255,10 @@ size_t esp_apptrace_fread(esp_apptrace_dest_t dest, void *ptr, size_t size, size
ESP_EARLY_LOGV(TAG, "esp_apptrace_fread f %p l %d", stream, size*nmemb);
if (ptr == NULL) {
return 0;
}
cmd_args.size = size * nmemb;
cmd_args.file = stream;
esp_err_t ret = esp_apptrace_file_cmd_send(dest, ESP_APPTRACE_FILE_CMD_FREAD, esp_apptrace_fread_args_prepare,

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

@ -244,8 +244,10 @@ Notes:
#define traceQUEUE_SEND( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), 0, 0, xCopyPosition)
#endif
#define traceQUEUE_SEND_FAILED( pxQueue ) SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSEND, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, xTicksToWait, xCopyPosition)
#define traceQUEUE_SEND_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
#define traceQUEUE_SEND_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, (U32)pxHigherPriorityTaskWoken, xCopyPosition)
#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x4(apiFastID_OFFSET + apiID_XQUEUEGENERICSENDFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pvItemToQueue, (U32)pxHigherPriorityTaskWoken, xCopyPosition)
#define traceQUEUE_GIVE_FROM_ISR( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
#define traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue ) SEGGER_SYSVIEW_RecordU32x2(apiFastID_OFFSET + apiID_XQUEUEGIVEFROMISR, SEGGER_SYSVIEW_ShrinkId((U32)pxQueue), (U32)pxHigherPriorityTaskWoken)
#if( portSTACK_GROWTH < 0 )
#define traceTASK_CREATE(pxNewTCB) if (pxNewTCB != NULL) { \

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

@ -514,6 +514,14 @@ extern "C" {
#define traceTASK_CREATE( pxNewTCB )
#endif
#ifndef traceQUEUE_GIVE_FROM_ISR
#define traceQUEUE_GIVE_FROM_ISR( pxQueue )
#endif
#ifndef traceQUEUE_GIVE_FROM_ISR_FAILED
#define traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue )
#endif
#ifndef traceTASK_CREATE_FAILED
#define traceTASK_CREATE_FAILED()
#endif

View file

@ -1333,7 +1333,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
space'. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
traceQUEUE_SEND_FROM_ISR( pxQueue );
traceQUEUE_GIVE_FROM_ISR( pxQueue );
/* A task can only have an inherited priority if it is a mutex
holder - and if there is a mutex holder then the mutex cannot be
@ -1427,7 +1427,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
}
else
{
traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue );
traceQUEUE_GIVE_FROM_ISR_FAILED( pxQueue );
xReturn = errQUEUE_FULL;
}
taskEXIT_CRITICAL_ISR(&pxQueue->mux);

View file

@ -1,6 +1,5 @@
set(COMPONENT_SRCS "heap_caps.c"
"heap_caps_init.c"
"heap_trace.c"
"multi_heap.c")
if(NOT CONFIG_HEAP_POISONING_DISABLED)
@ -11,6 +10,10 @@ if(CONFIG_HEAP_TASK_TRACKING)
list(APPEND COMPONENT_SRCS "heap_task_info.c")
endif()
if(CONFIG_HEAP_TRACING_STANDALONE)
list(APPEND COMPONENT_SRCS "heap_trace_standalone.c")
endif()
set(COMPONENT_ADD_INCLUDEDIRS "include")
set(COMPONENT_ADD_LDFRAGMENTS linker.lf)
set(COMPONENT_REQUIRES "")

View file

@ -17,14 +17,31 @@ menu "Heap memory debugging"
bool "Comprehensive"
endchoice
config HEAP_TRACING
bool "Enable heap tracing"
choice HEAP_TRACING_DEST
bool "Heap tracing"
default HEAP_TRACING_OFF
help
Enables the heap tracing API defined in esp_heap_trace.h.
This function causes a moderate increase in IRAM code side and a minor increase in heap function
(malloc/free/realloc) CPU overhead, even when the tracing feature is not used. So it's best to keep it
disabled unless tracing is being used.
(malloc/free/realloc) CPU overhead, even when the tracing feature is not used.
So it's best to keep it disabled unless tracing is being used.
config HEAP_TRACING_OFF
bool "Disabled"
config HEAP_TRACING_STANDALONE
bool "Standalone"
select HEAP_TRACING
config HEAP_TRACING_TOHOST
bool "Host-based"
select HEAP_TRACING
endchoice
config HEAP_TRACING
bool
default F
help
Enables/disables heap tracing API.
config HEAP_TRACING_STACK_DEPTH
int "Heap tracing stack depth"

View file

@ -2,7 +2,7 @@
# Component Makefile
#
COMPONENT_OBJS := heap_caps_init.o heap_caps.o multi_heap.o heap_trace.o
COMPONENT_OBJS := heap_caps_init.o heap_caps.o multi_heap.o
ifndef CONFIG_HEAP_POISONING_DISABLED
COMPONENT_OBJS += multi_heap_poisoning.o
@ -12,6 +12,12 @@ COMPONENT_OBJS += heap_task_info.o
endif
endif
ifdef CONFIG_HEAP_TRACING_STANDALONE
COMPONENT_OBJS += heap_trace_standalone.o
endif
ifdef CONFIG_HEAP_TRACING
WRAP_FUNCTIONS = calloc malloc free realloc heap_caps_malloc heap_caps_free heap_caps_realloc heap_caps_malloc_default heap_caps_realloc_default

View file

@ -12,23 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include <sys/param.h>
#include <sdkconfig.h>
#define HEAP_TRACE_SRCFILE /* don't warn on inclusion here */
#include "esp_heap_trace.h"
#undef HEAP_TRACE_SRCFILE
#include "esp_heap_caps.h"
#include "esp_attr.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "soc/soc_memory_layout.h"
#include "heap_private.h"
#define STACK_DEPTH CONFIG_HEAP_TRACING_STACK_DEPTH
#if CONFIG_HEAP_TRACING_STANDALONE
static portMUX_TYPE trace_mux = portMUX_INITIALIZER_UNLOCKED;
static bool tracing;
static heap_trace_mode_t mode;
@ -55,10 +53,6 @@ static bool has_overflowed = false;
esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records)
{
#ifndef CONFIG_HEAP_TRACING
return ESP_ERR_NOT_SUPPORTED;
#endif
if (tracing) {
return ESP_ERR_INVALID_STATE;
}
@ -70,13 +64,10 @@ esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t
esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
{
#ifndef CONFIG_HEAP_TRACING
return ESP_ERR_NOT_SUPPORTED;
#endif
if (buffer == NULL || total_records == 0) {
return ESP_ERR_INVALID_STATE;
}
portENTER_CRITICAL(&trace_mux);
tracing = false;
@ -93,9 +84,6 @@ esp_err_t heap_trace_start(heap_trace_mode_t mode_param)
static esp_err_t set_tracing(bool enable)
{
#ifndef CONFIG_HEAP_TRACING
return ESP_ERR_NOT_SUPPORTED;
#endif
if (tracing == enable) {
return ESP_ERR_INVALID_STATE;
}
@ -120,9 +108,6 @@ size_t heap_trace_get_count(void)
esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
{
#ifndef CONFIG_HEAP_TRACING
return ESP_ERR_NOT_SUPPORTED;
#endif
if (record == NULL) {
return ESP_ERR_INVALID_STATE;
}
@ -141,10 +126,6 @@ esp_err_t heap_trace_get(size_t index, heap_trace_record_t *record)
void heap_trace_dump(void)
{
#ifndef CONFIG_HEAP_TRACING
printf("no data, heap tracing is disabled.\n");
return;
#endif
size_t delta_size = 0;
size_t delta_allocs = 0;
printf("%u allocations trace (%u entry buffer)\n",
@ -192,6 +173,10 @@ void heap_trace_dump(void)
/* Add a new allocation to the heap trace records */
static IRAM_ATTR void record_allocation(const heap_trace_record_t *record)
{
if (!tracing || record->address == NULL) {
return;
}
portENTER_CRITICAL(&trace_mux);
if (tracing) {
if (count == total_records) {
@ -224,6 +209,10 @@ static void remove_record(int index);
*/
static IRAM_ATTR void record_free(void *p, void **callers)
{
if (!tracing || p == NULL) {
return;
}
portENTER_CRITICAL(&trace_mux);
if (tracing && count > 0) {
total_frees++;
@ -261,179 +250,6 @@ static IRAM_ATTR void remove_record(int index)
count--;
}
/* Encode the CPU ID in the LSB of the ccount value */
inline static uint32_t get_ccount(void)
{
uint32_t ccount = xthal_get_ccount() & ~3;
#ifndef CONFIG_FREERTOS_UNICORE
ccount |= xPortGetCoreID();
#endif
return ccount;
}
#include "heap_trace.inc"
// Caller is 2 stack frames deeper than we care about
#define STACK_OFFSET 2
#define TEST_STACK(N) do { \
if (STACK_DEPTH == N) { \
return; \
} \
callers[N] = __builtin_return_address(N+STACK_OFFSET); \
if (!esp_ptr_executable(callers[N])) { \
return; \
} \
} while(0)
/* Static function to read the call stack for a traced heap call.
Calls to __builtin_return_address are "unrolled" via TEST_STACK macro as gcc requires the
argument to be a compile-time constant.
*/
static IRAM_ATTR __attribute__((noinline)) void get_call_stack(void **callers)
{
bzero(callers, sizeof(void *) * STACK_DEPTH);
TEST_STACK(0);
TEST_STACK(1);
TEST_STACK(2);
TEST_STACK(3);
TEST_STACK(4);
TEST_STACK(5);
TEST_STACK(6);
TEST_STACK(7);
TEST_STACK(8);
TEST_STACK(9);
}
_Static_assert(STACK_DEPTH >= 0 && STACK_DEPTH <= 10, "CONFIG_HEAP_TRACING_STACK_DEPTH must be in range 0-10");
typedef enum {
TRACE_MALLOC_CAPS,
TRACE_MALLOC_DEFAULT
} trace_malloc_mode_t;
void *__real_heap_caps_malloc(size_t size, uint32_t caps);
void *__real_heap_caps_malloc_default( size_t size );
void *__real_heap_caps_realloc_default( void *ptr, size_t size );
/* trace any 'malloc' event */
static IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t size, uint32_t caps, trace_malloc_mode_t mode)
{
uint32_t ccount = get_ccount();
void *p;
if ( mode == TRACE_MALLOC_CAPS ) {
p = __real_heap_caps_malloc(size, caps);
} else { //TRACE_MALLOC_DEFAULT
p = __real_heap_caps_malloc_default(size);
}
if (tracing && p != NULL) {
heap_trace_record_t rec = {
.address = p,
.ccount = ccount,
.size = size,
};
get_call_stack(rec.alloced_by);
record_allocation(&rec);
}
return p;
}
void __real_heap_caps_free(void *p);
/* trace any 'free' event */
static IRAM_ATTR __attribute__((noinline)) void trace_free(void *p)
{
if (tracing && p != NULL) {
void *callers[STACK_DEPTH];
get_call_stack(callers);
record_free(p, callers);
}
__real_heap_caps_free(p);
}
void * __real_heap_caps_realloc(void *p, size_t size, uint32_t caps);
/* trace any 'realloc' event */
static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t size, uint32_t caps, trace_malloc_mode_t mode)
{
void *callers[STACK_DEPTH];
uint32_t ccount = get_ccount();
if (tracing && p != NULL && size == 0) {
get_call_stack(callers);
record_free(p, callers);
}
void *r;
if (mode == TRACE_MALLOC_CAPS ) {
r = __real_heap_caps_realloc(p, size, caps);
} else { //TRACE_MALLOC_DEFAULT
r = __real_heap_caps_realloc_default(p, size);
}
if (tracing && r != NULL) {
get_call_stack(callers);
if (p != NULL) {
/* trace realloc as free-then-alloc */
record_free(p, callers);
}
heap_trace_record_t rec = {
.address = r,
.ccount = ccount,
.size = size,
};
memcpy(rec.alloced_by, callers, sizeof(void *) * STACK_DEPTH);
record_allocation(&rec);
}
return r;
}
/* Note: this changes the behaviour of libc malloc/realloc/free a bit,
as they no longer go via the libc functions in ROM. But more or less
the same in the end. */
IRAM_ATTR void *__wrap_malloc(size_t size)
{
return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void __wrap_free(void *p)
{
trace_free(p);
}
IRAM_ATTR void *__wrap_realloc(void *p, size_t size)
{
return trace_realloc(p, size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void *__wrap_calloc(size_t nmemb, size_t size)
{
size = size * nmemb;
void *result = trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
if (result != NULL) {
memset(result, 0, size);
}
return result;
}
IRAM_ATTR void *__wrap_heap_caps_malloc(size_t size, uint32_t caps)
{
return trace_malloc(size, caps, TRACE_MALLOC_CAPS);
}
void __wrap_heap_caps_free(void *p) __attribute__((alias("__wrap_free")));
IRAM_ATTR void *__wrap_heap_caps_realloc(void *p, size_t size, uint32_t caps)
{
return trace_realloc(p, size, caps, TRACE_MALLOC_CAPS);
}
IRAM_ATTR void *__wrap_heap_caps_malloc_default( size_t size )
{
return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void *__wrap_heap_caps_realloc_default( void *ptr, size_t size )
{
return trace_realloc(ptr, size, 0, TRACE_MALLOC_DEFAULT);
}
#endif /*CONFIG_HEAP_TRACING_STANDALONE*/

View file

@ -47,7 +47,6 @@ typedef struct {
/**
* @brief Initialise heap tracing in standalone mode.
* @note Standalone mode is the only mode currently supported.
*
* This function must be called before any other heap tracing functions.
*
@ -63,6 +62,17 @@ typedef struct {
*/
esp_err_t heap_trace_init_standalone(heap_trace_record_t *record_buffer, size_t num_records);
/**
* @brief Initialise heap tracing in host-based mode.
*
* This function must be called before any other heap tracing functions.
*
* @return
* - ESP_ERR_INVALID_STATE Heap tracing is currently in progress.
* - ESP_OK Heap tracing initialised successfully.
*/
esp_err_t heap_trace_init_tohost(void);
/**
* @brief Start heap tracing. All heap allocations & frees will be traced, until heap_trace_stop() is called.
*

View file

@ -0,0 +1,189 @@
// Copyright 2015-2016 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 <string.h>
#include <sdkconfig.h>
#include "soc/soc_memory_layout.h"
#include "esp_attr.h"
/* Encode the CPU ID in the LSB of the ccount value */
inline static uint32_t get_ccount(void)
{
uint32_t ccount = xthal_get_ccount() & ~3;
#ifndef CONFIG_FREERTOS_UNICORE
ccount |= xPortGetCoreID();
#endif
return ccount;
}
// Caller is 2 stack frames deeper than we care about
#define STACK_OFFSET 2
#define TEST_STACK(N) do { \
if (STACK_DEPTH == N) { \
return; \
} \
callers[N] = __builtin_return_address(N+STACK_OFFSET); \
if (!esp_ptr_executable(callers[N])) { \
return; \
} \
} while(0)
/* Static function to read the call stack for a traced heap call.
Calls to __builtin_return_address are "unrolled" via TEST_STACK macro as gcc requires the
argument to be a compile-time constant.
*/
static IRAM_ATTR __attribute__((noinline)) void get_call_stack(void **callers)
{
bzero(callers, sizeof(void *) * STACK_DEPTH);
TEST_STACK(0);
TEST_STACK(1);
TEST_STACK(2);
TEST_STACK(3);
TEST_STACK(4);
TEST_STACK(5);
TEST_STACK(6);
TEST_STACK(7);
TEST_STACK(8);
TEST_STACK(9);
}
_Static_assert(STACK_DEPTH >= 0 && STACK_DEPTH <= 10, "CONFIG_HEAP_TRACING_STACK_DEPTH must be in range 0-10");
typedef enum {
TRACE_MALLOC_CAPS,
TRACE_MALLOC_DEFAULT
} trace_malloc_mode_t;
void *__real_heap_caps_malloc(size_t size, uint32_t caps);
void *__real_heap_caps_malloc_default( size_t size );
void *__real_heap_caps_realloc_default( void *ptr, size_t size );
/* trace any 'malloc' event */
static IRAM_ATTR __attribute__((noinline)) void *trace_malloc(size_t size, uint32_t caps, trace_malloc_mode_t mode)
{
uint32_t ccount = get_ccount();
void *p;
if ( mode == TRACE_MALLOC_CAPS ) {
p = __real_heap_caps_malloc(size, caps);
} else { //TRACE_MALLOC_DEFAULT
p = __real_heap_caps_malloc_default(size);
}
heap_trace_record_t rec = {
.address = p,
.ccount = ccount,
.size = size,
};
get_call_stack(rec.alloced_by);
record_allocation(&rec);
return p;
}
void __real_heap_caps_free(void *p);
/* trace any 'free' event */
static IRAM_ATTR __attribute__((noinline)) void trace_free(void *p)
{
void *callers[STACK_DEPTH];
get_call_stack(callers);
record_free(p, callers);
__real_heap_caps_free(p);
}
void * __real_heap_caps_realloc(void *p, size_t size, uint32_t caps);
/* trace any 'realloc' event */
static IRAM_ATTR __attribute__((noinline)) void *trace_realloc(void *p, size_t size, uint32_t caps, trace_malloc_mode_t mode)
{
void *callers[STACK_DEPTH];
uint32_t ccount = get_ccount();
void *r;
/* trace realloc as free-then-alloc */
get_call_stack(callers);
record_free(p, callers);
if (mode == TRACE_MALLOC_CAPS ) {
r = __real_heap_caps_realloc(p, size, caps);
} else { //TRACE_MALLOC_DEFAULT
r = __real_heap_caps_realloc_default(p, size);
}
/* realloc with zero size is a free */
if (size != 0) {
heap_trace_record_t rec = {
.address = r,
.ccount = ccount,
.size = size,
};
memcpy(rec.alloced_by, callers, sizeof(void *) * STACK_DEPTH);
record_allocation(&rec);
}
return r;
}
/* Note: this changes the behaviour of libc malloc/realloc/free a bit,
as they no longer go via the libc functions in ROM. But more or less
the same in the end. */
IRAM_ATTR void *__wrap_malloc(size_t size)
{
return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void __wrap_free(void *p)
{
trace_free(p);
}
IRAM_ATTR void *__wrap_realloc(void *p, size_t size)
{
return trace_realloc(p, size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void *__wrap_calloc(size_t nmemb, size_t size)
{
size = size * nmemb;
void *result = trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
if (result != NULL) {
memset(result, 0, size);
}
return result;
}
IRAM_ATTR void *__wrap_heap_caps_malloc(size_t size, uint32_t caps)
{
return trace_malloc(size, caps, TRACE_MALLOC_CAPS);
}
void __wrap_heap_caps_free(void *p) __attribute__((alias("__wrap_free")));
IRAM_ATTR void *__wrap_heap_caps_realloc(void *p, size_t size, uint32_t caps)
{
return trace_realloc(p, size, caps, TRACE_MALLOC_CAPS);
}
IRAM_ATTR void *__wrap_heap_caps_malloc_default( size_t size )
{
return trace_malloc(size, 0, TRACE_MALLOC_DEFAULT);
}
IRAM_ATTR void *__wrap_heap_caps_realloc_default( void *ptr, size_t size )
{
return trace_realloc(ptr, size, 0, TRACE_MALLOC_DEFAULT);
}

View file

@ -184,6 +184,7 @@ INPUT = \
## Application Level Tracing - API Reference
##
../../components/app_trace/include/esp_app_trace.h \
../../components/app_trace/include/esp_sysview_trace.h \
### Power management
../../components/esp_common/include/esp_pm.h \
../../components/esp32/include/esp32/pm.h \

View file

@ -15,4 +15,5 @@ API Reference
-------------
.. include:: /_build/inc/esp_app_trace.inc
.. include:: /_build/inc/esp_sysview_trace.inc

View file

@ -122,11 +122,10 @@ Calls to :cpp:func:`heap_caps_check_integrity` may print errors relating to 0xFE
Heap Tracing
------------
Heap Tracing allows tracing of code which allocates/frees memory.
Heap Tracing allows tracing of code which allocates/frees memory. Two tracing modes are supported:
.. note::
Heap tracing "standalone" mode is currently implemented, meaning that tracing does not require any external hardware but uses internal memory to hold trace data. Heap tracing via JTAG trace port is also planned.
- Standalone. In this mode trace data are kept on-board, so the size of gathered information is limited by the buffer assigned for that purposes. Analysis is done by the on-board code. There are a couple of APIs available for accessing and dumping collected info.
- Host-based. This mode does not have the limitation of the standalone mode, because trace data are sent to the host over JTAG connection using app_trace library. Later on they can be analysed using special tools.
Heap tracing can perform two functions:
@ -138,9 +137,13 @@ How To Diagnose Memory Leaks
If you suspect a memory leak, the first step is to figure out which part of the program is leaking memory. Use the :cpp:func:`xPortGetFreeHeapSize`, :cpp:func:`heap_caps_get_free_size`, or :ref:`related functions <heap-information>` to track memory use over the life of the application. Try to narrow the leak down to a single function or sequence of functions where free memory always decreases and never recovers.
Standalone Mode
+++++++++++++++
Once you've identified the code which you think is leaking:
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` and set :ref:`CONFIG_HEAP_TRACING`.
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Standalone`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`).
- Call the function :cpp:func:`heap_trace_init_standalone` early in the program, to register a buffer which can be used to record the memory trace.
- Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory.
- Call the function :cpp:func:`heap_trace_stop` to stop the trace once the suspect piece of code has finished executing.
@ -165,9 +168,9 @@ An example::
void some_function()
{
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
do_something_you_suspect_is_leaking();
ESP_ERROR_CHECK( heap_trace_stop() );
heap_trace_dump();
...
@ -208,6 +211,164 @@ Finally, the total number of 'leaked' bytes (bytes allocated but not freed while
A warning will be printed if the trace buffer was not large enough to hold all the allocations which happened. If you see this warning, consider either shortening the tracing period or increasing the number of records in the trace buffer.
Host-Based Mode
+++++++++++++++
Once you've identified the code which you think is leaking:
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Heap Memory Debugging`` -> ``Heap tracing`` and select ``Host-Based`` option (see :ref:`CONFIG_HEAP_TRACING_DEST`).
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``Data Destination`` and select ``Trace memory``.
- Under ``make menuconfig``, navigate to ``Component settings`` -> ``Application Level Tracing`` -> ``FreeRTOS SystemView Tracing`` and check ``SystemView Tracing Enable``.
- Call the function :cpp:func:`heap_trace_init_tohost` early in the program, to initialize JTAG heap tracing module.
- Call the function :cpp:func:`heap_trace_start` to begin recording all mallocs/frees in the system. Call this immediately before the piece of code which you suspect is leaking memory.
In host-based mode argument to this function is ignored and heap tracing module behaves like ``HEAP_TRACE_ALL`` was passed: all allocations and deallocations are sent to the host.
- Call the function :cpp:func:`heap_trace_stop` to stop the trace once the suspect piece of code has finished executing.
An example::
#include "esp_heap_trace.h"
...
void app_main()
{
...
ESP_ERROR_CHECK( heap_trace_init_tohost() );
...
}
void some_function()
{
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
do_something_you_suspect_is_leaking();
ESP_ERROR_CHECK( heap_trace_stop() );
...
}
To gather and analyse heap trace do the following on the host:
1. Build the program and download it to the target as described in :doc:`Build and Flash </get-started/make-project>`.
2. Run OpenOCD (see :doc:`JTAG Debugging </api-guides/jtag-debugging/index>`).
.. note::
In order to use this feature you need OpenOCD version `v0.10.0-esp32-20181105` or later.
3. You can use GDB to start and/or stop tracing automatically. To do this you need to prepare special ``gdbinit`` file::
target remote :3333
mon reset halt
flushregs
tb heap_trace_start
commands
mon esp32 sysview start file:///tmp/heap.svdat
c
end
tb heap_trace_stop
commands
mon esp32 sysview stop
end
c
Using this file GDB will connect to the target, reset it, and start tracing when program hits breakpoint at :cpp:func:`heap_trace_start`. Trace data will be saved to ``/tmp/heap_log.svdat``. Tracing will be stopped when program hits breakpoint at :cpp:func:`heap_trace_stop`.
4. Run GDB using the following command ``xtensa-esp32-elf-gdb -x gdbinit </path/to/program/elf>``
5. Quit GDB when program stops at :cpp:func:`heap_trace_stop`. Trace data are saved in ``/tmp/heap.svdat``
6. Run processing script ``$IDF_PATH/tools/esp_app_trace/sysviewtrace_proc.py /tmp/heap_log.svdat </path/to/program/elf>``
The output from the heap trace will look something like this::
Parse trace from '/tmp/heap.svdat'...
Stop parsing trace. (Timeout 0.000000 sec while reading 1 bytes!)
Process events from '['/tmp/heap.svdat']'...
[0.002244575] HEAP: Allocated 1 bytes @ 0x3ffaffd8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.002258425] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.002563725] HEAP: Freed bytes @ 0x3ffaffe0 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.002782950] HEAP: Freed bytes @ 0x3ffb40b8 from task "main" on core 0 by:
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
[0.002798700] HEAP: Freed bytes @ 0x3ffb50bc from task "main" on core 0 by:
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
[0.102436025] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.102449800] HEAP: Allocated 4 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.102666150] HEAP: Freed bytes @ 0x3ffaffe8 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202436200] HEAP: Allocated 3 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202451725] HEAP: Allocated 6 bytes @ 0x3ffafff0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202667075] HEAP: Freed bytes @ 0x3ffafff0 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302436000] HEAP: Allocated 4 bytes @ 0x3ffafff0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302451475] HEAP: Allocated 8 bytes @ 0x3ffb40b8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302667500] HEAP: Freed bytes @ 0x3ffb40b8 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
Processing completed.
Processed 1019 events
=============== HEAP TRACE REPORT ===============
Processed 14 heap events.
[0.002244575] HEAP: Allocated 1 bytes @ 0x3ffaffd8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.102436025] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202436200] HEAP: Allocated 3 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302436000] HEAP: Allocated 4 bytes @ 0x3ffafff0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
Found 10 leaked bytes in 4 blocks.
Heap Tracing To Find Heap Corruption
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -15,15 +15,15 @@ To compile with ESP-IDF you need to get the following packages:
- CentOS 7::
sudo yum install git wget ncurses-devel flex bison gperf python pyserial cmake ninja-build ccache
sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache
- Ubuntu and Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache
.. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".

View file

@ -13,15 +13,15 @@ To compile with ESP-IDF you need to get the following packages:
- CentOS 7::
sudo yum install git wget ncurses-devel flex bison gperf python pyserial cmake ninja-build ccache
sudo yum install git wget ncurses-devel flex bison gperf python pyserial python-pyelftools cmake ninja-build ccache
- Ubuntu and Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools cmake ninja-build ccache
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools cmake ninja ccache
.. note::
CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".

View file

@ -14,11 +14,11 @@ To compile with ESP-IDF you need to get the following packages:
- Ubuntu and Debian::
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools
.. note::

View file

@ -14,11 +14,11 @@ To compile with ESP-IDF you need to get the following packages:
- Ubuntu and Debian::
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools
.. note::

View file

@ -15,15 +15,15 @@
- CentOS 7::
sudo yum install git wget ncurses-devel flex bison gperf python pyserial cmake ninja-build ccache
sudo yum install git wget ncurses-devel flex bison gperf python pyserial cmake ninja-build ccache python-pyelftools
- Ubuntu 和 Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache python-pyelftools
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache python2-pyelftools
.. note::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。

View file

@ -13,15 +13,15 @@ Linux 平台工具链的标准设置 (CMake)
- CentOS 7::
sudo yum install git wget ncurses-devel flex bison gperf python pyserial cmake ninja-build ccache
sudo yum install git wget ncurses-devel flex bison gperf python pyserial cmake ninja-build ccache python-pyelftools
- Ubuntu 和 Debian::
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache python-pyelftools
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache python2-pyelftools
.. note::
使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。

View file

@ -4,7 +4,7 @@
:link_to_translation:`en:[English]`
.. note::
安装工具链的标准流程可以通过阅读文档 :doc:`Linux 平台工具链的标准设置 <linux-setup>` 来获得,:ref:`工具链的自定义设置 <get-started-customized-setup>` 章节会介绍哪些情况下我们必须要重新定义工具链。
@ -15,11 +15,11 @@
- Ubuntu 和 Debian::
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools
.. note::

View file

@ -12,15 +12,15 @@ Linux 平台工具链的标准设置
- CentOS 7::
sudo yum install gcc git wget make ncurses-devel flex bison gperf python pyserial
sudo yum install gcc git wget make ncurses-devel flex bison gperf python pyserial python-pyelftools
- Ubuntu and Debian::
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing python-pyelftools
- Arch::
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing python2-pyelftools
.. note::
@ -52,7 +52,7 @@ Linux 版的 ESP32 工具链可以从 Espressif 的网站下载:
.. include:: /_build/inc/unpack-code-linux32.inc
.. _setup-linux-toolchain-add-it-to-path:
.. _setup-linux-toolchain-add-it-to-path:
2. 工具链将会被解压到 ``~/esp/xtensa-esp32-elf/`` 目录。
@ -67,9 +67,9 @@ Linux 版的 ESP32 工具链可以从 Espressif 的网站下载:
然后,当你需要使用工具链时,在命令行输入 ``get_esp32``,然后工具链会自动添加到你的 ``PATH`` 中。
.. note::
如果将 ``/bin/bash`` 设置为登录 shell且同时存在 ``.bash_profile````.profile``,则更新 ``.bash_profile`` 。在 CentOS 环境下, ``alias`` 需要添加到 ``.bashrc`` 文件中。
3. 退出并重新登录以使 ``.profile`` 更改生效。 运行以下命令来检查 ``PATH`` 设置是否正确: ::
printenv PATH

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

View file

@ -1,5 +1,7 @@
# Enable single core mode by default
CONFIG_MEMMAP_SMP=n
CONFIG_FREERTOS_UNICORE=y
# 1ms tick period
CONFIG_FREERTOS_HZ=1000
# Enable application tracing by default
CONFIG_ESP32_APPTRACE_DEST_TRAX=y

View file

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(sysview_tracing_heap_log)

View file

@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := sysview_tracing_heap_log
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,164 @@
# SystemView Heap and Log Tracing Example
Heap memory leaking is quite widespread software bug. IDF provides [heap tracing feature](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/heap_debug.html#heap-tracing) which allows to collect information related to heap operations (allocations/deallocations) and detect potential memory leaks. This feature can be used in two modes: standalone and host-based. In standalone mode collected data are kept on-board, so this mode is limited by avaialable memory in the system. Host-based mode does not have such limitation because collected data are sent to the host and can be analysed there using special tools. One of such tool is SEGGER SystemView. For description of [SystemView tracing feature](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#system-behaviour-analysis-with-segger-systemview) please refer to **ESP32 Programming Guide**, section **Application Level Tracing library**. SystemView is also can be useful to show log message sent from the target.
This example shows how to use this tool and IDF's scripts for host-based heap and log tracing analysis.
Consider the following situation. User program have two tasks. One task allocates memory and puts obtained addresses into the queue. Another task waits on that queue, reads sent pointers and frees memory. The first task queues only part of the pointers so some of the allocated blocks are not freed and become leaked. Both tasks uses IDF's logging API to report their actions. This example uses IDF's heap tracing module to record allocations and deallocations to detect memory leaks. Both heap tracing records and log mesages are redirected to the host.
## How to use example
### Hardware and tools required
This example does not require any special hardware, and can be run on any common development board.
This example requires the following tools:
1. [OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#run-openocd).
NOTE: In order to run this example you need OpenOCD version `v0.10.0-esp32-20190313` or later.
2. [GDB](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html#setup-toolchain) can be used to start and/or stop tracing automatically. To do this you need to prepare special GDB command file. Having provided with `gdbinit` file from the example project directory GDB will connect to the target, reset it, start and stop tracing automatically.
when program hits breakpoint at `heap_trace_start`. Trace data will be saved to `/tmp/hesp_log.svdat`. Tracing will be stopped when program hits breakpoint at `heap_trace_stop`.
3. [SEGGER SystemView tool](https://www.segger.com/products/development-tools/systemview/). By default SystemView shows only numeric values of IDs and parameters for IDF's heap messages in `Events` view. To make them pretty-looking you need to copy `SYSVIEW_FreeRTOS.txt` from the project's root directory to SystemView installation one.
### Configure the project
If using Make based build system, run `make menuconfig` and set serial port under Serial Flasher Options.
If using CMake based build system, no configuration is required.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 flash monitor
```
Or, for CMake based build system (replace PORT with serial port name):
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
### Collect And View Trace Data
To run the example and collect trace data:
1. Run GDB using the following command from the project root directory:
```
xtensa-esp32-elf-gdb -x gdbinit build/sysview_tracing_heap_log.elf
```
2. When program stops at `heap_trace_stop` quit GDB.
3. Open trace data file in SystemView tool.
4. Now you can inspect all collected events. Log messages are shown in `Terminal` view.
5. You can filter out API related and heap events by right-clicking on any item in `Events` view and select `Show APIs only`.
### Auto-detect Heap Leaks
Since SystemView tool is mostly intended for OS level analysis. It allows just to inspect custom events' timestamps and parameters. So it can require some efforts to analyse heap operations flow. IDF provides special script to make the life a bit more easy. This script parses SystemView trace file sand reports detected memory leaks. The script also prints found log messages. To run it type the following from the project root directory:
```
$IDF_PATH/tools/esp_app_trace/sysviewtrace_proc.py -p /tmp/heap_log.svdat build/sysview_tracing_heap_log.elf
```
Below is the sample scripts output.
```
Parse trace from '/tmp/heap_log.svdat'...
Stop parsing trace. (Timeout 0.000000 sec while reading 1 bytes!)
Process events from '['/tmp/heap_log.svdat']'...
[0.002244575] HEAP: Allocated 1 bytes @ 0x3ffaffd8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.002258425] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.002405000] LOG: I (264) example: Task[0x3ffb6cf4]: allocated 2 bytes @ 0x3ffaffe0
[0.002553425] LOG: I (265) example: Task[0x3ffb7660]: free memory @ 0x3ffaffe0
[0.002563725] HEAP: Freed bytes @ 0x3ffaffe0 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.002782950] HEAP: Freed bytes @ 0x3ffb40b8 from task "main" on core 0 by:
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
[0.002798700] HEAP: Freed bytes @ 0x3ffb50bc from task "main" on core 0 by:
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
/home/user/projects/esp/esp-idf/components/freertos/tasks.c:4590
[0.102436025] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.102449800] HEAP: Allocated 4 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.102536400] LOG: I (365) example: Task[0x3ffb6cf4]: allocated 4 bytes @ 0x3ffaffe8
[0.102655625] LOG: I (365) example: Task[0x3ffb7660]: free memory @ 0x3ffaffe8
[0.102666150] HEAP: Freed bytes @ 0x3ffaffe8 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202436200] HEAP: Allocated 3 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202451725] HEAP: Allocated 6 bytes @ 0x3ffafff0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202538225] LOG: I (465) example: Task[0x3ffb6cf4]: allocated 6 bytes @ 0x3ffafff0
[0.202654475] LOG: I (465) example: Task[0x3ffb7660]: free memory @ 0x3ffafff0
[0.202667075] HEAP: Freed bytes @ 0x3ffafff0 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302436000] HEAP: Allocated 4 bytes @ 0x3ffafff0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302451475] HEAP: Allocated 8 bytes @ 0x3ffb40b8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:48
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302540900] LOG: I (565) example: Task[0x3ffb6cf4]: allocated 8 bytes @ 0x3ffb40b8
[0.302657050] LOG: I (565) example: Task[0x3ffb7660]: free memory @ 0x3ffb40b8
[0.302667500] HEAP: Freed bytes @ 0x3ffb40b8 from task "free" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:31 (discriminator 9)
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
Processing completed.
Processed 1027 events
=============== LOG TRACE REPORT ===============
Processed 8 log messages.
=============== HEAP TRACE REPORT ===============
Processed 14 heap events.
[0.002244575] HEAP: Allocated 1 bytes @ 0x3ffaffd8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.102436025] HEAP: Allocated 2 bytes @ 0x3ffaffe0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.202436200] HEAP: Allocated 3 bytes @ 0x3ffaffe8 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.302436000] HEAP: Allocated 4 bytes @ 0x3ffafff0 from task "alloc" on core 0 by:
/home/user/projects/esp/esp-idf/examples/system/sysview_tracing_heap_log/main/sysview_heap_log.c:47
/home/user/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
Found 10 leaked bytes in 4 blocks.
```

View file

@ -0,0 +1,107 @@
128 vTaskAllocateMPURegions xTask=%t pxRegions=%u
33 vTaskDelete xTaskToDelete=%t
34 vTaskDelay xTicksToDelay=%u
35 vTaskDelayUntil
129 uxTaskPriorityGet xTask=%t
56 uxTaskPriorityGetFromISR xTask=%t
130 eTaskGetState xTask=%t
55 vTaskPrioritySet xTask=%t uxNewPriority=%u
36 vTaskSuspend xTaskToSuspend=%t
40 vTaskResume xTaskToResume=%t
43 xTaskResumeFromISR xTaskToResume=%t
131 vTaskStartScheduler
132 vTaskEndScheduler
133 vTaskSuspendAll
134 xTaskResumeAll
135 xTaskGetTickCount
57 xTaskGetTickCountFromISR
136 uxTaskGetNumberOfTasks
137 pcTaskGetTaskName xTaskToQuery=%t
138 uxTaskGetStackHighWaterMark xTask=%t
139 vTaskSetApplicationTaskTag xTask=%t pxHookFunction=%u
140 xTaskGetApplicationTaskTag xTask=%t
141 vTaskSetThreadLocalStoragePointer xTaskToSet=%T xIndex=%u pvValue=%u
142 pvTaskGetThreadLocalStoragePointer xTaskToQuery=%T xIndex=%u
143 xTaskCallApplicationTaskHook xTask=%T pvParameter=%u
144 xTaskGetIdleTaskHandle
145 uxTaskGetSystemState pxTaskStatusArray=%u uxArraySize=%u pulTotalRunTime=%u
146 vTaskList pcWriteBuffer=%u
147 vTaskGetRunTimeStats pcWriteBuffer=%u
44 xTaskGenericNotify xTaskToNotify=%t ulValue=%u eAction=%u pulPreviousNotificationValue=%u
45 xTaskGenericNotifyFromISR xTaskToNotify=%t ulValue=%u eAction=%u pulPreviousNotificationValue=%u pxHigherPriorityTaskWoken=%u
46 xTaskNotifyWait ulBitsToClearOnEntry=%u ulBitsToClearOnExit=%u pulNotificationValue=%u xTicksToWait=%u
38 vTaskNotifyGiveFromISR xTaskToNotify=%t pxHigherPriorityTaskWoken=%u
37 ulTaskNotifyTake xClearCountOnExit=%u xTicksToWait=%u
148 xTaskNotifyStateClear xTask=%t
149 xTaskGetCurrentTaskHandle
150 vTaskSetTimeOutState pxTimeOut=%u
151 xTaskCheckForTimeOut pxTimeOut=%u pxTicksToWait=%u
152 vTaskMissedYield
153 xTaskGetSchedulerState
39 vTaskPriorityInherit pxMutexHolder=%p
42 xTaskPriorityDisinherit pxMutexHolder=%p
154 xTaskGenericCreate pxTaskCode=%u pcName=%u usStackDepth=%u pvParameters=%u uxPriority=%u pxCreatedTask=%u puxStackBuffer=%u xRegions=%u
155 uxTaskGetTaskNumber xTask=%u
156 vTaskSetTaskNumber xTask=%u uxHandle=%u
41 vTaskStepTick xTicksToJump=%u
157 eTaskConfirmSleepModeStatus
158 xTimerCreate pcTimerName=%u xTimerPeriodInTicks=%u uxAutoReload=%u pvTimerID=%u pxCallbackFunction=%u
159 pvTimerGetTimerID xTimer=%u
160 vTimerSetTimerID xTimer=%u pvNewID=%u
161 xTimerIsTimerActive xTimer=%u
162 xTimerGetTimerDaemonTaskHandle
163 xTimerPendFunctionCallFromISR xFunctionToPend=%u pvParameter1=%u ulParameter2=%u pxHigherPriorityTaskWoken=%u
164 xTimerPendFunctionCall xFunctionToPend=%u pvParameter1=%u ulParameter2=%u xTicksToWait=%u
165 pcTimerGetTimerName xTimer=%u
166 xTimerCreateTimerTask
167 xTimerGenericCommand xTimer=%u xCommandID=%u xOptionalValue=%u pxHigherPriorityTaskWoken=%u xTicksToWait=%u
53 xQueueGenericSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u xCopyPosition=%u
50 xQueuePeekFromISR xQueue=%I pvBuffer=%p
49 xQueueGenericReceive xQueue=%I pvBuffer=%p xTicksToWait=%u xJustPeek=%u
168 uxQueueMessagesWaiting xQueue=%I
169 uxQueueSpacesAvailable xQueue=%I
48 vQueueDelete xQueue=%I
54 xQueueGenericSendFromISR xQueue=%I pvItemToQueue=%p pxHigherPriorityTaskWoken=%u xCopyPosition=%u
61 xQueueGiveFromISR xQueue=%I pxHigherPriorityTaskWoken=%u
51 xQueueReceiveFromISR xQueue=%I pvBuffer=%p pxHigherPriorityTaskWoken=%u
62 xQueueIsQueueEmptyFromISR xQueue=%I
63 xQueueIsQueueFullFromISR xQueue=%I
170 uxQueueMessagesWaitingFromISR xQueue=%I
171 xQueueAltGenericSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u xCopyPosition=%u
172 xQueueAltGenericReceive xQueue=%I pvBuffer=%p xTicksToWait=%u xJustPeeking=%u
173 xQueueCRSendFromISR xQueue=%I pvItemToQueue=%p xCoRoutinePreviouslyWoken=%u
174 xQueueCRReceiveFromISR xQueue=%I pvBuffer=%p pxTaskWoken=%u
175 xQueueCRSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u
176 xQueueCRReceive xQueue=%I pvBuffer=%p xTicksToWait=%u
177 xQueueCreateMutex ucQueueType=%u
178 xQueueCreateCountingSemaphore uxMaxCount=%u uxInitialCount=%u
179 xQueueGetMutexHolder xSemaphore=%u
180 xQueueTakeMutexRecursive xMutex=%u xTicksToWait=%u
181 xQueueGiveMutexRecursive pxMutex=%u
52 vQueueAddToRegistry xQueue=%I pcName=%u
182 vQueueUnregisterQueue xQueue=%I
47 xQueueGenericCreate uxQueueLength=%u uxItemSize=%u ucQueueType=%u
183 xQueueCreateSet uxEventQueueLength=%u
184 xQueueAddToSet xQueueOrSemaphore=%u xQueueSet=%u
185 xQueueRemoveFromSet xQueueOrSemaphore=%u xQueueSet=%u
186 xQueueSelectFromSet xQueueSet=%u xTicksToWait=%u
187 xQueueSelectFromSetFromISR xQueueSet=%u
188 xQueueGenericReset xQueue=%I xNewQueue=%u
189 vListInitialise pxList=%u
190 vListInitialiseItem pxItem=%u
191 vListInsert pxList=%u pxNewListItem=%u
192 vListInsertEnd pxList=%u pxNewListItem=%u
193 uxListRemove pxItemToRemove=%u
194 xEventGroupCreate
195 xEventGroupWaitBits xEventGroup=%u uxBitsToWaitFor=%u xClearOnExit=%u xWaitForAllBits=%u xTicksToWait=%u
196 xEventGroupClearBits xEventGroup=%u uxBitsToClear=%u
58 xEventGroupClearBitsFromISR xEventGroup=%u uxBitsToSet=%u
197 xEventGroupSetBits xEventGroup=%u uxBitsToSet=%u
59 xEventGroupSetBitsFromISR xEventGroup=%u uxBitsToSet=%u pxHigherPriorityTaskWoken=%u
198 xEventGroupSync xEventGroup=%u uxBitsToSet=%u uxBitsToWaitFor=%u xTicksToWait=%u
60 xEventGroupGetBitsFromISR xEventGroup=%u
199 vEventGroupDelete xEventGroup=%u
200 uxEventGroupGetNumber xEventGroup=%u
512 esp_sysview_heap_trace_alloc addr=%p size=%u callers=%x
513 esp_sysview_heap_trace_free addr=%p callers=%x

View file

@ -0,0 +1,17 @@
target remote :3333
mon reset halt
flushregs
tb heap_trace_start
commands
mon esp32 sysview start file:///tmp/heap_log.svdat
c
end
tb heap_trace_stop
commands
mon esp32 sysview stop
end
c

View file

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "sysview_heap_log.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View file

@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View file

@ -0,0 +1,75 @@
/* Application Trace to Host Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "esp_sysview_trace.h"
#include "esp_heap_trace.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
static const char *TAG = "example";
// waits on queue for memory addresses and frees memory allocated by 'alloc_task'
static void free_task(void *p)
{
QueueHandle_t queue = (QueueHandle_t)p;
while (1) {
void *p = NULL;
if (xQueueReceive(queue, ( void * )&p, portMAX_DELAY) != pdPASS) {
ESP_LOGE(TAG, "Failed to send to queue!");
} else {
ESP_LOGI(TAG, "Task[%p]: free memory @ %p", xTaskGetCurrentTaskHandle(), p);
free(p);
}
}
}
// allocates memory and puts addresses to the queue
static void alloc_task(void *p)
{
QueueHandle_t queue = (QueueHandle_t)p;
xTaskCreatePinnedToCore(free_task, "free", 2048, queue, 5, NULL, portNUM_PROCESSORS-1);
// here GDB will stop at brekpoint and execute OpenOCD command to start tracing
heap_trace_start(HEAP_TRACE_ALL);
for(int i = 1; i < 5; i++) {
uint32_t sz = 2*i;
void *p = malloc(sz/2);
// WARNING: the previous allocated memory is intentionally not deallocated in order to cause memory leak!
p = malloc(sz);
ESP_LOGI(TAG, "Task[%p]: allocated %d bytes @ %p", xTaskGetCurrentTaskHandle(), sz, p);
if (xQueueSend(queue, ( void * )&p, portMAX_DELAY) != pdPASS) {
ESP_LOGE(TAG, "Failed to send to queue!");
}
vTaskDelay(100/portTICK_PERIOD_MS);
}
// here GDB will stop at brekpoint and execute OpenOCD command to stop tracing
heap_trace_stop();
while(1);
}
void app_main()
{
// redirect log messages to the host using SystemView tracing module
esp_log_set_vprintf(&esp_sysview_vprintf);
QueueHandle_t queue = xQueueCreate(10, sizeof(void *));
if(queue == 0) {
ESP_LOGE(TAG, "Failed to create queue!");
return;
}
// init host-based heap tracing
if(heap_trace_init_tohost() != ESP_OK) {
ESP_LOGE(TAG, "Failed to init heap trace!");
return;
}
xTaskCreatePinnedToCore(alloc_task, "alloc", 2048, queue, 5, NULL, 0);
}

View file

@ -0,0 +1,28 @@
# Enable single core mode by default
CONFIG_MEMMAP_SMP=n
CONFIG_FREERTOS_UNICORE=y
# 1ms tick period
CONFIG_FREERTOS_HZ=1000
# Enable application tracing by default
CONFIG_ESP32_APPTRACE_DEST_TRAX=y
CONFIG_ESP32_APPTRACE_ENABLE=y
# Enable FreeRTOS SystemView Tracing by default
CONFIG_SYSVIEW_ENABLE=y
CONFIG_SYSVIEW_TS_SOURCE_TIMER_00=y
CONFIG_SYSVIEW_EVT_OVERFLOW_ENABLE=y
CONFIG_SYSVIEW_EVT_ISR_ENTER_ENABLE=y
CONFIG_SYSVIEW_EVT_ISR_EXIT_ENABLE=y
CONFIG_SYSVIEW_EVT_ISR_TO_SCHEDULER_ENABLE=y
CONFIG_SYSVIEW_EVT_TASK_START_EXEC_ENABLE=y
CONFIG_SYSVIEW_EVT_TASK_STOP_EXEC_ENABLE=y
CONFIG_SYSVIEW_EVT_TASK_START_READY_ENABLE=y
CONFIG_SYSVIEW_EVT_TASK_STOP_READY_ENABLE=y
CONFIG_SYSVIEW_EVT_TASK_CREATE_ENABLE=y
CONFIG_SYSVIEW_EVT_TASK_TERMINATE_ENABLE=y
CONFIG_SYSVIEW_EVT_IDLE_ENABLE=y
CONFIG_SYSVIEW_EVT_TIMER_ENTER_ENABLE=y
CONFIG_SYSVIEW_EVT_TIMER_EXIT_ENABLE=y
# Disable color output in logs
CONFIG_LOG_COLORS=
# Enable heap tracing to host
CONFIG_HEAP_TRACING_TOHOST=y

View file

@ -8,4 +8,5 @@ setuptools
pyserial>=3.0
future>=0.15.2
cryptography>=2.1.4
pyparsing>=2.0.3
pyparsing>=2.0.3
pyelftools>=0.22

View file

@ -34,8 +34,10 @@ tools/ci/test_build_system_cmake.sh
tools/ci/test_configure_ci_environment.sh
tools/cmake/convert_to_cmake.py
tools/cmake/run_cmake_lint.sh
tools/esp_app_trace/apptrace_proc.py
tools/esp_app_trace/logtrace_proc.py
tools/esp_app_trace/sysviewtrace_proc.py
tools/esp_app_trace/test/logtrace/test.sh
tools/esp_app_trace/test/sysview/test.sh
tools/format.sh
tools/gen_esp_err_to_name.py
tools/idf.py

View file

@ -0,0 +1,107 @@
128 vTaskAllocateMPURegions xTask=%t pxRegions=%u
33 vTaskDelete xTaskToDelete=%t
34 vTaskDelay xTicksToDelay=%u
35 vTaskDelayUntil
129 uxTaskPriorityGet xTask=%t
56 uxTaskPriorityGetFromISR xTask=%t
130 eTaskGetState xTask=%t
55 vTaskPrioritySet xTask=%t uxNewPriority=%u
36 vTaskSuspend xTaskToSuspend=%t
40 vTaskResume xTaskToResume=%t
43 xTaskResumeFromISR xTaskToResume=%t
131 vTaskStartScheduler
132 vTaskEndScheduler
133 vTaskSuspendAll
134 xTaskResumeAll
135 xTaskGetTickCount
57 xTaskGetTickCountFromISR
136 uxTaskGetNumberOfTasks
137 pcTaskGetTaskName xTaskToQuery=%t
138 uxTaskGetStackHighWaterMark xTask=%t
139 vTaskSetApplicationTaskTag xTask=%t pxHookFunction=%u
140 xTaskGetApplicationTaskTag xTask=%t
141 vTaskSetThreadLocalStoragePointer xTaskToSet=%T xIndex=%u pvValue=%u
142 pvTaskGetThreadLocalStoragePointer xTaskToQuery=%T xIndex=%u
143 xTaskCallApplicationTaskHook xTask=%T pvParameter=%u
144 xTaskGetIdleTaskHandle
145 uxTaskGetSystemState pxTaskStatusArray=%u uxArraySize=%u pulTotalRunTime=%u
146 vTaskList pcWriteBuffer=%u
147 vTaskGetRunTimeStats pcWriteBuffer=%u
44 xTaskGenericNotify xTaskToNotify=%t ulValue=%u eAction=%u pulPreviousNotificationValue=%u
45 xTaskGenericNotifyFromISR xTaskToNotify=%t ulValue=%u eAction=%u pulPreviousNotificationValue=%u pxHigherPriorityTaskWoken=%u
46 xTaskNotifyWait ulBitsToClearOnEntry=%u ulBitsToClearOnExit=%u pulNotificationValue=%u xTicksToWait=%u
38 vTaskNotifyGiveFromISR xTaskToNotify=%t pxHigherPriorityTaskWoken=%u
37 ulTaskNotifyTake xClearCountOnExit=%u xTicksToWait=%u
148 xTaskNotifyStateClear xTask=%t
149 xTaskGetCurrentTaskHandle
150 vTaskSetTimeOutState pxTimeOut=%u
151 xTaskCheckForTimeOut pxTimeOut=%u pxTicksToWait=%u
152 vTaskMissedYield
153 xTaskGetSchedulerState
39 vTaskPriorityInherit pxMutexHolder=%p
42 xTaskPriorityDisinherit pxMutexHolder=%p
154 xTaskGenericCreate pxTaskCode=%u pcName=%u usStackDepth=%u pvParameters=%u uxPriority=%u pxCreatedTask=%u puxStackBuffer=%u xRegions=%u
155 uxTaskGetTaskNumber xTask=%u
156 vTaskSetTaskNumber xTask=%u uxHandle=%u
41 vTaskStepTick xTicksToJump=%u
157 eTaskConfirmSleepModeStatus
158 xTimerCreate pcTimerName=%u xTimerPeriodInTicks=%u uxAutoReload=%u pvTimerID=%u pxCallbackFunction=%u
159 pvTimerGetTimerID xTimer=%u
160 vTimerSetTimerID xTimer=%u pvNewID=%u
161 xTimerIsTimerActive xTimer=%u
162 xTimerGetTimerDaemonTaskHandle
163 xTimerPendFunctionCallFromISR xFunctionToPend=%u pvParameter1=%u ulParameter2=%u pxHigherPriorityTaskWoken=%u
164 xTimerPendFunctionCall xFunctionToPend=%u pvParameter1=%u ulParameter2=%u xTicksToWait=%u
165 pcTimerGetTimerName xTimer=%u
166 xTimerCreateTimerTask
167 xTimerGenericCommand xTimer=%u xCommandID=%u xOptionalValue=%u pxHigherPriorityTaskWoken=%u xTicksToWait=%u
53 xQueueGenericSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u xCopyPosition=%u
50 xQueuePeekFromISR xQueue=%I pvBuffer=%p
49 xQueueGenericReceive xQueue=%I pvBuffer=%p xTicksToWait=%u xJustPeek=%u
168 uxQueueMessagesWaiting xQueue=%I
169 uxQueueSpacesAvailable xQueue=%I
48 vQueueDelete xQueue=%I
54 xQueueGenericSendFromISR xQueue=%I pvItemToQueue=%p pxHigherPriorityTaskWoken=%u xCopyPosition=%u
61 xQueueGiveFromISR xQueue=%I pxHigherPriorityTaskWoken=%u
51 xQueueReceiveFromISR xQueue=%I pvBuffer=%p pxHigherPriorityTaskWoken=%u
62 xQueueIsQueueEmptyFromISR xQueue=%I
63 xQueueIsQueueFullFromISR xQueue=%I
170 uxQueueMessagesWaitingFromISR xQueue=%I
171 xQueueAltGenericSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u xCopyPosition=%u
172 xQueueAltGenericReceive xQueue=%I pvBuffer=%p xTicksToWait=%u xJustPeeking=%u
173 xQueueCRSendFromISR xQueue=%I pvItemToQueue=%p xCoRoutinePreviouslyWoken=%u
174 xQueueCRReceiveFromISR xQueue=%I pvBuffer=%p pxTaskWoken=%u
175 xQueueCRSend xQueue=%I pvItemToQueue=%p xTicksToWait=%u
176 xQueueCRReceive xQueue=%I pvBuffer=%p xTicksToWait=%u
177 xQueueCreateMutex ucQueueType=%u
178 xQueueCreateCountingSemaphore uxMaxCount=%u uxInitialCount=%u
179 xQueueGetMutexHolder xSemaphore=%u
180 xQueueTakeMutexRecursive xMutex=%u xTicksToWait=%u
181 xQueueGiveMutexRecursive pxMutex=%u
52 vQueueAddToRegistry xQueue=%I pcName=%u
182 vQueueUnregisterQueue xQueue=%I
47 xQueueGenericCreate uxQueueLength=%u uxItemSize=%u ucQueueType=%u
183 xQueueCreateSet uxEventQueueLength=%u
184 xQueueAddToSet xQueueOrSemaphore=%u xQueueSet=%u
185 xQueueRemoveFromSet xQueueOrSemaphore=%u xQueueSet=%u
186 xQueueSelectFromSet xQueueSet=%u xTicksToWait=%u
187 xQueueSelectFromSetFromISR xQueueSet=%u
188 xQueueGenericReset xQueue=%I xNewQueue=%u
189 vListInitialise pxList=%u
190 vListInitialiseItem pxItem=%u
191 vListInsert pxList=%u pxNewListItem=%u
192 vListInsertEnd pxList=%u pxNewListItem=%u
193 uxListRemove pxItemToRemove=%u
194 xEventGroupCreate
195 xEventGroupWaitBits xEventGroup=%u uxBitsToWaitFor=%u xClearOnExit=%u xWaitForAllBits=%u xTicksToWait=%u
196 xEventGroupClearBits xEventGroup=%u uxBitsToClear=%u
58 xEventGroupClearBitsFromISR xEventGroup=%u uxBitsToSet=%u
197 xEventGroupSetBits xEventGroup=%u uxBitsToSet=%u
59 xEventGroupSetBitsFromISR xEventGroup=%u uxBitsToSet=%u pxHigherPriorityTaskWoken=%u
198 xEventGroupSync xEventGroup=%u uxBitsToSet=%u uxBitsToWaitFor=%u xTicksToWait=%u
60 xEventGroupGetBitsFromISR xEventGroup=%u
199 vEventGroupDelete xEventGroup=%u
200 uxEventGroupGetNumber xEventGroup=%u
512 esp_sysview_heap_trace_alloc addr=%p size=%u callers=%x
513 esp_sysview_heap_trace_free addr=%p callers=%x

View file

@ -1,130 +0,0 @@
#!/usr/bin/env python
#
from __future__ import print_function
import argparse
import struct
import sys
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
def main():
ESP32_TRACE_BLOCK_HDR_SZ = 8
ESP32_TRACE_BLOCK_TASK_IDX = 0
ESP32_TRACE_BLOCK_TS_IDX = 1
ESP32_TRACE_BLOCK_DATA_IDX = 2
parser = argparse.ArgumentParser(description='ESP32 App Trace Parse Tool')
parser.add_argument('file', help='Path to app trace file', type=str)
parser.add_argument('--print-tasks', '-p', help='Print tasks', action='store_true')
parser.add_argument('--print-details', '-d', help='Print detailed stats', action='store_true')
parser.add_argument('--no-errors', '-n', help='Do not print errors', action='store_true')
parser.add_argument('--block-len', '-b', help='Block length', type=int, default=1024)
args = parser.parse_args()
print("====================================================================")
try:
ftrc = open(args.file, 'rb')
except IOError as e:
print("Failed to open trace file (%s)!" % e)
sys.exit(2)
passed = True
off = 0
data_stats = {}
last_ts = None
tot_discont = 0
while True:
# ftrc.seek(off)
task = None
ts = 0
trc_buf = ftrc.read(args.block_len)
if len(trc_buf) == 0:
# print('EOF')
break
trc_data = struct.unpack('<LL%sB' % (len(trc_buf) - ESP32_TRACE_BLOCK_HDR_SZ), trc_buf)
if len(trc_data):
# print("%x %x, len %d" % (trc_data[0], trc_data[1], len(trc_data) - 2))
# print(trc_data[2:])
# sys.exit(0)
task = trc_data[ESP32_TRACE_BLOCK_TASK_IDX]
ts = trc_data[ESP32_TRACE_BLOCK_TS_IDX]
# print(ts)
if last_ts and last_ts >= ts:
# print("Global TS discontinuity %x -> %x, task %x, stamp %x at %x" % (last_ts, ts, task,
# data_stats[task]['stamp'], off))
if args.print_details:
print("Global TS discontinuity %x -> %x, task %x at %x" % (last_ts, ts, task, off))
# tot_discont += 1
# passed = False
last_ts = ts
if task not in data_stats:
print("%x: NEW TASK" % task)
data_stats[task] = {'stamp': trc_data[ESP32_TRACE_BLOCK_DATA_IDX], 'last_ts': ts, 'count': 1, 'discont_offs': [], 'inv_stamps_offs': []}
else:
if data_stats[task]['last_ts'] == ts:
print("Task TS discontinuity %x -> %x, task %x, stamp %x at %x" % (last_ts, ts, task, data_stats[task]['stamp'], off))
data_stats[task]['discont_offs'].append(off)
tot_discont += 1
passed = False
data_stats[task]['last_ts'] = ts
data_stats[task]['count'] += 1
if len(trc_data) > ESP32_TRACE_BLOCK_DATA_IDX:
# print("DATA = %x %x %x %x" % (trc_data[-4], trc_data[-3], trc_data[-2], trc_data[-1]))
if args.print_tasks:
print("Task[%d] %x, ts %08x, stamp %x" % (off / args.block_len, task, ts, trc_data[ESP32_TRACE_BLOCK_DATA_IDX]))
else:
print("%x: NO DATA" % task)
else:
print("Failed to unpack data!")
sys.exit(2)
# check data
for i in range(ESP32_TRACE_BLOCK_DATA_IDX, len(trc_data)):
if trc_data[i] != data_stats[task]['stamp']:
if not args.no_errors:
print("Invalid stamp %x->%x at %x, task %x" % (data_stats[task]['stamp'], trc_data[i], off + ESP32_TRACE_BLOCK_HDR_SZ + i, task))
passed = False
data_stats[task]['stamp'] = trc_data[i]
data_stats[task]['inv_stamps_offs'].append(off)
# break
if len(trc_buf) < args.block_len:
print('Last block (not full)')
break
if data_stats[task]['stamp'] is not None:
data_stats[task]['stamp'] = (data_stats[task]['stamp'] + 1) & 0xFF
# print("stamp=%x" % data_stats[task][ESP32_TRACE_STAMP_IDX])
off += args.block_len
ftrc.close()
print("====================================================================")
print("Trace size %d bytes, discont %d\n" % (off, tot_discont))
for t in data_stats:
print("Task %x. Total count %d. Inv stamps %d. TS Discontinuities %d." % (t, data_stats[t]['count'],
len(data_stats[t]['inv_stamps_offs']), len(data_stats[t]['discont_offs'])))
if args.print_details:
print('Invalid stamps offs: [{}]'.format(', '.join(hex(x) for x in data_stats[t]['inv_stamps_offs'])))
print('TS Discontinuities offs: [{}]'.format(', '.join(hex(x) for x in data_stats[t]['discont_offs'])))
print("\n")
if passed:
print("Data - OK")
else:
print("Data - FAILED!")
if __name__ == '__main__':
main()

View file

@ -0,0 +1,5 @@
# espytrace Python package
This package implements base routines and classes for processing ESP32 application level trace data.
- `apptrace.py` includes functionality which is common for all types of trace data.
- `sysview.py` includes functionality which is specific for SystemView trace data format.

View file

@ -0,0 +1,720 @@
import os
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
try:
import SocketServer
except ImportError:
import socketserver as SocketServer
import threading
import tempfile
import time
import subprocess
import os.path
import elftools.elf.elffile as elffile
import elftools.elf.constants as elfconst
def addr2line(toolchain, elf_path, addr):
"""
Creates trace reader.
Parameters
----------
toolchain : string
toolchain prefix to retrieve source line locations using addresses
elf_path : string
path to ELF file to use
addr : int
address to retrieve source line location
Returns
-------
string
source line location string
"""
try:
return subprocess.check_output(['%saddr2line' % toolchain, '-e', elf_path, '0x%x' % addr]).decode("utf-8")
except subprocess.CalledProcessError:
return ''
class ParseError(RuntimeError):
"""
Parse error exception
"""
def __init__(self, message):
RuntimeError.__init__(self, message)
class ReaderError(RuntimeError):
"""
Trace reader error exception
"""
def __init__(self, message):
RuntimeError.__init__(self, message)
class ReaderTimeoutError(ReaderError):
"""
Trace reader timeout error
"""
def __init__(self, tmo, sz):
ReaderError.__init__(self, 'Timeout %f sec while reading %d bytes!' % (tmo, sz))
class ReaderShutdownRequest(ReaderError):
"""
Trace reader shutdown request error
Raised when user presses CTRL+C (SIGINT).
"""
def __init__(self):
ReaderError.__init__(self, 'Shutdown request!')
class Reader:
"""
Base abstract reader class
"""
def __init__(self, tmo):
"""
Constructor
Parameters
----------
tmo : int
read timeout
"""
self.timeout = tmo
self.need_stop = False
def read(self, sz):
"""
Reads a number of bytes
Parameters
----------
sz : int
number of bytes to read
Returns
-------
bytes object
read bytes
Returns
-------
ReaderTimeoutError
if timeout expires
ReaderShutdownRequest
if SIGINT was received during reading
"""
pass
def readline(self):
"""
Reads line
Parameters
----------
sz : int
number of bytes to read
Returns
-------
string
read line
"""
pass
def forward(self, sz):
"""
Moves read pointer to a number of bytes
Parameters
----------
sz : int
number of bytes to read
"""
pass
def cleanup(self):
"""
Cleans up reader
"""
self.need_stop = True
class FileReader(Reader):
"""
File reader class
"""
def __init__(self, path, tmo):
"""
Constructor
Parameters
----------
path : string
path to file to read
tmo : int
see Reader.__init__()
"""
Reader.__init__(self, tmo)
self.trace_file_path = path
self.trace_file = open(path, 'rb')
def read(self, sz):
"""
see Reader.read()
"""
data = b''
start_tm = time.clock()
while not self.need_stop:
data += self.trace_file.read(sz - len(data))
if len(data) == sz:
break
if self.timeout != -1 and time.clock() >= start_tm + self.timeout:
raise ReaderTimeoutError(self.timeout, sz)
if self.need_stop:
raise ReaderShutdownRequest()
return data
def get_pos(self):
"""
Retrieves current file read position
Returns
-------
int
read position
"""
return self.trace_file.tell()
def readline(self, linesep=os.linesep):
"""
see Reader.read()
"""
line = ''
start_tm = time.clock()
while not self.need_stop:
line += self.trace_file.readline().decode("utf-8")
if line.endswith(linesep):
break
if self.timeout != -1 and time.clock() >= start_tm + self.timeout:
raise ReaderTimeoutError(self.timeout, 1)
if self.need_stop:
raise ReaderShutdownRequest()
return line
def forward(self, sz):
"""
see Reader.read()
"""
cur_pos = self.trace_file.tell()
start_tm = time.clock()
while not self.need_stop:
file_sz = os.path.getsize(self.trace_file_path)
if file_sz - cur_pos >= sz:
break
if self.timeout != -1 and time.clock() >= start_tm + self.timeout:
raise ReaderTimeoutError(self.timeout, sz)
if self.need_stop:
raise ReaderShutdownRequest()
self.trace_file.seek(sz, os.SEEK_CUR)
class NetRequestHandler:
"""
Handler for incoming network requests (connections, datagrams)
"""
def handle(self):
while not self.server.need_stop:
data = self.rfile.read(1024)
if len(data) == 0:
break
self.server.wtrace.write(data)
self.server.wtrace.flush()
class NetReader(FileReader):
"""
Base netwoek socket reader class
"""
def __init__(self, tmo):
"""
see Reader.__init__()
"""
fhnd,fname = tempfile.mkstemp()
FileReader.__init__(self, fname, tmo)
self.wtrace = os.fdopen(fhnd, 'wb')
self.server_thread = threading.Thread(target=self.serve_forever)
self.server_thread.start()
def cleanup(self):
"""
see Reader.cleanup()
"""
FileReader.cleanup(self)
self.shutdown()
self.server_close()
self.server_thread.join()
time.sleep(0.1)
self.trace_file.close()
self.wtrace.close()
class TCPRequestHandler(NetRequestHandler, SocketServer.StreamRequestHandler):
"""
Handler for incoming TCP connections
"""
pass
class TCPReader(NetReader, SocketServer.TCPServer):
"""
TCP socket reader class
"""
def __init__(self, host, port, tmo):
"""
Constructor
Parameters
----------
host : string
see SocketServer.BaseServer.__init__()
port : int
see SocketServer.BaseServer.__init__()
tmo : int
see Reader.__init__()
"""
SocketServer.TCPServer.__init__(self, (host, port), TCPRequestHandler)
NetReader.__init__(self, tmo)
class UDPRequestHandler(NetRequestHandler, SocketServer.DatagramRequestHandler):
"""
Handler for incoming UDP datagrams
"""
pass
class UDPReader(NetReader, SocketServer.UDPServer):
"""
UDP socket reader class
"""
def __init__(self, host, port, tmo):
"""
Constructor
Parameters
----------
host : string
see SocketServer.BaseServer.__init__()
port : int
see SocketServer.BaseServer.__init__()
tmo : int
see Reader.__init__()
"""
SocketServer.UDPServer.__init__(self, (host, port), UDPRequestHandler)
NetReader.__init__(self, tmo)
def reader_create(trc_src, tmo):
"""
Creates trace reader.
Parameters
----------
trc_src : string
trace source URL. Supports 'file:///path/to/file' or (tcp|udp)://host:port
tmo : int
read timeout
Returns
-------
Reader
reader object or None if URL scheme is not supported
"""
url = urlparse(trc_src)
if len(url.scheme) == 0 or url.scheme == 'file':
if os.name == 'nt':
# workaround for Windows path
return FileReader(trc_src[7:], tmo)
else:
return FileReader(url.path, tmo)
if url.scheme == 'tcp':
return TCPReader(url.hostname, url.port, tmo)
if url.scheme == 'udp':
return UDPReader(url.hostname, url.port, tmo)
return None
class TraceDataProcessor:
"""
Base abstract class for all trace data processors.
"""
def __init__(self, print_events, keep_all_events=False):
"""
Constructor.
Parameters
----------
print_events : bool
if True every event will be printed as they arrive
keep_all_events : bool
if True all events will be kept in self.events in the order they arrive
"""
self.print_events = print_events
self.keep_all_events = keep_all_events
self.total_events = 0
self.events = []
# This can be changed by the root procesor that includes several sub-processors.
# It is used access some method of root processor which can contain methods/data common for all sub-processors.
# Common info could be current execution context, info about running tasks, available IRQs etc.
self.root_proc = self
def _print_event(self, event):
"""
Base method to print an event.
Parameters
----------
event : object
Event object
"""
print("EVENT[{:d}]: {}".format(self.total_events, event))
def print_report(self):
"""
Base method to print report.
"""
print("Processed {:d} events".format(self.total_events))
def cleanup(self):
"""
Base method to make cleanups.
"""
pass
def on_new_event(self, event):
"""
Base method to process event.
"""
if self.print_events:
self._print_event(event)
if self.keep_all_events:
self.events.append(event)
self.total_events += 1
class LogTraceParseError(ParseError):
"""
Log trace parse error exception.
"""
pass
def get_str_from_elf(felf, str_addr):
"""
Retrieves string from ELF file.
Parameters
----------
felf : elffile.ELFFile
open ELF file handle to retrive format string from
str_addr : int
address of the string
Returns
-------
string
string or None if it was not found
"""
tgt_str = ''
for sect in felf.iter_sections():
if sect['sh_addr'] == 0 or (sect['sh_flags'] & elfconst.SH_FLAGS.SHF_ALLOC) == 0:
continue
if str_addr < sect['sh_addr'] or str_addr >= sect['sh_addr'] + sect['sh_size']:
continue
sec_data = sect.data()
for i in range(str_addr - sect['sh_addr'], sect['sh_size']):
if type(sec_data) is str:
ch = sec_data[i]
else:
ch = str(chr(sec_data[i]))
if ch == '\0':
break
tgt_str += ch
if len(tgt_str) > 0:
return tgt_str
return None
class LogTraceEvent:
"""
Log trace event.
"""
def __init__(self, fmt_addr, log_args):
"""
Constructor.
Parameters
----------
fmt_addr : int
address of the format string
log_args : list
list of log message arguments
"""
self.fmt_addr = fmt_addr
self.args = log_args
def get_message(self, felf):
"""
Retrieves log message.
Parameters
----------
felf : elffile.ELFFile
open ELF file handle to retrive format string from
Returns
-------
string
formatted log message
Raises
------
LogTraceParseError
if format string has not been found in ELF file
"""
fmt_str = get_str_from_elf(felf, self.fmt_addr)
if not fmt_str:
raise LogTraceParseError('Failed to find format string for 0x%x' % self.fmt_addr)
prcnt_idx = 0
for i, arg in enumerate(self.args):
prcnt_idx = fmt_str.find('%', prcnt_idx, -2) # TODO: check str ending with %
if prcnt_idx == -1:
break
prcnt_idx += 1 # goto next char
if fmt_str[prcnt_idx] == 's':
# find string
arg_str = get_str_from_elf(felf, self.args[i])
if arg_str:
self.args[i] = arg_str
else:
self.args[i] = '<None>'
fmt_str = fmt_str.replace('%p', '%x')
return fmt_str % tuple(self.args)
class BaseLogTraceDataProcessorImpl:
"""
Base implementation for log data processors.
"""
def __init__(self, print_log_events=False, elf_path=''):
"""
Constructor.
Parameters
----------
print_log_events : bool
if True every log event will be printed as they arrive
elf_path : string
path to ELF file to retrieve format strings for log messages
"""
if len(elf_path):
self.felf = elffile.ELFFile(open(elf_path, 'rb'))
else:
self.felf = None
self.print_log_events = print_log_events
self.messages = []
def cleanup(self):
"""
Cleanup
"""
if self.felf:
self.felf.stream.close()
def print_report(self):
"""
Prints log report
"""
print("=============== LOG TRACE REPORT ===============")
print("Processed {:d} log messages.".format(len(self.messages)))
def on_new_event(self, event):
"""
Processes log events.
Parameters
----------
event : LogTraceEvent
Event object.
"""
msg = event.get_message(self.felf)
self.messages.append(msg)
if self.print_log_events:
print(msg),
class HeapTraceParseError(ParseError):
"""
Heap trace parse error exception.
"""
pass
class HeapTraceDuplicateAllocError(HeapTraceParseError):
"""
Heap trace duplicate allocation error exception.
"""
def __init__(self, addr, new_size, prev_size):
"""
Constructor.
Parameters
----------
addr : int
memory block address
new_size : int
size of the new allocation
prev_size : int
size of the previous allocation
"""
HeapTraceParseError.__init__(self, """Duplicate alloc @ 0x{:x}!
New alloc is {:d} bytes,
previous is {:d} bytes.""".format(addr, new_size, prev_size))
class HeapTraceEvent:
"""
Heap trace event.
"""
def __init__(self, ctx_name, in_irq, core_id, ts, alloc, size, addr, callers, toolchain='', elf_path=''):
"""
Constructor.
Parameters
----------
ctx_name : string
name of event context (task or IRQ name)
in_irq : bool
True if event has been generated in IRQ context, otherwise False
core_id : int
core which generated the event
ts : float
event timestamp
alloc : bool
True for allocation event, otherwise False
size : int
size of allocation; has no meaning for de-allocation event
addr : int
address of allocation/de-allocation
callers : list
list of callers (callstack) for event
toolchain_pref : string
toolchain prefix to retrieve source line locations using addresses
elf_path : string
path to ELF file to retrieve format strings for log messages
"""
self.ctx_name = ctx_name
self.in_irq = in_irq
self.core_id = core_id
self.ts = ts
self.alloc = alloc
self.size = size
self.addr = addr
self.callers = callers
self.toolchain = toolchain
self.elf_path = elf_path
def __repr__(self):
if len(self.toolchain) and len(self.elf_path):
callers = os.linesep
for addr in self.callers:
callers += '{}'.format(addr2line(self.toolchain, self.elf_path, addr))
else:
callers = ''
for addr in self.callers:
if len(callers):
callers += ':'
callers += '0x{:x}'.format(addr)
if self.in_irq:
ctx_desc = 'IRQ "%s"' % self.ctx_name
else:
ctx_desc = 'task "%s"' % self.ctx_name
if self.alloc:
return "[{:.9f}] HEAP: Allocated {:d} bytes @ 0x{:x} from {} on core {:d} by: {}".format(self.ts, self.size,
self.addr, ctx_desc,
self.core_id, callers)
else:
return "[{:.9f}] HEAP: Freed bytes @ 0x{:x} from {} on core {:d} by: {}".format(self.ts, self.addr, ctx_desc,
self.core_id, callers)
class BaseHeapTraceDataProcessorImpl:
"""
Base implementation for heap data processors.
"""
def __init__(self, print_heap_events=False):
"""
Constructor.
Parameters
----------
print_heap_events : bool
if True every heap event will be printed as they arrive
"""
self._alloc_addrs = {}
self.allocs = []
self.frees = []
self.heap_events_count = 0
self.print_heap_events = print_heap_events
def on_new_event(self, event):
"""
Processes heap events. Keeps track of active allocations list.
Parameters
----------
event : HeapTraceEvent
Event object.
"""
self.heap_events_count += 1
if self.print_heap_events:
print(event)
if event.alloc:
if event.addr in self._alloc_addrs:
raise HeapTraceDuplicateAllocError(event.addr, event.size, self._alloc_addrs[event.addr].size)
self.allocs.append(event)
self._alloc_addrs[event.addr] = event
else:
# do not treat free on unknown addresses as errors, because these blocks coould be allocated when tracing was disabled
if event.addr in self._alloc_addrs:
event.size = self._alloc_addrs[event.addr].size
self.allocs.remove(self._alloc_addrs[event.addr])
del self._alloc_addrs[event.addr]
else:
self.frees.append(event)
def print_report(self):
"""
Prints heap report
"""
print("=============== HEAP TRACE REPORT ===============")
print("Processed {:d} heap events.".format(self.heap_events_count))
if len(self.allocs) == 0:
print("OK - Heap errors was not found.")
return
leaked_bytes = 0
for alloc in self.allocs:
leaked_bytes += alloc.size
print(alloc)
for free in self.frees:
if free.addr > alloc.addr and free.addr <= alloc.addr + alloc.size:
print("Possible wrong free operation found")
print(free)
print("Found {:d} leaked bytes in {:d} blocks.".format(leaked_bytes, len(self.allocs)))

File diff suppressed because it is too large Load diff

View file

@ -5,11 +5,8 @@ from __future__ import print_function
import argparse
import struct
import sys
import pylibelf as elf
import pylibelf.util as elfutil
import pylibelf.iterators as elfiter
import pylibelf.constants as elfconst
import ctypes
import elftools.elf.elffile as elffile
import espytrace.apptrace as apptrace
class ESPLogTraceParserError(RuntimeError):
@ -77,34 +74,14 @@ def logtrace_parse(fname):
return recs
def logtrace_get_str_from_elf(felf, str_addr):
tgt_str = ""
for sect in elfiter.sections(felf):
hdr = elfutil.section_hdr(felf, sect)
if hdr.sh_addr == 0 or hdr.sh_type != elfconst.SHT_PROGBITS:
continue
if str_addr < hdr.sh_addr or str_addr >= hdr.sh_addr + hdr.sh_size:
continue
# print("Found SECT: %x..%x @ %x" % (hdr.sh_addr, hdr.sh_addr + hdr.sh_size, str_addr - hdr.sh_addr))
sec_data = elfiter.getOnlyData(sect).contents
buf = ctypes.cast(sec_data.d_buf, ctypes.POINTER(ctypes.c_char))
for i in range(str_addr - hdr.sh_addr, hdr.sh_size):
if buf[i] == "\0":
break
tgt_str += buf[i]
if len(tgt_str) > 0:
return tgt_str
return None
def logtrace_formated_print(recs, elfname, no_err):
try:
felf = elfutil.open_elf(elfname)
felf = elffile.ELFFile(open(elfname, 'rb'))
except OSError as e:
raise ESPLogTraceParserError("Failed to open ELF file (%s)!" % e)
for lrec in recs:
fmt_str = logtrace_get_str_from_elf(felf, lrec.fmt_addr)
fmt_str = apptrace.get_str_from_elf(felf, lrec.fmt_addr)
i = 0
prcnt_idx = 0
while i < len(lrec.args):
@ -114,7 +91,7 @@ def logtrace_formated_print(recs, elfname, no_err):
prcnt_idx += 1 # goto next char
if fmt_str[prcnt_idx] == 's':
# find string
arg_str = logtrace_get_str_from_elf(felf, lrec.args[i])
arg_str = apptrace.get_str_from_elf(felf, lrec.args[i])
if arg_str:
lrec.args[i] = arg_str
i += 1
@ -129,8 +106,7 @@ def logtrace_formated_print(recs, elfname, no_err):
if not no_err:
print("Print error (%s)" % e)
print("\nFmt = {%s}, args = %d/%s" % (fmt_str, len(lrec.args), lrec.args))
elf.elf_end(felf)
felf.stream.close()
def main():

View file

@ -1,59 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
*.swp
*.swo
*.swn

View file

@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 d1m0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,5 +0,0 @@
pylibelf
========
Python binding for libelf.

View file

@ -1,155 +0,0 @@
from types import *
from constants import *
from ctypes import *
lelf=CDLL("libelf.so.1")
__all__ = []
all_objs = []
class ElfError(Exception):
def __init__(self, msg):
self.msg = msg
self.errno = elf_errno()
self.elfmsg = elf_errmsg(self.errno)
def __str__(self):
return "ElfError(%d, %s): %s" % (self.errno, self.elfmsg, self.msg)
__all__.append("ElfError")
def nonNullDec(f):
def decorated(*args):
res = f(*args)
try:
a = res.contents
all_objs.append(res)
except ValueError: # NULL
raise ElfError(f.__name__ + " returned NULL")
return res
return decorated
def nonNegDec(f):
def decorated(*args):
res = f(*args)
if 0 > res:
raise ElfError(f.__name__ + " returned %d" % (res,))
return res
return decorated
def badValDec(badVal):
def decorator(f):
def decorated(*args):
res = f(*args)
if res == badVal:
raise ElfError(f.__name__ + " returned %s" % (str(res),))
return res
return decorated
return decorator
def define(f, argtypes, restype, err_decorator = None):
f.argtypes = argtypes
f.restype = restype
name = f.__name__
__all__.append(name)
if (err_decorator != None):
f = err_decorator(f)
globals()[name] = f
define(lelf.elf_version, [ c_int ], c_int )
if (elf_version(EV_CURRENT) == EV_NONE):
raise Exception("Version mismatch")
off_t = c_size_t # TODO(dbounov): Figure out actual off_t type
define(lelf.elf_begin, [ c_int, Elf_Cmd, ElfP ], ElfP)
define(lelf.elf_getident, [ ElfP, POINTER(c_int) ], POINTER(Elf_IdentT), nonNullDec)
define(lelf.elf_end, [ ElfP ], c_int, nonNegDec )
define(lelf.elf_cntl, [ ElfP, c_int ], c_int, nonNegDec)
define(lelf.elf_errmsg, [ c_int ], c_char_p)
define(lelf.elf_errno, [ ], c_int)
define(lelf.elf_fill, [ c_int ], None)
define(lelf.elf_flagdata, [ Elf_DataP, c_int, c_uint ], c_uint)
define(lelf.elf_flagehdr, [ ElfP, c_int, c_uint ], c_uint)
define(lelf.elf_flagelf, [ ElfP, c_int, c_uint ], c_uint)
define(lelf.elf_flagphdr, [ ElfP, c_int, c_uint ], c_uint)
define(lelf.elf_flagscn, [ Elf_ScnP, c_int, c_uint ], c_uint)
define(lelf.elf_flagshdr, [ Elf_ScnP, c_int, c_uint ], c_uint)
define(lelf.elf_getarhdr, [ ElfP ], POINTER(Elf_Arhdr))
#define(lelf.elf_getarsym, [ ], )
define(lelf.elf_getbase, [ ElfP ], off_t, nonNegDec)
define(lelf.elf_getdata, [ Elf_ScnP, Elf_DataP ], Elf_DataP)
define(lelf.elf_getscn, [ ElfP, c_size_t ], Elf_ScnP, nonNullDec )
define(lelf.elf_getshnum, [ ElfP, POINTER(c_size_t) ], c_int, nonNegDec )
define(lelf.elf_getshstrndx, [ ElfP, POINTER(c_size_t) ], c_int, nonNegDec )
define(lelf.elf_hash, [ c_char_p ], c_ulong)
define(lelf.elf_kind, [ ElfP ], c_int )
define(lelf.elf_memory, [ POINTER(c_char), c_size_t ], ElfP, nonNullDec)
define(lelf.elf_ndxscn, [ Elf_ScnP ], c_size_t, badValDec(SHN_UNDEF))
define(lelf.elf_newdata, [ Elf_ScnP ], Elf_DataP, nonNullDec)
define(lelf.elf_newscn, [ ElfP ], Elf_ScnP, nonNullDec)
#define(lelf.elf_next, [ ], )
define(lelf.elf_nextscn, [ ElfP, Elf_ScnP ], Elf_ScnP)
#define(lelf.elf_rand, [ ], )
define(lelf.elf_rawdata, [ Elf_ScnP, Elf_DataP ], Elf_DataP)
#define(lelf.elf_rawfile, [ ], )
define(lelf.elf_strptr, [ ElfP, c_size_t, c_size_t ], c_char_p)
define(lelf.elf_update, [ ElfP, c_int], off_t, nonNegDec)
define(lelf.elf32_checksum, [ ElfP ], c_long)
define(lelf.elf32_fsize, [ c_int, c_size_t, c_uint ], c_size_t, nonNegDec)
define(lelf.elf32_getehdr, [ ElfP ], POINTER(Elf32_Ehdr), nonNullDec)
define(lelf.elf32_getphdr, [ ElfP ], POINTER(Elf32_Phdr), nonNullDec)
define(lelf.elf32_getshdr, [ Elf_ScnP ], POINTER(Elf32_Shdr), nonNullDec)
define(lelf.elf32_newehdr, [ ElfP ], POINTER(Elf32_Ehdr), nonNullDec)
define(lelf.elf32_newphdr, [ ElfP, c_size_t ], POINTER(Elf32_Phdr), nonNullDec)
define(lelf.elf32_xlatetof, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec)
define(lelf.elf32_xlatetom, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec)
define(lelf.elf64_checksum, [ ElfP ], c_long )
define(lelf.elf64_fsize, [ c_int, c_size_t, c_uint ], c_size_t, nonNegDec)
define(lelf.elf64_getehdr,[ ElfP ], POINTER(Elf64_Ehdr), nonNullDec)
define(lelf.elf64_getphdr, [ ElfP ], POINTER(Elf64_Phdr), nonNullDec)
define(lelf.elf64_getshdr, [ Elf_ScnP ], POINTER(Elf64_Shdr), nonNullDec)
define(lelf.elf64_newehdr, [ ElfP ], POINTER(Elf64_Ehdr), nonNullDec)
define(lelf.elf64_newphdr, [ ElfP, c_size_t ], POINTER(Elf64_Phdr), nonNullDec)
define(lelf.elf64_xlatetof, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec)
define(lelf.elf64_xlatetom, [ Elf_DataP, Elf_DataP, c_uint ], Elf_DataP, nonNullDec)
# NOTE(dbounov): Ignoring gelf functions for now
#define(lelf.gelf_checksum, [ ], )
#define(lelf.gelf_fsize, [ ], )
#define(lelf.gelf_getcap, [ ], )
#define(lelf.gelf_getclass, [ ], )
#define(lelf.gelf_getdyn, [ ], )
#define(lelf.gelf_getehdr, [ ], )
#define(lelf.gelf_getmove, [ ], )
#define(lelf.gelf_getphdr, [ ], )
#define(lelf.gelf_getrel, [ ], )
#define(lelf.gelf_getrela, [ ], )
#define(lelf.gelf_getshdr, [ ], )
#define(lelf.gelf_getsym, [ ], )
#define(lelf.gelf_getsyminfo, [ ], )
#define(lelf.gelf_getsymshndx, [ ], )
#define(lelf.gelf_newehdr, [ ], )
#define(lelf.gelf_newphdr, [ ], )
#define(lelf.gelf_update_cap, [ ], )
#define(lelf.gelf_update_dyn, [ ], )
#define(lelf.gelf_update_ehdr, [ ], )
#define(lelf.gelf_update_move, [ ], )
#define(lelf.gelf_update_phdr, [ ], )
#define(lelf.gelf_update_rel, [ ], )
#define(lelf.gelf_update_rela, [ ], )
#define(lelf.gelf_update_shdr, [ ], )
#define(lelf.gelf_update_sym, [ ], )
#define(lelf.gelf_update_symshndx, [ ], )
#define(lelf.gelf_update_syminfo, [ ], )
#define(lelf.gelf_xlatetof, [ ], )
#define(lelf.gelf_xlatetom, [ ], )
#define(lelf.nlist, [ ], )

File diff suppressed because it is too large Load diff

View file

@ -1,216 +0,0 @@
import sys
import os
from .. import *
from ..constants import *
from ..types import *
from ..util import *
from ctypes import *
def sections(elf, **kwargs):
i = None
ndx = 0 # we skip the first null section
if 'info' in kwargs:
if (isinstance(kwargs['info'], Elf_Scn)):
info = elf_ndxscn(kwargs['info'])
else:
info = kwargs['info']
else:
info = None
while 1:
i = elf_nextscn(elf, i)
ndx += 1
if (not bool(i)):
break
try:
if ('name' in kwargs and section_name(elf, i) != kwargs['name']):
continue
if ('type' in kwargs and section_type(elf, i) != kwargs['type']):
continue
if ('link' in kwargs and section_link(elf, i) != kwargs['link']):
continue
if (info != None and section_hdr(elf, i).sh_info != info):
continue
except ValueError:
print "Error iterating over section ", i
continue
if ('ndx' in kwargs and kwargs['ndx']):
yield (ndx, i.contents)
else:
yield i.contents
def shdrs(elf):
i = None
while 1:
i = elf_nextscn(elf, i)
if (not bool(i)):
break
yield select(elf, 'getshdr')(i.contents).contents
def phdrs(elf):
phdrTbl = select(elf, "getphdr")(elf)
ehdr = select(elf, "getehdr")(elf).contents
phdrCnt = ehdr.e_phnum
for i in xrange(0, phdrCnt):
yield phdrTbl[i]
def data(elf_scn):
i = None
while 1:
i = elf_getdata(elf_scn, i)
if (not bool(i)):
break
yield i.contents
def strings(v):
if (isinstance(v, Elf_Data)):
strtab_data = v
size = strtab_data.d_size
buf = cast(strtab_data.d_buf, POINTER(c_char))
start = 0;
while start < size:
end = start;
while buf[end] != '\x00': end += 1
yield (strtab_data.d_off + start, buf[start:end])
start = end+1
elif (isinstance(v, Elf_Scn)):
for d in data(v):
strtab_data = d
size = strtab_data.d_size
buf = cast(strtab_data.d_buf, POINTER(c_char))
start = 0;
while start < size:
end = start;
while buf[end] != '\x00': end += 1
yield (strtab_data.d_off + start, buf[start:end])
start = end+1
def arr_iter(data, itemT, ind = False):
size = data.d_size
if size % sizeof(itemT) != 0:
raise Exception("Data size not a multiple of symbol size!")
buf = cast(data.d_buf, POINTER(itemT))
nelems = size / sizeof(itemT)
for i in xrange(0, nelems):
if ind:
yield (i, buf[i])
else:
yield buf[i]
def syms(elf, v = None):
symT = Elf32_Sym if (is32(elf)) else Elf64_Sym
if v == None:
for s in sections(elf):
hdr = section_hdr(elf, s)
if (hdr.sh_type != SHT_SYMTAB and hdr.sh_type != SHT_DYNSYM):
continue
for d in data(s):
for (ind, sym) in arr_iter(d, symT, True):
yield (ind, sym)
elif isinstance(v, Elf_Scn):
for d in data(v):
for (ind, sym) in arr_iter(d, symT, True):
yield (ind, sym)
else:
assert isinstance(v, Elf_Data)
for (ind, sym) in arr_iter(v, symT, True):
yield (ind, sym)
def rels(elf, **kwargs):
relT = Elf32_Rel if (is32(elf)) else Elf64_Rel
if 'section' in kwargs:
secl = sections(elf, type = SHT_REL, info = kwargs['section'])
else:
secl = sections(elf, type = SHT_REL)
if 'range' in kwargs:
for scn in secl:
for d in data(scn):
for rel in arr_iter(d, relT):
if (rel.r_offset >= kwargs['range'][0] and
rel.r_offset < kwargs['range'][1]):
yield (rel, section_hdr(elf, scn).sh_link)
else:
for scn in secl:
for d in data(scn):
for rel in arr_iter(d, relT):
yield (rel, section_hdr(elf, scn).sh_link)
def relas(elf, **kwargs):
relT = Elf32_Rela if (is32(elf)) else Elf64_Rela
if 'section' in kwargs:
scn = kwargs['section']
if (type(scn) == str): scn = list(sections(elf, name=scn))[0]
if (isinstance(scn, Elf_Scn)): scn = elf_ndxscn(byref(scn))
secl = list(sections(elf, type = SHT_RELA, info = scn))
else:
secl = list(sections(elf, type = SHT_RELA))
if 'range' in kwargs:
for scn in secl:
for d in data(scn):
for rel in arr_iter(d, relT):
if (rel.r_offset + rel.r_addend >= kwargs['range'][0] and
rel.r_offset + rel.r_addend < kwargs['range'][1]):
yield (rel, section_hdr(elf, scn).sh_link)
else:
addSecId = kwargs['withSectionId']==True \
if 'withSectionId' in kwargs \
else False
if not addSecId:
for scn in secl:
for d in data(scn):
for rel in arr_iter(d, relT):
yield (rel, section_hdr(elf, scn).sh_link)
else:
for scn in secl:
for d in data(scn):
for rel in arr_iter(d, relT):
yield (rel, section_hdr(elf, scn).sh_info)
def getOnlyData(scn):
d = elf_getdata(scn, None);
assert bool(elf_getdata(scn, d)) == False
return d
def dyns(elf):
relT = Elf64_Dyn
for scn in sections(elf, name=".dynamic"):
for d in data(scn):
for dyn in arr_iter(d, relT):
yield dyn
def elfs(fname):
fd = os.open(fname, os.O_RDONLY)
ar = elf_begin(fd, ELF_C_READ, None)
i = None
while 1:
i = elf_begin(fd, ELF_C_READ, ar)
if (not bool(i)):
break
yield i
elf_end(ar)
os.close(fd)

View file

@ -1,55 +0,0 @@
def ELF32_R_SYM(i):
if type(i) == str:
assert(len(i) == 1) # Single char
i = ord(i)
return i >> 8
def ELF32_R_TYPE(i):
if type(i) == str:
assert(len(i) == 1) # Single char
i = ord(i)
return i % 256 # Lowest 8 bits
def ELF32_R_INFO(sym, typ):
return (((sym) << 8) + typ % 256)
def ELF64_R_SYM(i):
if type(i) == str:
assert(len(i) == 1) # Single char
i = ord(i)
return i >> 32
def ELF64_R_TYPE(i):
if type(i) == str:
assert(len(i) == 1) # Single char
i = ord(i)
return i & 0xffffffffL
def ELF64_R_INFO(sym, typ):
return ((sym << 32) + (typ & 0xffffffffL))
# symbol st_info
def ELF32_ST_BIND(val):
if type(val) == str:
assert(len(val) == 1) # Single char
val = ord(val)
return val >> 4
def ELF32_ST_TYPE(val):
if type(val) == str:
assert(len(val) == 1) # Single char
val = ord(val)
return val & 0xf
def ELF32_ST_INFO(bind, type):
return (((bind) << 4) + ((type) & 0xf))
def ELF64_ST_BIND(val):
return ELF32_ST_BIND(val)
def ELF64_ST_TYPE(val):
return ELF32_ST_TYPE(val)
def ELF64_ST_INFO(bind, type):
return ELF32_ST_INFO(bind, type)

View file

@ -1,274 +0,0 @@
from ctypes import *
from ..constants import EI_NIDENT
# Obtained from /usr/lib/elf.h
# Type for a 16-bit quantity.
Elf32_Half = c_uint16
Elf64_Half = c_uint16
# Types for signed and unsigned 32-bit quantities.
Elf32_Word = c_uint32
Elf32_Sword = c_int32
Elf64_Word = c_uint32
Elf64_Sword = c_int32
# Types for signed and unsigned 64-bit quantities.
Elf32_Xword = c_uint64
Elf32_Sxword = c_int64
Elf64_Xword = c_uint64
Elf64_Sxword = c_int64
# Type of addresses.
Elf32_Addr = c_uint32
Elf64_Addr = c_uint64
# Type of file offsets.
Elf32_Off = c_uint32
Elf64_Off = c_uint64
# Type for section indices, which are 16-bit quantities.
Elf32_Section = c_uint16
Elf64_Section = c_uint16
# Type for version symbol information.
Elf32_Versym = Elf32_Half
Elf64_Versym = Elf64_Half
# The ELF file header. This appears at the start of every ELF file.
Elf_IdentT = c_char * EI_NIDENT
Elf_Cmd = c_int
class _ElfStructure(Structure):
def __str__(self):
return self.__class__.__name__ + '(' + \
','.join([field[0] + '=' + str(getattr(self, field[0])) for field in self._fields_]) + ')'
class _ElfUnion(Union):
def __str__(self):
return self.__class__.__name__ + '(' + \
','.join([field[0] + '=' + str(getattr(self, field[0])) for field in self._fields_]) + ')'
# Libelf opaque handles
class Elf(_ElfStructure):
_fields_ = []
class Elf_Scn(_ElfStructure):
_fields_ = []
class Elf_Data(_ElfStructure):
_fields_ = [
('d_buf', c_void_p),
('d_type', c_int),
('d_size', c_size_t),
('d_off', c_size_t),
('d_align', c_size_t),
('d_version', c_uint)
]
ElfP = POINTER(Elf)
Elf_ScnP = POINTER(Elf_Scn)
Elf_DataP = POINTER(Elf_Data)
class Elf32_Ehdr(_ElfStructure):
_fields_ = [
('e_ident', Elf_IdentT ), # Magic number and other info
('e_type', Elf32_Half ), # Object file type
('e_machine', Elf32_Half ), # Architecture
('e_version', Elf32_Word ), # Object file version
('e_entry', Elf32_Addr ), # Entry point virtual address
('e_phoff', Elf32_Off), # Program header table file offset
('e_shoff', Elf32_Off), # Section header table file offset
('e_flags', Elf32_Word ), # Processor-specific flags
('e_ehsize', Elf32_Half ), # ELF header size in bytes
('e_phentsize', Elf32_Half ), # Program header table entry size
('e_phnum', Elf32_Half ), # Program header table entry count
('e_shentsize', Elf32_Half ), # Section header table entry size
('e_shnum', Elf32_Half ), # Section header table entry count
('e_shstrndx', Elf32_Half ), # Section header string table index
]
class Elf64_Ehdr(_ElfStructure):
_fields_ = [
('e_ident', Elf_IdentT ), # Magic number and other info
('e_type', Elf64_Half ), # Object file type
('e_machine', Elf64_Half ), # Architecture
('e_version', Elf64_Word ), # Object file version
('e_entry', Elf64_Addr ), # Entry point virtual address
('e_phoff', Elf64_Off), # Program header table file offset
('e_shoff', Elf64_Off), # Section header table file offset
('e_flags', Elf64_Word ), # Processor-specific flags
('e_ehsize', Elf64_Half ), # ELF header size in bytes
('e_phentsize', Elf64_Half ), # Program header table entry size
('e_phnum', Elf64_Half ), # Program header table entry count
('e_shentsize', Elf64_Half ), # Section header table entry size
('e_shnum', Elf64_Half ), # Section header table entry count
('e_shstrndx', Elf64_Half ), # Section header string table index
]
class Elf32_Shdr(_ElfStructure):
_fields_ = [
('sh_name', Elf32_Word), # Section name (string tbl index)
('sh_type', Elf32_Word), # Section type
('sh_flags', Elf32_Word), # Section flags
('sh_addr', Elf32_Addr), # Section virtual addr at execution
('sh_offset', Elf32_Off), # Section file offset
('sh_size', Elf32_Word), # Section size in bytes
('sh_link', Elf32_Word), # Link to another section
('sh_info', Elf32_Word), # Additional section information
('sh_addralign', Elf32_Word), # Section alignment
('sh_entsize', Elf32_Word), # Entry size if section holds table
]
class Elf64_Shdr(_ElfStructure):
_fields_ = [
('sh_name', Elf64_Word), # Section name (string tbl index)
('sh_type', Elf64_Word), # Section type
('sh_flags', Elf64_Xword), # Section flags
('sh_addr', Elf64_Addr), # Section virtual addr at execution
('sh_offset', Elf64_Off), # Section file offset
('sh_size', Elf64_Xword), # Section size in bytes
('sh_link', Elf64_Word), # Link to another section
('sh_info', Elf64_Word), # Additional section information
('sh_addralign', Elf64_Xword), # Section alignment
('sh_entsize', Elf64_Xword), # Entry size if section holds table
]
class Elf32_Phdr(_ElfStructure):
_fields_ = [
('p_type', Elf32_Word), # Segment type
('p_offset', Elf32_Off), # Segment file offset
('p_vaddr', Elf32_Addr), # Segment virtual address
('p_paddr', Elf32_Addr), # Segment physical address
('p_filesz', Elf32_Word), # Segment size in file
('p_memsz', Elf32_Word), # Segment size in memory
('p_flags', Elf32_Word), # Segment flags
('p_align', Elf32_Word), # Segment alignment
]
class Elf64_Phdr(_ElfStructure):
_fields_ = [
('p_type', Elf64_Word), # Segment type
('p_flags', Elf64_Word), # Segment flags
('p_offset', Elf64_Off), # Segment file offset
('p_vaddr', Elf64_Addr), # Segment virtual address
('p_paddr', Elf64_Addr), # Segment physical address
('p_filesz', Elf64_Xword), # Segment size in file
('p_memsz', Elf64_Xword), # Segment size in memory
('p_align', Elf64_Xword), # Segment alignment
]
# /* Symbol table entry. */
class Elf32_Sym(_ElfStructure):
_fields_ = [
('st_name', Elf32_Word), # Symbol name (string tbl index)
('st_value', Elf32_Addr), # Symbol value
('st_size', Elf32_Word), # Symbol size
('st_info', c_char), # Symbol type and binding
('st_other', c_char), # Symbol visibility
('st_shndx', Elf32_Section), # Section index
]
class Elf64_Sym(_ElfStructure):
_fields_ = [
('st_name', Elf64_Word), # Symbol name (string tbl index)
('st_info', c_char), # Symbol type and binding
('st_other', c_char), # Symbol visibility
('st_shndx', Elf64_Section), # Section index
('st_value', Elf64_Addr), # Symbol value
('st_size', Elf64_Xword), # Symbol size
]
#/* The syminfo section if available contains additional information about
# every dynamic symbol. */
class Elf32_Syminfo(_ElfStructure):
_fields_ = [
('si_boundto', Elf32_Half), # Direct bindings, symbol bound to
('si_flags', Elf32_Half), # Per symbol flags
]
class Elf64_Syminfo(_ElfStructure):
_fields_ = [
('si_boundto', Elf64_Half), # Direct bindings, symbol bound to
('si_flags', Elf64_Half), # Per symbol flags
]
# /* Relocation table entry without addend (in section of type SHT_REL). */
class Elf32_Rel(_ElfStructure):
_fields_ = [
('r_offset', Elf32_Addr), # Address
('r_info', Elf32_Word), # Relocation type and symbol index
]
class Elf64_Rel(_ElfStructure):
_fields_ = [
('r_offset', Elf64_Addr), # Address
('r_info', Elf64_Xword), # Relocation type and symbol index
]
# # Relocation table entry with addend (in section of type SHT_RELA).
class Elf32_Rela(_ElfStructure):
_fields_ = [
('r_offset', Elf32_Addr), # Address
('r_info', Elf32_Word), # Relocation type and symbol index
('r_addend', Elf32_Sword), # Addend
]
class Elf64_Rela(_ElfStructure):
_fields_ = [
('r_offset', Elf64_Addr), # Address
('r_info', Elf64_Xword), # Relocation type and symbol index
('r_addend', Elf64_Sxword), # Addend
]
time_t = c_int64
uid_t = c_int32
gid_t = c_int32
mode_t = c_int32
off_t = c_int64
class Elf_Arhdr(_ElfStructure):
_fields_ = [
('ar_name', c_char_p),
('ar_date', time_t),
('ar_uid', uid_t),
('ar_gid', gid_t),
('ar_mode', mode_t),
('ar_size', off_t),
('ar_fmag', POINTER(c_char)),
]
class _Elf64_DynUnion(_ElfUnion):
_fields_ = [
('d_val', Elf64_Xword),
('d_ptr', Elf64_Addr),
]
class Elf64_Dyn(_ElfStructure):
_fields_ = [
('d_tag', Elf64_Xword),
('d_un', _Elf64_DynUnion),
]
# GNU Extensions
class Elf64_Verneed(_ElfStructure):
_fields_ = [
('vn_version', Elf64_Half),
('vn_cnt', Elf64_Half),
('vn_file', Elf64_Word),
('vn_aux', Elf64_Word),
('vn_next', Elf64_Word),
]
class Elf64_Vernaux(_ElfStructure):
_fields_ = [
('vna_hash', Elf64_Word),
('vna_flags', Elf64_Half),
('vna_other', Elf64_Half),
('vna_name', Elf64_Word),
('vna_next', Elf64_Word),
]

View file

@ -1,38 +0,0 @@
from .. import *
from ..types import *
from ..constants import *
from ctypes import *
import os
def _class(elf): return ord(elf_getident(elf, None).contents[EI_CLASS])
def is32(elf): return _class(elf) == ELFCLASS32
def is64(elf): return _class(elf) == ELFCLASS64
def select(elf, fname):
if is32(elf):
return globals()['elf32_' + fname]
else:
return globals()['elf64_' + fname]
def section_name(elfP, secP):
shstrndx = c_size_t()
r = elf_getshstrndx(elfP, byref(shstrndx))
shdr = select(elfP, 'getshdr')(secP)
return elf_strptr(elfP, shstrndx, shdr.contents.sh_name)
def section_type(elfP, secP):
return select(elfP, 'getshdr')(secP).contents.sh_type
def section_link(elfP, secP):
return select(elfP, 'getshdr')(secP).contents.sh_link
def section_hdr(elfP, secP):
return select(elfP, 'getshdr')(secP).contents
def open_elf(fname):
fd = os.open(fname, os.O_RDONLY)
return elf_begin(fd, ELF_C_READ, None)
def sym_name(elf, scn, sym):
return elf_strptr(elf, section_link(elf, scn), sym.st_name)

View file

@ -1,58 +0,0 @@
from .. import *
from ...types import *
from ...iterators import *
def defined(s): return s.st_shndx != SHN_UNDEF
def defines(elf, symN):
s = findSymbol(elf, symN)
print elf, symN, s
if s != None:
print s.st_shndx, s.st_name
return s != None and defined(s[1])
def derefSymbol(elf, s):
assert defined(s)
if s.st_shndx == SHN_ABS:
raise Exception("NYI")
else:
scn = elf_getscn(elf, s.st_shndx)
shdr = section_hdr(elf, scn);
off = 0
base = shdr.sh_addr if shdr.sh_addr != 0 else 0
start = s.st_value
end = s.st_value + s.st_size
r = ''
for d in data(scn):
if start >= end: break;
off = base + d.d_off
if start >= off and start < off + d.d_size:
c = cast(d.d_buf, POINTER(c_char))
l = min(off + d.d_size, end) - start
r += c[start- off : start - off + l]
start += l
return r
def derefSymbolFull(elf, s):
""" Given an elf file and a Elf{32/64}_Sym defined in the elf file,
return a tuple with the contents of memory refered to by the symbol,
and any Rel's and Rela's inside that memory.
"""
assert (defined(s))
contents = derefSymbol(elf, s)
relL = list(rels(elf, section=s.st_shndx, \
range=(s.st_value, s.st_size + s.st_value)))
relaL = list(relas(elf, section=s.st_shndx, \
range=(s.st_value, s.st_size + s.st_value)))
return (contents, relL, relaL)
# Given a symbol name return the symbol and section in which it occurs
def findSymbol(elf, s):
for scn in sections(elf, type=SHT_SYMTAB):
strndx = section_link(elf, scn)
for d in data(scn):
for (ind, sym) in syms(elf, d):
if s == elf_strptr(elf, strndx, sym.st_name):
return (scn, sym)
return None

View file

@ -0,0 +1,119 @@
#!/usr/bin/env python
#
# Copyright 2019 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.
#
# This is python script to process various types trace data streams in SystemView format.
# Trace data can be provided in multiple trace files (one per CPU). After processing phase
# script prints report for every type of trace data stream which was found.
#
import argparse
import sys
import os.path
import signal
import traceback
import espytrace.apptrace as apptrace
import espytrace.sysview as sysview
def main():
parser = argparse.ArgumentParser(description='ESP32 SEGGER SystemView Trace Parsing Tool')
parser.add_argument('trace_sources', help='Trace data sources. Format: [file://]/path/to/file.', nargs='+', type=str)
parser.add_argument('elf_file', help='Path to program ELF file.', type=str)
parser.add_argument('--tmo', '-w', help='Data wait timeout in sec. -1: infinite, 0: no wait', type=int, default=0)
parser.add_argument('--dump-events', '-d', help='Dump all events.', action='store_true')
parser.add_argument('--print-events', '-p', help='Print events of selected types. By default only reports are printed', action='store_true')
parser.add_argument('--include-events', '-i', help='Events types to be included into report.', type=str, choices=['heap', 'log', 'all'], default='all')
parser.add_argument('--toolchain', '-t', help='Toolchain prefix.', type=str, default='xtensa-esp32-elf-')
parser.add_argument('--events-map', '-e', help='Events map file.', type=str, default=os.path.join(os.path.dirname(__file__), 'SYSVIEW_FreeRTOS.txt'))
args = parser.parse_args()
def sig_int_handler(signum, frame):
reader.cleanup()
signal.signal(signal.SIGINT, sig_int_handler)
include_events = {'heap': False, 'log': False}
if args.include_events == 'all':
for k in include_events:
include_events[k] = True
elif args.include_events == 'heap':
include_events['heap'] = True
elif args.include_events == 'log':
include_events['log'] = True
# parse trace files
parsers = []
for i, trace_source in enumerate(args.trace_sources):
try:
parser = sysview.SysViewMultiTraceDataParser(print_events=False, core_id=i)
if include_events['heap']:
parser.add_stream_parser(sysview.SysViewTraceDataParser.STREAMID_HEAP,
sysview.SysViewHeapTraceDataParser(print_events=False, core_id=i))
if include_events['log']:
parser.add_stream_parser(sysview.SysViewTraceDataParser.STREAMID_LOG,
sysview.SysViewLogTraceDataParser(print_events=False, core_id=i))
parsers.append(parser)
except Exception as e:
print("Failed to create data parser ({})!".format(e))
traceback.print_exc()
sys.exit(2)
reader = apptrace.reader_create(trace_source, args.tmo)
if not reader:
print("Failed to create trace reader!")
sys.exit(2)
try:
print("Parse trace from '{}'...".format(trace_source))
sysview.parse_trace(reader, parser, args.events_map)
print("Parsing completed.")
except (apptrace.ReaderTimeoutError, apptrace.ReaderShutdownRequest) as e:
print("Stop parsing trace. ({})".format(e))
except Exception as e:
print("Failed to parse trace ({})!".format(e))
parser.cleanup()
traceback.print_exc()
sys.exit(2)
finally:
reader.cleanup()
# merge and process traces
try:
proc = sysview.SysViewMultiTraceDataProcessor(traces=parsers, print_events=args.dump_events)
if include_events['heap']:
proc.add_stream_processor(sysview.SysViewTraceDataParser.STREAMID_HEAP,
sysview.SysViewHeapTraceDataProcessor(args.toolchain, args.elf_file, print_heap_events=args.print_events))
if include_events['log']:
proc.add_stream_processor(sysview.SysViewTraceDataParser.STREAMID_LOG,
sysview.SysViewLogTraceDataProcessor(print_log_events=args.print_events))
except Exception as e:
print("Failed to create data processor ({})!".format(e))
traceback.print_exc()
sys.exit(2)
try:
print("Process events from '{}'...".format(args.trace_sources))
proc.merge_and_process()
print("Processing completed.")
except Exception as e:
print("Failed to process trace ({})!".format(e))
traceback.print_exc()
sys.exit(2)
finally:
proc.print_report()
if __name__ == '__main__':
main()

Binary file not shown.

View file

@ -0,0 +1,436 @@
Parse trace file 'adc_log.trc'...
Unprocessed 7 bytes of log record args!
Parsing completed.
====================================================================
I (75854) example: Sample:1, Value:0
I (75854) example: Sample:2, Value:0
I (75854) example: Sample:3, Value:0
I (75854) example: Sample:4, Value:0
I (75854) example: Sample:5, Value:0
I (75854) example: Sample:6, Value:0
I (75854) example: Sample:7, Value:0
I (75854) example: Sample:8, Value:0
I (75854) example: Sample:9, Value:0
I (75854) example: Sample:10, Value:0
I (75854) example: Sample:11, Value:0
I (75854) example: Sample:12, Value:0
I (75854) example: Sample:13, Value:0
I (75854) example: Sample:14, Value:0
I (75854) example: Sample:15, Value:0
I (75854) example: Sample:16, Value:0
I (75854) example: Sample:17, Value:0
I (75854) example: Sample:18, Value:0
I (75854) example: Sample:19, Value:0
I (75854) example: Sample:20, Value:0
I (75854) example: Sample:21, Value:0
I (75854) example: Sample:22, Value:0
I (75854) example: Sample:23, Value:0
I (75854) example: Sample:24, Value:0
I (75854) example: Sample:25, Value:0
I (75854) example: Sample:26, Value:0
I (75854) example: Sample:27, Value:0
I (75854) example: Sample:28, Value:0
I (75854) example: Sample:29, Value:0
I (75854) example: Sample:30, Value:0
I (75854) example: Sample:31, Value:0
I (75854) example: Sample:32, Value:0
I (75854) example: Sample:33, Value:0
I (75854) example: Sample:34, Value:0
I (75854) example: Sample:35, Value:0
I (75854) example: Sample:36, Value:0
I (75854) example: Sample:37, Value:0
I (75854) example: Sample:38, Value:0
I (75854) example: Sample:39, Value:0
I (75854) example: Sample:40, Value:0
I (75854) example: Sample:41, Value:0
I (75854) example: Sample:42, Value:0
I (75854) example: Sample:43, Value:0
I (75854) example: Sample:44, Value:0
I (75854) example: Sample:45, Value:0
I (75854) example: Sample:46, Value:0
I (75854) example: Sample:47, Value:0
I (75854) example: Sample:48, Value:0
I (75854) example: Sample:49, Value:0
I (75854) example: Sample:50, Value:0
I (75854) example: Sample:51, Value:0
I (75854) example: Sample:52, Value:0
I (75854) example: Sample:53, Value:0
I (75854) example: Sample:54, Value:0
I (75854) example: Sample:55, Value:0
I (75854) example: Sample:56, Value:0
I (75854) example: Sample:57, Value:0
I (75854) example: Sample:58, Value:0
I (75854) example: Sample:59, Value:0
I (75854) example: Sample:60, Value:0
I (75854) example: Sample:61, Value:0
I (75854) example: Sample:62, Value:0
I (75854) example: Sample:63, Value:0
I (75854) example: Sample:64, Value:0
I (75854) example: Sample:65, Value:0
I (75854) example: Sample:66, Value:0
I (75854) example: Sample:67, Value:0
I (75854) example: Sample:68, Value:0
I (75854) example: Sample:69, Value:0
I (75854) example: Sample:70, Value:0
I (75854) example: Sample:71, Value:0
I (75854) example: Sample:72, Value:0
I (75854) example: Sample:73, Value:0
I (75854) example: Sample:74, Value:0
I (75854) example: Sample:75, Value:0
I (75854) example: Sample:76, Value:0
I (75854) example: Sample:77, Value:0
I (75854) example: Sample:78, Value:0
I (75854) example: Sample:79, Value:0
I (75854) example: Sample:80, Value:0
I (75854) example: Sample:81, Value:0
I (75854) example: Sample:82, Value:0
I (75854) example: Sample:83, Value:0
I (75854) example: Sample:84, Value:0
I (75854) example: Sample:85, Value:0
I (75854) example: Sample:86, Value:0
I (75854) example: Sample:87, Value:0
I (75854) example: Sample:88, Value:0
I (75854) example: Sample:89, Value:0
I (75854) example: Sample:90, Value:0
I (75854) example: Sample:91, Value:0
I (75854) example: Sample:92, Value:0
I (75854) example: Sample:93, Value:0
I (75854) example: Sample:94, Value:0
I (75854) example: Sample:95, Value:0
I (75854) example: Sample:96, Value:0
I (75854) example: Sample:97, Value:0
I (75854) example: Sample:98, Value:0
I (75854) example: Sample:99, Value:0
I (75854) example: Sample:100, Value:0
I (75854) example: Sample:101, Value:0
I (75854) example: Sample:102, Value:0
I (75854) example: Sample:103, Value:0
I (75854) example: Sample:104, Value:0
I (75854) example: Sample:105, Value:0
I (75854) example: Sample:106, Value:0
I (75854) example: Sample:107, Value:0
I (75854) example: Sample:108, Value:0
I (75854) example: Sample:109, Value:0
I (75854) example: Sample:110, Value:0
I (75854) example: Sample:111, Value:0
I (75854) example: Sample:112, Value:0
I (75854) example: Sample:113, Value:0
I (75854) example: Sample:114, Value:0
I (75854) example: Sample:115, Value:0
I (75854) example: Sample:116, Value:0
I (75854) example: Sample:117, Value:0
I (75854) example: Sample:118, Value:0
I (75854) example: Sample:119, Value:0
I (75854) example: Sample:120, Value:0
I (75854) example: Sample:121, Value:0
I (75854) example: Sample:122, Value:0
I (75854) example: Sample:123, Value:0
I (75854) example: Sample:124, Value:0
I (75854) example: Sample:125, Value:0
I (75854) example: Sample:126, Value:0
I (75854) example: Sample:127, Value:0
I (75854) example: Sample:128, Value:0
I (75854) example: Sample:129, Value:0
I (75854) example: Sample:130, Value:0
I (75854) example: Sample:131, Value:0
I (75854) example: Sample:132, Value:0
I (75854) example: Sample:133, Value:0
I (75854) example: Sample:134, Value:0
I (75854) example: Sample:135, Value:0
I (75854) example: Sample:136, Value:0
I (75854) example: Sample:137, Value:0
I (75854) example: Sample:138, Value:0
I (75854) example: Sample:139, Value:0
I (75854) example: Sample:140, Value:0
I (75854) example: Sample:141, Value:0
I (75854) example: Sample:142, Value:0
I (75854) example: Sample:143, Value:0
I (75854) example: Sample:144, Value:0
I (75854) example: Sample:145, Value:0
I (75854) example: Sample:146, Value:0
I (75854) example: Sample:147, Value:0
I (75854) example: Sample:148, Value:0
I (75854) example: Sample:149, Value:0
I (75854) example: Sample:150, Value:0
I (75854) example: Sample:151, Value:0
I (75854) example: Sample:152, Value:0
I (75854) example: Sample:153, Value:0
I (75854) example: Sample:154, Value:0
I (75854) example: Sample:155, Value:0
I (75854) example: Sample:156, Value:0
I (75854) example: Sample:157, Value:0
I (75854) example: Sample:158, Value:0
I (75854) example: Sample:159, Value:0
I (75854) example: Sample:160, Value:0
I (75854) example: Sample:161, Value:0
I (75854) example: Sample:162, Value:0
I (75854) example: Sample:163, Value:0
I (75854) example: Sample:164, Value:0
I (75854) example: Sample:165, Value:0
I (75854) example: Sample:166, Value:0
I (75854) example: Sample:167, Value:0
I (75854) example: Sample:168, Value:0
I (75854) example: Sample:169, Value:0
I (75854) example: Sample:170, Value:0
I (75854) example: Sample:171, Value:0
I (75854) example: Sample:172, Value:0
I (75854) example: Sample:173, Value:0
I (75854) example: Sample:174, Value:0
I (75854) example: Sample:175, Value:0
I (75854) example: Sample:176, Value:0
I (75864) example: Sample:177, Value:0
I (75864) example: Sample:178, Value:0
I (75864) example: Sample:179, Value:0
I (75864) example: Sample:180, Value:0
I (75864) example: Sample:181, Value:0
I (75864) example: Sample:182, Value:0
I (75864) example: Sample:183, Value:0
I (75864) example: Sample:184, Value:0
I (75864) example: Sample:185, Value:0
I (75864) example: Sample:186, Value:0
I (75864) example: Sample:187, Value:0
I (75864) example: Sample:188, Value:0
I (75864) example: Sample:189, Value:0
I (75864) example: Sample:190, Value:0
I (75864) example: Sample:191, Value:0
I (75864) example: Sample:192, Value:0
I (75864) example: Sample:193, Value:0
I (75864) example: Sample:194, Value:0
I (75864) example: Sample:195, Value:0
I (75864) example: Sample:196, Value:0
I (75864) example: Sample:197, Value:0
I (75864) example: Sample:198, Value:0
I (75864) example: Sample:199, Value:0
I (75864) example: Sample:200, Value:0
I (75864) example: Sample:201, Value:0
I (75864) example: Sample:202, Value:0
I (75864) example: Sample:203, Value:0
I (75864) example: Sample:204, Value:0
I (75864) example: Sample:205, Value:0
I (75864) example: Sample:206, Value:0
I (75864) example: Sample:207, Value:0
I (75864) example: Sample:208, Value:0
I (75864) example: Sample:209, Value:0
I (75864) example: Sample:210, Value:0
I (75864) example: Sample:211, Value:0
I (75864) example: Sample:212, Value:0
I (75864) example: Sample:213, Value:0
I (75864) example: Sample:214, Value:0
I (75864) example: Sample:215, Value:0
I (75864) example: Sample:216, Value:0
I (75864) example: Sample:217, Value:0
I (75864) example: Sample:218, Value:0
I (75864) example: Sample:219, Value:0
I (75864) example: Sample:220, Value:0
I (75864) example: Sample:221, Value:0
I (75864) example: Sample:222, Value:0
I (75864) example: Sample:223, Value:0
I (75864) example: Sample:224, Value:0
I (75864) example: Sample:225, Value:0
I (75864) example: Sample:226, Value:0
I (75864) example: Sample:227, Value:0
I (75864) example: Sample:228, Value:0
I (75864) example: Sample:229, Value:0
I (75864) example: Sample:230, Value:0
I (75864) example: Sample:231, Value:0
I (75864) example: Sample:232, Value:0
I (75864) example: Sample:233, Value:0
I (75864) example: Sample:234, Value:0
I (75864) example: Sample:235, Value:0
I (75864) example: Sample:236, Value:0
I (75864) example: Sample:237, Value:0
I (75864) example: Sample:238, Value:0
I (75864) example: Sample:239, Value:0
I (75864) example: Sample:240, Value:0
I (75864) example: Sample:241, Value:0
I (75864) example: Sample:242, Value:0
I (75864) example: Sample:243, Value:0
I (75864) example: Sample:244, Value:0
I (75864) example: Sample:245, Value:0
I (75864) example: Sample:246, Value:0
I (75864) example: Sample:247, Value:0
I (75864) example: Sample:248, Value:0
I (75864) example: Sample:249, Value:0
I (75864) example: Sample:250, Value:0
I (75864) example: Sample:251, Value:0
I (75864) example: Sample:252, Value:0
I (75864) example: Sample:253, Value:0
I (75864) example: Sample:254, Value:0
I (75864) example: Sample:255, Value:0
I (75864) example: Sample:256, Value:0
I (75864) example: Sample:257, Value:0
I (75864) example: Sample:258, Value:0
I (75864) example: Sample:259, Value:0
I (75864) example: Sample:260, Value:0
I (75864) example: Sample:261, Value:0
I (75864) example: Sample:262, Value:0
I (75864) example: Sample:263, Value:0
I (75864) example: Sample:264, Value:0
I (75864) example: Sample:265, Value:0
I (75864) example: Sample:266, Value:0
I (75864) example: Sample:267, Value:0
I (75864) example: Sample:268, Value:0
I (75864) example: Sample:269, Value:0
I (75864) example: Sample:270, Value:0
I (75864) example: Sample:271, Value:0
I (75864) example: Sample:272, Value:0
I (75864) example: Sample:273, Value:0
I (75864) example: Sample:274, Value:0
I (75864) example: Sample:275, Value:0
I (75864) example: Sample:276, Value:0
I (75864) example: Sample:277, Value:0
I (75864) example: Sample:278, Value:0
I (75864) example: Sample:279, Value:0
I (75864) example: Sample:280, Value:0
I (75864) example: Sample:281, Value:0
I (75864) example: Sample:282, Value:0
I (75864) example: Sample:283, Value:0
I (75864) example: Sample:284, Value:0
I (75864) example: Sample:285, Value:0
I (75864) example: Sample:286, Value:0
I (75864) example: Sample:287, Value:0
I (75864) example: Sample:288, Value:0
I (75864) example: Sample:289, Value:0
I (75864) example: Sample:290, Value:0
I (75864) example: Sample:291, Value:0
I (75864) example: Sample:292, Value:0
I (75864) example: Sample:293, Value:0
I (75864) example: Sample:294, Value:0
I (75864) example: Sample:295, Value:0
I (75864) example: Sample:296, Value:0
I (75864) example: Sample:297, Value:0
I (75864) example: Sample:298, Value:0
I (75864) example: Sample:299, Value:0
I (75864) example: Sample:300, Value:0
I (75864) example: Sample:301, Value:0
I (75864) example: Sample:302, Value:0
I (75864) example: Sample:303, Value:0
I (75864) example: Sample:304, Value:0
I (75864) example: Sample:305, Value:0
I (75864) example: Sample:306, Value:0
I (75864) example: Sample:307, Value:0
I (75864) example: Sample:308, Value:0
I (75864) example: Sample:309, Value:0
I (75864) example: Sample:310, Value:0
I (75864) example: Sample:311, Value:0
I (75864) example: Sample:312, Value:0
I (75864) example: Sample:313, Value:0
I (75864) example: Sample:314, Value:0
I (75864) example: Sample:315, Value:0
I (75864) example: Sample:316, Value:0
I (75864) example: Sample:317, Value:0
I (75864) example: Sample:318, Value:0
I (75864) example: Sample:319, Value:0
I (75864) example: Sample:320, Value:0
I (75864) example: Sample:321, Value:0
I (75864) example: Sample:322, Value:0
I (75864) example: Sample:323, Value:0
I (75864) example: Sample:324, Value:0
I (75864) example: Sample:325, Value:0
I (75864) example: Sample:326, Value:0
I (75864) example: Sample:327, Value:0
I (75864) example: Sample:328, Value:0
I (75864) example: Sample:329, Value:0
I (75864) example: Sample:330, Value:0
I (75864) example: Sample:331, Value:0
I (75864) example: Sample:332, Value:0
I (75864) example: Sample:333, Value:0
I (75864) example: Sample:334, Value:0
I (75864) example: Sample:335, Value:0
I (75864) example: Sample:336, Value:0
I (75864) example: Sample:337, Value:0
I (75864) example: Sample:338, Value:0
I (75864) example: Sample:339, Value:0
I (75864) example: Sample:340, Value:0
I (75864) example: Sample:341, Value:0
I (75864) example: Sample:342, Value:0
I (75864) example: Sample:343, Value:0
I (75864) example: Sample:344, Value:0
I (75864) example: Sample:345, Value:0
I (75864) example: Sample:346, Value:0
I (75864) example: Sample:347, Value:0
I (75864) example: Sample:348, Value:0
I (75864) example: Sample:349, Value:0
I (75864) example: Sample:350, Value:0
I (75864) example: Sample:351, Value:0
I (75864) example: Sample:352, Value:0
I (75864) example: Sample:353, Value:0
I (77894) example: Sample:1, Value:0
I (77894) example: Sample:2, Value:0
I (77894) example: Sample:3, Value:0
I (77894) example: Sample:4, Value:0
I (77894) example: Sample:5, Value:0
I (77894) example: Sample:6, Value:0
I (77894) example: Sample:7, Value:0
I (77894) example: Sample:8, Value:0
I (77894) example: Sample:9, Value:0
I (77894) example: Sample:10, Value:0
I (77894) example: Sample:11, Value:0
I (77894) example: Sample:12, Value:0
I (77894) example: Sample:13, Value:0
I (77894) example: Sample:14, Value:0
I (77894) example: Sample:15, Value:0
I (77894) example: Sample:16, Value:0
I (77894) example: Sample:17, Value:0
I (77894) example: Sample:18, Value:0
I (77894) example: Sample:19, Value:0
I (77894) example: Sample:20, Value:0
I (77894) example: Sample:21, Value:0
I (77894) example: Sample:22, Value:0
I (77894) example: Sample:23, Value:0
I (77894) example: Sample:24, Value:0
I (77894) example: Sample:25, Value:0
I (77894) example: Sample:26, Value:0
I (77894) example: Sample:27, Value:0
I (77894) example: Sample:28, Value:0
I (77894) example: Sample:29, Value:0
I (77894) example: Sample:30, Value:0
I (77894) example: Sample:31, Value:0
I (77894) example: Sample:32, Value:0
I (77894) example: Sample:33, Value:0
I (77894) example: Sample:34, Value:0
I (77894) example: Sample:35, Value:0
I (77894) example: Sample:36, Value:0
I (77894) example: Sample:37, Value:0
I (77894) example: Sample:38, Value:0
I (77894) example: Sample:39, Value:0
I (77894) example: Sample:40, Value:0
I (77894) example: Sample:41, Value:0
I (77894) example: Sample:42, Value:0
I (77894) example: Sample:43, Value:0
I (77894) example: Sample:44, Value:0
I (77894) example: Sample:45, Value:0
I (77894) example: Sample:46, Value:0
I (77894) example: Sample:47, Value:0
I (77894) example: Sample:48, Value:0
I (77894) example: Sample:49, Value:0
I (77894) example: Sample:50, Value:0
I (77894) example: Sample:51, Value:0
I (77894) example: Sample:52, Value:0
I (77894) example: Sample:53, Value:0
I (77894) example: Sample:54, Value:0
I (77894) example: Sample:55, Value:0
I (77894) example: Sample:56, Value:0
I (77894) example: Sample:57, Value:0
I (77894) example: Sample:58, Value:0
I (77894) example: Sample:59, Value:0
I (77894) example: Sample:60, Value:0
I (77894) example: Sample:61, Value:0
I (77894) example: Sample:62, Value:0
I (77894) example: Sample:63, Value:0
I (77894) example: Sample:64, Value:0
I (77894) example: Sample:65, Value:0
I (77894) example: Sample:66, Value:0
I (77894) example: Sample:67, Value:0
I (77894) example: Sample:68, Value:0
I (77894) example: Sample:69, Value:0
I (77894) example: Sample:70, Value:0
I (77894) example: Sample:71, Value:0
I (77894) example: Sample:72, Value:0
I (77894) example: Sample:73, Value:0
I (77894) example: Sample:74, Value:0
I (77894) example: Sample:75, Value:0
====================================================================
Log records count: 428

Binary file not shown.

View file

@ -0,0 +1,8 @@
#! /bin/bash
{ coverage debug sys \
&& coverage erase &> output \
&& coverage run -a $IDF_PATH/tools/esp_app_trace/logtrace_proc.py adc_log.trc test.elf &>> output \
&& diff output expected_output \
&& coverage report \
; } || { echo 'The test for logtrace_proc has failed. Please examine the artifacts.' ; exit 1; }

View file

@ -0,0 +1,88 @@
/* Blink Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_heap_trace.h"
/* Can run 'make menuconfig' to choose the GPIO to blink,
or you can edit the following line and set a number here.
*/
#define BLINK_GPIO CONFIG_BLINK_GPIO
void blink_task2(void *pvParameter)
{
TaskHandle_t task = (TaskHandle_t)pvParameter;
while(1) {
if (xTaskNotifyWait(0, 0, NULL, portMAX_DELAY) != pdPASS) {
printf("Failed to wait for main task!\n");
return;
}
void *a = malloc(65);
printf("Alloced 65 bytes @ %p\n", a);
void *b = malloc(97);
printf("Alloced 97 bytes @ %p\n", b);
free(a);
printf("Freed @ %p\n", a);
b = malloc(11);
printf("Alloced 11 bytes @ %p\n", b);
b = malloc(24);
printf("Alloced 24 bytes @ %p\n", b);
free(b);
printf("Freed @ %p\n", b);
if (xTaskNotify(task, 0, eNoAction) != pdPASS) {
printf("Failed to notify main task!\n");
return;
}
}
}
void blink_task(void *pvParameter)
{
TaskHandle_t task = 0;
if(heap_trace_init_tohost() != ESP_OK) {
printf("Failed to init heap trace!\n");
return;
}
xTaskCreatePinnedToCore(&blink_task2, "blink_task2", 2048, xTaskGetCurrentTaskHandle(), 5, &task, 1);
while(1) {
heap_trace_start(HEAP_TRACE_ALL);
if (xTaskNotify(task, 0, eNoAction) != pdPASS) {
printf("Failed to notify slave task!\n");
return;
}
void *a = malloc(64);
printf("Alloced 64 bytes @ %p\n", a);
void *b = malloc(96);
printf("Alloced 96 bytes @ %p\n", b);
free(a);
printf("Freed @ %p\n", a);
b = malloc(10);
printf("Alloced 10 bytes @ %p\n", b);
b = malloc(23);
printf("Alloced 23 bytes @ %p\n", b);
free(b);
printf("Freed @ %p\n", b);
if (xTaskNotifyWait(0, 0, NULL, portMAX_DELAY) != pdPASS) {
printf("Failed to wait for slave task!\n");
return;
}
heap_trace_stop();
}
}
void app_main()
{
xTaskCreatePinnedToCore(&blink_task, "blink_task", 2048, NULL, 5, NULL, 0);
}

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,450 @@
Parse trace from 'cpu0.svdat'...
Stop parsing trace. (Timeout 0.000000 sec while reading 1 bytes!)
Parse trace from 'cpu1.svdat'...
Stop parsing trace. (Timeout 0.000000 sec while reading 1 bytes!)
Process events from '['cpu0.svdat', 'cpu1.svdat']'...
EVENT[0]: 0.000000000 - core[0].svTraceStart(10), plen 0: []
EVENT[1]: 0.000000000 - core[1].svTraceStart(10), plen 0: []
EVENT[2]: 0.000010950 - core[0].svInit(24), plen 14: [sys_freq: 40000000, cpu_freq: 160000000, ram_base: 1061158912, id_shift: 0]
EVENT[3]: 0.000010950 - core[1].svInit(24), plen 14: [sys_freq: 40000000, cpu_freq: 160000000, ram_base: 1061158912, id_shift: 0]
EVENT[4]: 0.000024800 - core[0].svSysDesc(14), plen 0: [desc: N=FreeRTOS Application,D=ESP32,C=Xtensa,O=FreeRTOS]
EVENT[5]: 0.000024800 - core[1].svSysDesc(14), plen 0: [desc: N=FreeRTOS Application,D=ESP32,C=Xtensa,O=FreeRTOS]
EVENT[6]: 0.000051650 - core[0].svSysDesc(14), plen 0: [desc: I#5=SysTick]
EVENT[7]: 0.000051650 - core[1].svSysDesc(14), plen 0: [desc: I#5=SysTick]
EVENT[8]: 0.000104150 - core[0].svSysDesc(14), plen 0: [desc: I#6=WIFI_MAC]
EVENT[9]: 0.000104150 - core[1].svSysDesc(14), plen 0: [desc: I#6=WIFI_MAC]
EVENT[10]: 0.000121100 - core[0].svSysDesc(14), plen 0: [desc: I#7=WIFI_NMI]
EVENT[11]: 0.000121100 - core[1].svSysDesc(14), plen 0: [desc: I#7=WIFI_NMI]
EVENT[12]: 0.000138125 - core[0].svSysDesc(14), plen 0: [desc: I#8=WIFI_BB]
EVENT[13]: 0.000138125 - core[1].svSysDesc(14), plen 0: [desc: I#8=WIFI_BB]
EVENT[14]: 0.000154825 - core[0].svSysDesc(14), plen 0: [desc: I#9=BT_MAC]
EVENT[15]: 0.000154825 - core[1].svSysDesc(14), plen 0: [desc: I#9=BT_MAC]
EVENT[16]: 0.000193350 - core[0].svSysDesc(14), plen 0: [desc: I#10=BT_BB]
EVENT[17]: 0.000193350 - core[1].svSysDesc(14), plen 0: [desc: I#10=BT_BB]
EVENT[18]: 0.000212875 - core[0].svSysDesc(14), plen 0: [desc: I#11=BT_BB_NMI]
EVENT[19]: 0.000212875 - core[1].svSysDesc(14), plen 0: [desc: I#11=BT_BB_NMI]
EVENT[20]: 0.000231625 - core[0].svSysDesc(14), plen 0: [desc: I#12=RWBT]
EVENT[21]: 0.000231625 - core[1].svSysDesc(14), plen 0: [desc: I#12=RWBT]
EVENT[22]: 0.000250250 - core[0].svSysDesc(14), plen 0: [desc: I#13=RWBLE]
EVENT[23]: 0.000250250 - core[1].svSysDesc(14), plen 0: [desc: I#13=RWBLE]
EVENT[24]: 0.000269450 - core[0].svSysDesc(14), plen 0: [desc: I#14=RWBT_NMI]
EVENT[25]: 0.000269450 - core[1].svSysDesc(14), plen 0: [desc: I#14=RWBT_NMI]
EVENT[26]: 0.000288925 - core[0].svSysDesc(14), plen 0: [desc: I#15=RWBLE_NMI]
EVENT[27]: 0.000288925 - core[1].svSysDesc(14), plen 0: [desc: I#15=RWBLE_NMI]
EVENT[28]: 0.000310575 - core[0].svSysDesc(14), plen 0: [desc: I#16=SLC0]
EVENT[29]: 0.000310575 - core[1].svSysDesc(14), plen 0: [desc: I#16=SLC0]
EVENT[30]: 0.000329150 - core[0].svSysDesc(14), plen 0: [desc: I#17=SLC1]
EVENT[31]: 0.000329150 - core[1].svSysDesc(14), plen 0: [desc: I#17=SLC1]
EVENT[32]: 0.000347675 - core[0].svSysDesc(14), plen 0: [desc: I#18=UHCI0]
EVENT[33]: 0.000347675 - core[1].svSysDesc(14), plen 0: [desc: I#18=UHCI0]
EVENT[34]: 0.000366225 - core[0].svSysDesc(14), plen 0: [desc: I#19=UHCI1]
EVENT[35]: 0.000366225 - core[1].svSysDesc(14), plen 0: [desc: I#19=UHCI1]
EVENT[36]: 0.000386350 - core[0].svSysDesc(14), plen 0: [desc: I#20=TG0_T0_LEVEL]
EVENT[37]: 0.000386350 - core[1].svSysDesc(14), plen 0: [desc: I#20=TG0_T0_LEVEL]
EVENT[38]: 0.000406575 - core[0].svSysDesc(14), plen 0: [desc: I#21=TG0_T1_LEVEL]
EVENT[39]: 0.000406575 - core[1].svSysDesc(14), plen 0: [desc: I#21=TG0_T1_LEVEL]
EVENT[40]: 0.000427300 - core[0].svSysDesc(14), plen 0: [desc: I#22=TG0_WDT_LEVEL]
EVENT[41]: 0.000427300 - core[1].svSysDesc(14), plen 0: [desc: I#22=TG0_WDT_LEVEL]
EVENT[42]: 0.000448000 - core[0].svSysDesc(14), plen 0: [desc: I#23=TG0_LACT_LEVEL]
EVENT[43]: 0.000448000 - core[1].svSysDesc(14), plen 0: [desc: I#23=TG0_LACT_LEVEL]
EVENT[44]: 0.000468250 - core[0].svSysDesc(14), plen 0: [desc: I#24=TG1_T0_LEVEL]
EVENT[45]: 0.000468250 - core[1].svSysDesc(14), plen 0: [desc: I#24=TG1_T0_LEVEL]
EVENT[46]: 0.000488500 - core[0].svSysDesc(14), plen 0: [desc: I#25=TG1_T1_LEVEL]
EVENT[47]: 0.000488500 - core[1].svSysDesc(14), plen 0: [desc: I#25=TG1_T1_LEVEL]
EVENT[48]: 0.000508975 - core[0].svSysDesc(14), plen 0: [desc: I#26=TG1_WDT_LEVEL]
EVENT[49]: 0.000508975 - core[1].svSysDesc(14), plen 0: [desc: I#26=TG1_WDT_LEVEL]
EVENT[50]: 0.000529850 - core[0].svSysDesc(14), plen 0: [desc: I#27=TG1_LACT_LEVEL]
EVENT[51]: 0.000529850 - core[1].svSysDesc(14), plen 0: [desc: I#27=TG1_LACT_LEVEL]
EVENT[52]: 0.000548375 - core[0].svSysDesc(14), plen 0: [desc: I#28=GPIO]
EVENT[53]: 0.000548375 - core[1].svSysDesc(14), plen 0: [desc: I#28=GPIO]
EVENT[54]: 0.000570825 - core[0].svSysDesc(14), plen 0: [desc: I#29=GPIO_NMI]
EVENT[55]: 0.000570825 - core[1].svSysDesc(14), plen 0: [desc: I#29=GPIO_NMI]
EVENT[56]: 0.000590425 - core[0].svSysDesc(14), plen 0: [desc: I#30=FROM_CPU0]
EVENT[57]: 0.000590425 - core[1].svSysDesc(14), plen 0: [desc: I#30=FROM_CPU0]
EVENT[58]: 0.000610000 - core[0].svSysDesc(14), plen 0: [desc: I#31=FROM_CPU1]
EVENT[59]: 0.000610000 - core[1].svSysDesc(14), plen 0: [desc: I#31=FROM_CPU1]
EVENT[60]: 0.000629625 - core[0].svSysDesc(14), plen 0: [desc: I#32=FROM_CPU2]
EVENT[61]: 0.000629625 - core[1].svSysDesc(14), plen 0: [desc: I#32=FROM_CPU2]
EVENT[62]: 0.000649425 - core[0].svSysDesc(14), plen 0: [desc: I#33=FROM_CPU3]
EVENT[63]: 0.000649425 - core[1].svSysDesc(14), plen 0: [desc: I#33=FROM_CPU3]
EVENT[64]: 0.000667975 - core[0].svSysDesc(14), plen 0: [desc: I#34=SPI0]
EVENT[65]: 0.000667975 - core[1].svSysDesc(14), plen 0: [desc: I#34=SPI0]
EVENT[66]: 0.000686500 - core[0].svSysDesc(14), plen 0: [desc: I#35=SPI1]
EVENT[67]: 0.000686500 - core[1].svSysDesc(14), plen 0: [desc: I#35=SPI1]
EVENT[68]: 0.000704825 - core[0].svSysDesc(14), plen 0: [desc: I#36=SPI2]
EVENT[69]: 0.000704825 - core[1].svSysDesc(14), plen 0: [desc: I#36=SPI2]
EVENT[70]: 0.000723100 - core[0].svSysDesc(14), plen 0: [desc: I#37=SPI3]
EVENT[71]: 0.000723100 - core[1].svSysDesc(14), plen 0: [desc: I#37=SPI3]
EVENT[72]: 0.000741550 - core[0].svSysDesc(14), plen 0: [desc: I#38=I2S0]
EVENT[73]: 0.000741550 - core[1].svSysDesc(14), plen 0: [desc: I#38=I2S0]
EVENT[74]: 0.000760000 - core[0].svSysDesc(14), plen 0: [desc: I#39=I2S1]
EVENT[75]: 0.000760000 - core[1].svSysDesc(14), plen 0: [desc: I#39=I2S1]
EVENT[76]: 0.000778475 - core[0].svSysDesc(14), plen 0: [desc: I#40=UART0]
EVENT[77]: 0.000778475 - core[1].svSysDesc(14), plen 0: [desc: I#40=UART0]
EVENT[78]: 0.000797050 - core[0].svSysDesc(14), plen 0: [desc: I#41=UART1]
EVENT[79]: 0.000797050 - core[1].svSysDesc(14), plen 0: [desc: I#41=UART1]
EVENT[80]: 0.000815625 - core[0].svSysDesc(14), plen 0: [desc: I#42=UART2]
EVENT[81]: 0.000815625 - core[1].svSysDesc(14), plen 0: [desc: I#42=UART2]
EVENT[82]: 0.000835000 - core[0].svSysDesc(14), plen 0: [desc: I#43=SDIO_HOST]
EVENT[83]: 0.000835000 - core[1].svSysDesc(14), plen 0: [desc: I#43=SDIO_HOST]
EVENT[84]: 0.000854075 - core[0].svSysDesc(14), plen 0: [desc: I#44=ETH_MAC]
EVENT[85]: 0.000854075 - core[1].svSysDesc(14), plen 0: [desc: I#44=ETH_MAC]
EVENT[86]: 0.000875600 - core[0].svSysDesc(14), plen 0: [desc: I#45=PWM0]
EVENT[87]: 0.000875600 - core[1].svSysDesc(14), plen 0: [desc: I#45=PWM0]
EVENT[88]: 0.000893850 - core[0].svSysDesc(14), plen 0: [desc: I#46=PWM1]
EVENT[89]: 0.000893850 - core[1].svSysDesc(14), plen 0: [desc: I#46=PWM1]
EVENT[90]: 0.000912375 - core[0].svSysDesc(14), plen 0: [desc: I#47=PWM2]
EVENT[91]: 0.000912375 - core[1].svSysDesc(14), plen 0: [desc: I#47=PWM2]
EVENT[92]: 0.000930950 - core[0].svSysDesc(14), plen 0: [desc: I#48=PWM3]
EVENT[93]: 0.000930950 - core[1].svSysDesc(14), plen 0: [desc: I#48=PWM3]
EVENT[94]: 0.000949375 - core[0].svSysDesc(14), plen 0: [desc: I#49=LEDC]
EVENT[95]: 0.000949375 - core[1].svSysDesc(14), plen 0: [desc: I#49=LEDC]
EVENT[96]: 0.000968075 - core[0].svSysDesc(14), plen 0: [desc: I#50=EFUSE]
EVENT[97]: 0.000968075 - core[1].svSysDesc(14), plen 0: [desc: I#50=EFUSE]
EVENT[98]: 0.000986275 - core[0].svSysDesc(14), plen 0: [desc: I#51=CAN]
EVENT[99]: 0.000986275 - core[1].svSysDesc(14), plen 0: [desc: I#51=CAN]
EVENT[100]: 0.001005625 - core[0].svSysDesc(14), plen 0: [desc: I#52=RTC_CORE]
EVENT[101]: 0.001005625 - core[1].svSysDesc(14), plen 0: [desc: I#52=RTC_CORE]
EVENT[102]: 0.001023700 - core[0].svSysDesc(14), plen 0: [desc: I#53=RMT]
EVENT[103]: 0.001023700 - core[1].svSysDesc(14), plen 0: [desc: I#53=RMT]
EVENT[104]: 0.001042050 - core[0].svSysDesc(14), plen 0: [desc: I#54=PCNT]
EVENT[105]: 0.001042050 - core[1].svSysDesc(14), plen 0: [desc: I#54=PCNT]
EVENT[106]: 0.001061500 - core[0].svSysDesc(14), plen 0: [desc: I#55=I2C_EXT0]
EVENT[107]: 0.001061500 - core[1].svSysDesc(14), plen 0: [desc: I#55=I2C_EXT0]
EVENT[108]: 0.001081100 - core[0].svSysDesc(14), plen 0: [desc: I#56=I2C_EXT1]
EVENT[109]: 0.001081100 - core[1].svSysDesc(14), plen 0: [desc: I#56=I2C_EXT1]
EVENT[110]: 0.001099425 - core[0].svSysDesc(14), plen 0: [desc: I#57=RSA]
EVENT[111]: 0.001099425 - core[1].svSysDesc(14), plen 0: [desc: I#57=RSA]
EVENT[112]: 0.001118625 - core[0].svSysDesc(14), plen 0: [desc: I#58=SPI1_DMA]
EVENT[113]: 0.001118625 - core[1].svSysDesc(14), plen 0: [desc: I#58=SPI1_DMA]
EVENT[114]: 0.001137775 - core[0].svSysDesc(14), plen 0: [desc: I#59=SPI2_DMA]
EVENT[115]: 0.001137775 - core[1].svSysDesc(14), plen 0: [desc: I#59=SPI2_DMA]
EVENT[116]: 0.001156950 - core[0].svSysDesc(14), plen 0: [desc: I#60=SPI3_DMA]
EVENT[117]: 0.001156950 - core[1].svSysDesc(14), plen 0: [desc: I#60=SPI3_DMA]
EVENT[118]: 0.001175175 - core[0].svSysDesc(14), plen 0: [desc: I#61=WDT]
EVENT[119]: 0.001175175 - core[1].svSysDesc(14), plen 0: [desc: I#61=WDT]
EVENT[120]: 0.001197300 - core[0].svSysDesc(14), plen 0: [desc: I#62=TIMER1]
EVENT[121]: 0.001197300 - core[1].svSysDesc(14), plen 0: [desc: I#62=TIMER1]
EVENT[122]: 0.001216250 - core[0].svSysDesc(14), plen 0: [desc: I#63=TIMER2]
EVENT[123]: 0.001216250 - core[1].svSysDesc(14), plen 0: [desc: I#63=TIMER2]
EVENT[124]: 0.001236175 - core[0].svSysDesc(14), plen 0: [desc: I#64=TG0_T0_EDGE]
EVENT[125]: 0.001236175 - core[1].svSysDesc(14), plen 0: [desc: I#64=TG0_T0_EDGE]
EVENT[126]: 0.001256275 - core[0].svSysDesc(14), plen 0: [desc: I#65=TG0_T1_EDGE]
EVENT[127]: 0.001256275 - core[1].svSysDesc(14), plen 0: [desc: I#65=TG0_T1_EDGE]
EVENT[128]: 0.001276675 - core[0].svSysDesc(14), plen 0: [desc: I#66=TG0_WDT_EDGE]
EVENT[129]: 0.001276675 - core[1].svSysDesc(14), plen 0: [desc: I#66=TG0_WDT_EDGE]
EVENT[130]: 0.001297375 - core[0].svSysDesc(14), plen 0: [desc: I#67=TG0_LACT_EDGE]
EVENT[131]: 0.001297375 - core[1].svSysDesc(14), plen 0: [desc: I#67=TG0_LACT_EDGE]
EVENT[132]: 0.001317425 - core[0].svSysDesc(14), plen 0: [desc: I#68=TG1_T0_EDGE]
EVENT[133]: 0.001317425 - core[1].svSysDesc(14), plen 0: [desc: I#68=TG1_T0_EDGE]
EVENT[134]: 0.001337650 - core[0].svSysDesc(14), plen 0: [desc: I#69=TG1_T1_EDGE]
EVENT[135]: 0.001337650 - core[1].svSysDesc(14), plen 0: [desc: I#69=TG1_T1_EDGE]
EVENT[136]: 0.001357950 - core[0].svSysDesc(14), plen 0: [desc: I#70=TG1_WDT_EDGE]
EVENT[137]: 0.001357950 - core[1].svSysDesc(14), plen 0: [desc: I#70=TG1_WDT_EDGE]
EVENT[138]: 0.001378625 - core[0].svSysDesc(14), plen 0: [desc: I#71=TG1_LACT_EDGE]
EVENT[139]: 0.001378625 - core[1].svSysDesc(14), plen 0: [desc: I#71=TG1_LACT_EDGE]
EVENT[140]: 0.001397500 - core[0].svSysDesc(14), plen 0: [desc: I#72=MMU_IA]
EVENT[141]: 0.001397500 - core[1].svSysDesc(14), plen 0: [desc: I#72=MMU_IA]
EVENT[142]: 0.001416425 - core[0].svSysDesc(14), plen 0: [desc: I#73=MPU_IA]
EVENT[143]: 0.001416425 - core[1].svSysDesc(14), plen 0: [desc: I#73=MPU_IA]
EVENT[144]: 0.001435550 - core[0].svSysDesc(14), plen 0: [desc: I#74=CACHE_IA]
EVENT[145]: 0.001435550 - core[1].svSysDesc(14), plen 0: [desc: I#74=CACHE_IA]
EVENT[146]: 0.001441950 - core[0].svSysTimeUs(13), plen 0: [time: 10000]
EVENT[147]: 0.001441950 - core[1].svSysTimeUs(13), plen 0: [time: 10000]
EVENT[148]: 0.001647400 - core[0].svTaskInfo(9), plen 0: [tid: 12253880, prio: 22, name: esp_timer]
EVENT[149]: 0.001647400 - core[1].svTaskInfo(9), plen 0: [tid: 12253880, prio: 22, name: esp_timer]
EVENT[150]: 0.001652000 - core[0].svStackInfo(21), plen 0: [tid: 12253880, base: 1073408692, sz: 3436, unused: 0]
EVENT[151]: 0.001652000 - core[1].svStackInfo(21), plen 0: [tid: 12253880, base: 1073408692, sz: 3436, unused: 0]
EVENT[152]: 0.001738550 - core[0].svTaskInfo(9), plen 0: [tid: 12254636, prio: 24, name: ipc0]
EVENT[153]: 0.001738550 - core[1].svTaskInfo(9), plen 0: [tid: 12254636, prio: 24, name: ipc0]
EVENT[154]: 0.001742750 - core[0].svStackInfo(21), plen 0: [tid: 12254636, base: 1073430180, sz: 1388, unused: 0]
EVENT[155]: 0.001742750 - core[1].svStackInfo(21), plen 0: [tid: 12254636, base: 1073430180, sz: 1388, unused: 0]
EVENT[156]: 0.001828975 - core[0].svTaskInfo(9), plen 0: [tid: 12275372, prio: 24, name: ipc1]
EVENT[157]: 0.001828975 - core[1].svTaskInfo(9), plen 0: [tid: 12275372, prio: 24, name: ipc1]
EVENT[158]: 0.001833225 - core[0].svStackInfo(21), plen 0: [tid: 12275372, base: 1073432232, sz: 1384, unused: 0]
EVENT[159]: 0.001833225 - core[1].svStackInfo(21), plen 0: [tid: 12275372, base: 1073432232, sz: 1384, unused: 0]
EVENT[160]: 0.001871225 - core[0].svTaskInfo(9), plen 0: [tid: 12291908, prio: 5, name: blink_task]
EVENT[161]: 0.001871225 - core[1].svTaskInfo(9), plen 0: [tid: 12291908, prio: 5, name: blink_task]
EVENT[162]: 0.001875650 - core[0].svStackInfo(21), plen 0: [tid: 12291908, base: 1073448452, sz: 524, unused: 0]
EVENT[163]: 0.001875650 - core[1].svStackInfo(21), plen 0: [tid: 12291908, base: 1073448452, sz: 524, unused: 0]
EVENT[164]: 0.002070800 - core[0].svTaskInfo(9), plen 0: [tid: 12282660, prio: 1, name: main]
EVENT[165]: 0.002070800 - core[1].svTaskInfo(9), plen 0: [tid: 12282660, prio: 1, name: main]
EVENT[166]: 0.002075200 - core[0].svStackInfo(21), plen 0: [tid: 12282660, base: 1073437472, sz: 3296, unused: 0]
EVENT[167]: 0.002075200 - core[1].svStackInfo(21), plen 0: [tid: 12282660, base: 1073437472, sz: 3296, unused: 0]
EVENT[168]: 0.002153375 - core[0].svTaskInfo(9), plen 0: [tid: 12284560, prio: 0, name: IDLE0]
EVENT[169]: 0.002153375 - core[1].svTaskInfo(9), plen 0: [tid: 12284560, prio: 0, name: IDLE0]
EVENT[170]: 0.002157850 - core[0].svStackInfo(21), plen 0: [tid: 12284560, base: 1073441932, sz: 1236, unused: 0]
EVENT[171]: 0.002157850 - core[1].svStackInfo(21), plen 0: [tid: 12284560, base: 1073441932, sz: 1236, unused: 0]
EVENT[172]: 0.002228950 - core[0].svTaskInfo(9), plen 0: [tid: 12286460, prio: 0, name: IDLE1]
EVENT[173]: 0.002228950 - core[1].svTaskInfo(9), plen 0: [tid: 12286460, prio: 0, name: IDLE1]
EVENT[174]: 0.002233250 - core[0].svStackInfo(21), plen 0: [tid: 12286460, base: 1073443832, sz: 1112, unused: 0]
EVENT[175]: 0.002233250 - core[1].svStackInfo(21), plen 0: [tid: 12286460, base: 1073443832, sz: 1112, unused: 0]
EVENT[176]: 0.002319675 - core[0].svTaskInfo(9), plen 0: [tid: 12289116, prio: 1, name: Tmr Svc]
EVENT[177]: 0.002319675 - core[1].svTaskInfo(9), plen 0: [tid: 12289116, prio: 1, name: Tmr Svc]
EVENT[178]: 0.002324100 - core[0].svStackInfo(21), plen 0: [tid: 12289116, base: 1073445976, sz: 1384, unused: 0]
EVENT[179]: 0.002324100 - core[1].svStackInfo(21), plen 0: [tid: 12289116, base: 1073445976, sz: 1384, unused: 0]
EVENT[180]: 0.002431200 - core[0].svTaskInfo(9), plen 0: [tid: 12294320, prio: 5, name: blink_task2]
EVENT[181]: 0.002431200 - core[1].svTaskInfo(9), plen 0: [tid: 12294320, prio: 5, name: blink_task2]
EVENT[182]: 0.002438750 - core[0].svStackInfo(21), plen 0: [tid: 12294320, base: 1073451180, sz: 1748, unused: 0]
EVENT[183]: 0.002438750 - core[1].svStackInfo(21), plen 0: [tid: 12294320, base: 1073451180, sz: 1748, unused: 0]
EVENT[184]: 0.002446150 - core[0].svNumModules(27), plen 1: [mod_cnt: 0]
EVENT[185]: 0.002446150 - core[1].svNumModules(27), plen 1: [mod_cnt: 0]
EVENT[186]: 0.002484225 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[187]: 0.002496125 - core[0].svTaskStopReady(7), plen 0: [tid: 12291908, cause: 4]
EVENT[188]: 0.002508025 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[189]: 0.002516350 - core[0].svIsrEnter(2), plen 0: [irq_num: 30]
EVENT[190]: 0.002524325 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[191]: 0.002532350 - core[0].svExitIsrToScheduler(18), plen 0: []
EVENT[192]: 0.002541200 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[193]: 0.002548475 - core[0].svTaskStartExec(4), plen 0: [tid: 12282660]
EVENT[194]: 0.002556375 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[195]: 0.002564450 - core[0].vTaskDelete(33), plen 4: [xTaskToDelete: 12282660]
EVENT[196]: 0.002577700 - core[1].svIdle(17), plen 0: []
EVENT[197]: 0.002585225 - core[0].svIsrEnter(2), plen 0: [irq_num: 30]
EVENT[198]: 0.002592950 - core[0].svExitIsrToScheduler(18), plen 0: []
EVENT[199]: 0.002605950 - core[0].svIdle(17), plen 0: []
EVENT[200]: 0.008819550 - core[0].svIsrEnter(2), plen 0: [irq_num: 5]
EVENT[201]: 0.008828075 - core[0].svTaskStartReady(6), plen 0: [tid: 12291908]
EVENT[202]: 0.008828075 - core[1].svTaskStartReady(6), plen 0: [tid: 12291908]
EVENT[203]: 0.008837475 - core[0].svExitIsrToScheduler(18), plen 0: []
EVENT[204]: 0.008850450 - core[0].svTaskStartExec(4), plen 0: [tid: 12291908]
EVENT[205]: 0.008872650 - core[0].svModuleDesc(22), plen 0: [mod_id: 0, evt_off: 512, desc: ESP32 SystemView Heap Tracing Module]
EVENT[206]: 0.008872650 - core[1].svModuleDesc(22), plen 0: [mod_id: 0, evt_off: 512, desc: ESP32 SystemView Heap Tracing Module]
EVENT[207]: 0.008886175 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[208]: 0.008886175 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[209]: 0.008897425 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[210]: 0.008906150 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[211]: 0.008919900 - core[0].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450504, size: 64, callers: [1074601571, 1074296884]]
[0.008919900] HEAP: Allocated 64 bytes @ 0x3ffb8e08 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:65
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[212]: 0.008928250 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[213]: 0.008957950 - core[0].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450572, size: 80, callers: [1074298654, 1074299267]]
[0.008957950] HEAP: Allocated 80 bytes @ 0x3ffb8e4c from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
EVENT[214]: 0.008967250 - core[0].xQueueGenericCreate(47), plen 3: [uxQueueLength: 1, uxItemSize: 0, ucQueueType: 4]
EVENT[215]: 0.008977300 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[216]: 0.008984625 - core[1].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450656, size: 65, callers: [1074601382, 1074296884]]
[0.008984625] HEAP: Allocated 65 bytes @ 0x3ffb8ea0 from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:30
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[217]: 0.008995725 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[218]: 0.009010075 - core[1].svIsrEnter(2), plen 0: [irq_num: 5]
EVENT[219]: 0.009018025 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[220]: 0.009031900 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[221]: 0.009089600 - core[0].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073434644, size: 80, callers: [1074298654, 1074299267]]
[0.009089600] HEAP: Allocated 80 bytes @ 0x3ffb5014 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
EVENT[222]: 0.009098175 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[223]: 0.009106300 - core[0].xQueueGenericCreate(47), plen 3: [uxQueueLength: 1, uxItemSize: 0, ucQueueType: 4]
EVENT[224]: 0.009113825 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[225]: 0.009121600 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[226]: 0.009129000 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[227]: 0.009137900 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[228]: 0.009145425 - core[1].svIdle(17), plen 0: []
EVENT[229]: 0.009169600 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[230]: 0.009185225 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[231]: 0.009195125 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[232]: 0.009195125 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[233]: 0.009207000 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[234]: 0.009215575 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[235]: 0.009223275 - core[0].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073434728, size: 96, callers: [1074601587, 1074296884]]
[0.009223275] HEAP: Allocated 96 bytes @ 0x3ffb5068 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:68
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[236]: 0.009231050 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[237]: 0.009241875 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[238]: 0.009257225 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[239]: 0.009269200 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[240]: 0.009278275 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[241]: 0.009286275 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[242]: 0.009303450 - core[1].svIdle(17), plen 0: []
EVENT[243]: 0.009310950 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[244]: 0.009329625 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[245]: 0.009339525 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[246]: 0.009339525 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[247]: 0.009351425 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[248]: 0.009359450 - core[0].esp_sysview_heap_trace_free(513), plen 15: [addr: 1073450504, callers: [1074601600, 1074296884]]
[0.009359450] HEAP: Freed bytes @ 0x3ffb8e08 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:70
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[249]: 0.009367800 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[250]: 0.009378950 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[251]: 0.009387450 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[252]: 0.009402575 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[253]: 0.009414900 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[254]: 0.009423125 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[255]: 0.009430250 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[256]: 0.009445425 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[257]: 0.009453075 - core[1].svIdle(17), plen 0: []
EVENT[258]: 0.009469225 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[259]: 0.009479025 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[260]: 0.009479025 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[261]: 0.009490950 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[262]: 0.009499475 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[263]: 0.009507600 - core[0].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450504, size: 10, callers: [1074601615, 1074296884]]
[0.009507600] HEAP: Allocated 10 bytes @ 0x3ffb8e08 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:72
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[264]: 0.009515300 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[265]: 0.009526100 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[266]: 0.009541550 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[267]: 0.009553850 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[268]: 0.009561100 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[269]: 0.009568400 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[270]: 0.009585075 - core[1].svIdle(17), plen 0: []
EVENT[271]: 0.009593375 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[272]: 0.009609150 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[273]: 0.009621875 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[274]: 0.009621875 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[275]: 0.009633775 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[276]: 0.009642300 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[277]: 0.009649475 - core[0].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450520, size: 23, callers: [1074601628, 1074296884]]
[0.009649475] HEAP: Allocated 23 bytes @ 0x3ffb8e18 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:73
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[278]: 0.009657875 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[279]: 0.009666025 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[280]: 0.009681500 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[281]: 0.009693375 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[282]: 0.009702800 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[283]: 0.009710550 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[284]: 0.009726725 - core[1].svIdle(17), plen 0: []
EVENT[285]: 0.010504825 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[286]: 0.010520650 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[287]: 0.010530550 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[288]: 0.010530550 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[289]: 0.010542400 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[290]: 0.010550025 - core[0].esp_sysview_heap_trace_free(513), plen 15: [addr: 1073450520, callers: [1074601643, 1074296884]]
[0.010550025] HEAP: Freed bytes @ 0x3ffb8e18 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:76
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[291]: 0.010557450 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[292]: 0.010569700 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[293]: 0.010577700 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[294]: 0.010592825 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[295]: 0.010605950 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[296]: 0.010613575 - core[0].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[297]: 0.010620900 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[298]: 0.010637050 - core[1].svIdle(17), plen 0: []
EVENT[299]: 0.012240950 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[300]: 0.012256775 - core[0].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[301]: 0.012266650 - core[0].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[302]: 0.012266650 - core[1].svTaskStartReady(6), plen 0: [tid: 12294320]
EVENT[303]: 0.012281350 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[304]: 0.012289475 - core[0].svTaskStopReady(7), plen 0: [tid: 12291908, cause: 27]
EVENT[305]: 0.012297450 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[306]: 0.012306350 - core[0].svIsrEnter(2), plen 0: [irq_num: 30]
EVENT[307]: 0.012312875 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[308]: 0.012320700 - core[0].svExitIsrToScheduler(18), plen 0: []
EVENT[309]: 0.012328950 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[310]: 0.012338100 - core[0].svIdle(17), plen 0: []
EVENT[311]: 0.012640475 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[312]: 0.014931850 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[313]: 0.014963325 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[314]: 0.014984150 - core[1].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073434828, size: 97, callers: [1074601399, 1074296884]]
[0.014984150] HEAP: Allocated 97 bytes @ 0x3ffb50cc from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:33
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[315]: 0.014997400 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[316]: 0.015031050 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[317]: 0.017622800 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[318]: 0.017638675 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[319]: 0.017656375 - core[1].esp_sysview_heap_trace_free(513), plen 15: [addr: 1073450656, callers: [1074601412, 1074296884]]
[0.017656375] HEAP: Freed bytes @ 0x3ffb8ea0 from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:35
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[320]: 0.017674025 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[321]: 0.017701700 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[322]: 0.018819550 - core[0].svIsrEnter(2), plen 0: [irq_num: 5]
EVENT[323]: 0.018829625 - core[0].svExitIsrToScheduler(18), plen 0: []
EVENT[324]: 0.018844750 - core[0].svIdle(17), plen 0: []
EVENT[325]: 0.019010075 - core[1].svIsrEnter(2), plen 0: [irq_num: 5]
EVENT[326]: 0.019017950 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[327]: 0.019033200 - core[1].svTaskStartExec(4), plen 0: [tid: 12294320]
EVENT[328]: 0.019358925 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[329]: 0.019374600 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[330]: 0.019395425 - core[1].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450520, size: 11, callers: [1074601427, 1074296884]]
[0.019395425] HEAP: Allocated 11 bytes @ 0x3ffb8e18 from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:37
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[331]: 0.019412600 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[332]: 0.019446250 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[333]: 0.022049900 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[334]: 0.022065775 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[335]: 0.022086625 - core[1].esp_sysview_heap_trace_alloc(512), plen 16: [addr: 1073450536, size: 24, callers: [1074601440, 1074296884]]
[0.022086625] HEAP: Allocated 24 bytes @ 0x3ffb8e28 from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:38
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[336]: 0.022103925 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[337]: 0.022137550 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[338]: 0.024740850 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[339]: 0.024756725 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[340]: 0.024770475 - core[1].esp_sysview_heap_trace_free(513), plen 15: [addr: 1073450536, callers: [1074601455, 1074296884]]
[0.024770475] HEAP: Freed bytes @ 0x3ffb8e28 from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:41
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
EVENT[341]: 0.024791750 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12291660, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[342]: 0.024819500 - core[1].xQueueGenericReceive(49), plen 15: [xQueue: 12275732, pvBuffer: 3233808384, xTicksToWait: 4294967295, xJustPeek: 0]
EVENT[343]: 0.026476950 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12275732, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[344]: 0.026495700 - core[1].xQueueGenericSend(53), plen 7: [xQueue: 12291660, pvItemToQueue: 0, xTicksToWait: 0, xCopyPosition: 0]
EVENT[345]: 0.026506975 - core[0].svTaskStartReady(6), plen 0: [tid: 12291908]
EVENT[346]: 0.026506975 - core[1].svTaskStartReady(6), plen 0: [tid: 12291908]
EVENT[347]: 0.026518525 - core[1].svTaskStopReady(7), plen 0: [tid: 12294320, cause: 27]
EVENT[348]: 0.026526625 - core[0].svIsrEnter(2), plen 0: [irq_num: 30]
EVENT[349]: 0.026535575 - core[0].svExitIsrToScheduler(18), plen 0: []
EVENT[350]: 0.026544075 - core[1].svIsrEnter(2), plen 0: [irq_num: 31]
EVENT[351]: 0.026551650 - core[0].svTaskStartExec(4), plen 0: [tid: 12291908]
EVENT[352]: 0.026559500 - core[1].svExitIsrToScheduler(18), plen 0: []
EVENT[353]: 0.148816725 - core[1].svIdle(17), plen 0: []
EVENT[354]: 0.148825750 - core[0].vTaskDelay(34), plen 1: [xTicksToDelay: 1]
EVENT[355]: 0.148833200 - core[0].svTaskStopReady(7), plen 0: [tid: 12291908, cause: 4]
EVENT[356]: 0.148839250 - core[0].svTraceStop(11), plen 0: []
EVENT[357]: 0.148839250 - core[1].svTraceStop(11), plen 0: []
Processing completed.
Processed 358 events
=============== LOG TRACE REPORT ===============
Processed 0 log messages.
=============== HEAP TRACE REPORT ===============
Processed 14 heap events.
[0.008957950] HEAP: Allocated 80 bytes @ 0x3ffb8e4c from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
[0.009089600] HEAP: Allocated 80 bytes @ 0x3ffb5014 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
/home/alexey/projects/esp/esp-idf/components/freertos/queue.c:2037
[0.009223275] HEAP: Allocated 96 bytes @ 0x3ffb5068 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:68
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.009507600] HEAP: Allocated 10 bytes @ 0x3ffb8e08 from task "blink_task" on core 0 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:72
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.014984150] HEAP: Allocated 97 bytes @ 0x3ffb50cc from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:33
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
[0.019395425] HEAP: Allocated 11 bytes @ 0x3ffb8e18 from task "blink_task2" on core 1 by:
/home/alexey/projects/esp/esp-idf/examples/get-started/blink/main/blink.c:37
/home/alexey/projects/esp/esp-idf/components/freertos/port.c:355 (discriminator 1)
Found 374 leaked bytes in 6 blocks.

View file

@ -0,0 +1,19 @@
target remote :3333
mon reset halt
flushregs
b heap_trace_start
commands
clear heap_trace_start
mon esp32 sysview start file://cpu0.svdat file://cpu1.svdat
c
end
b heap_trace_stop
commands
clear heap_trace_stop
mon esp32 sysview stop
end
c

Binary file not shown.

View file

@ -0,0 +1,8 @@
#! /bin/bash
{ coverage debug sys \
&& coverage erase &> output \
&& coverage run -a $IDF_PATH/tools/esp_app_trace/sysviewtrace_proc.py -d -p cpu0.svdat cpu1.svdat test.elf &>> output \
&& diff output expected_output \
&& coverage report \
; } || { echo 'The test for sysviewtrace_proc has failed. Please examine the artifacts.' ; exit 1; }