diff --git a/components/app_trace/Kconfig b/components/app_trace/Kconfig index 6939174a3f..a10fcadfa6 100644 --- a/components/app_trace/Kconfig +++ b/components/app_trace/Kconfig @@ -191,15 +191,6 @@ menu "Application Level Tracing" help Size of the memory buffer for trace data in bytes. - config APPTRACE_PENDING_DATA_SIZE_MAX - int "Size of the pending data buffer" - depends on APPTRACE_MEMBUFS_APPTRACE_PROTO_ENABLE - default 0 - help - Size of the buffer for events in bytes. It is useful for buffering events from - the time critical code (scheduler, ISRs etc). If this parameter is 0 then - events will be discarded when main HW buffer is full. - menu "FreeRTOS SystemView Tracing" depends on APPTRACE_ENABLE config APPTRACE_SV_ENABLE diff --git a/components/app_trace/app_trace_membufs_proto.c b/components/app_trace/app_trace_membufs_proto.c index 9b96ff6da8..ef64277f74 100644 --- a/components/app_trace/app_trace_membufs_proto.c +++ b/components/app_trace/app_trace_membufs_proto.c @@ -63,10 +63,6 @@ esp_err_t esp_apptrace_membufs_init(esp_apptrace_membufs_proto_data_t *proto, co proto->state.markers[i] = 0; } proto->state.in_block = 0; -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - esp_apptrace_rb_init(&proto->rb_pend, proto->pending_data, - sizeof(proto->pending_data)); -#endif return ESP_OK; } @@ -80,10 +76,10 @@ static esp_err_t esp_apptrace_membufs_swap(esp_apptrace_membufs_proto_data_t *pr { int prev_block_num = proto->state.in_block % 2; int new_block_num = prev_block_num ? (0) : (1); - esp_err_t res = ESP_OK; - res = proto->hw->swap_start(proto->state.in_block); + esp_err_t res = proto->hw->swap_start(proto->state.in_block); if (res != ESP_OK) { + ESP_APPTRACE_LOGE("Failed to swap to new block: %d", res); return res; } @@ -112,28 +108,6 @@ static esp_err_t esp_apptrace_membufs_swap(esp_apptrace_membufs_proto_data_t *pr } hdr->block_sz = 0; } -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - // copy pending data to block if any - while (proto->state.markers[new_block_num] < proto->blocks[new_block_num].sz) { - uint32_t read_sz = esp_apptrace_rb_read_size_get(&proto->rb_pend); - if (read_sz == 0) { - break; // no more data in pending buffer - } - if (read_sz > proto->blocks[new_block_num].sz - proto->state.markers[new_block_num]) { - read_sz = proto->blocks[new_block_num].sz - proto->state.markers[new_block_num]; - } - uint8_t *ptr = esp_apptrace_rb_consume(&proto->rb_pend, read_sz); - if (!ptr) { - assert(false && "Failed to consume pended bytes!!"); - break; - } - ESP_APPTRACE_LOGD("Pump %d pend bytes [%x %x %x %x : %x %x %x %x : %x %x %x %x : %x %x...%x %x]", - read_sz, *(ptr + 0), *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), - *(ptr + 5), *(ptr + 6), *(ptr + 7), *(ptr + 8), *(ptr + 9), *(ptr + 10), *(ptr + 11), *(ptr + 12), *(ptr + 13), *(ptr + read_sz - 2), *(ptr + read_sz - 1)); - memcpy(proto->blocks[new_block_num].start + proto->state.markers[new_block_num], ptr, read_sz); - proto->state.markers[new_block_num] += read_sz; - } -#endif proto->hw->swap_end(proto->state.in_block, proto->state.markers[prev_block_num]); return res; } @@ -230,45 +204,6 @@ static uint32_t esp_apptrace_membufs_down_buffer_write_nolock(esp_apptrace_membu return total_sz; } -static inline uint8_t *esp_apptrace_membufs_wait4buf(esp_apptrace_membufs_proto_data_t *proto, uint16_t size, esp_apptrace_tmo_t *tmo, int *pended) -{ - uint8_t *ptr = NULL; - - int res = esp_apptrace_membufs_swap_waitus(proto, tmo); - if (res != ESP_OK) { - return NULL; - } -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - // check if we still have pending data - if (esp_apptrace_rb_read_size_get(&proto->rb_pend) > 0) { - // if after block switch we still have pending data (not all pending data have been pumped to block) - // alloc new pending buffer - *pended = 1; - ptr = esp_apptrace_rb_produce(&proto->rb_pend, size); - if (!ptr) { - ESP_APPTRACE_LOGE("Failed to alloc pend buf 1: w-r-s %d-%d-%d!", proto->rb_pend.wr, proto->rb_pend.rd, proto->rb_pend.cur_size); - } - } else -#endif - { - // update block pointers - if (ESP_APPTRACE_INBLOCK_MARKER(proto) + size > ESP_APPTRACE_INBLOCK(proto)->sz) { -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - *pended = 1; - ptr = esp_apptrace_rb_produce(&proto->rb_pend, size); - if (ptr == NULL) { - ESP_APPTRACE_LOGE("Failed to alloc pend buf 2: w-r-s %d-%d-%d!", proto->rb_pend.wr, proto->rb_pend.rd, proto->rb_pend.cur_size); - } -#endif - } else { - *pended = 0; - ptr = ESP_APPTRACE_INBLOCK(proto)->start + ESP_APPTRACE_INBLOCK_MARKER(proto); - } - } - - return ptr; -} - static inline uint8_t *esp_apptrace_membufs_pkt_start(uint8_t *ptr, uint16_t size) { // it is safe to use esp_cpu_get_core_id() in macro call because arg is used only once inside it @@ -286,63 +221,23 @@ static inline void esp_apptrace_membufs_pkt_end(uint8_t *ptr) uint8_t *esp_apptrace_membufs_up_buffer_get(esp_apptrace_membufs_proto_data_t *proto, uint32_t size, esp_apptrace_tmo_t *tmo) { - uint8_t *buf_ptr = NULL; - if (size > ESP_APPTRACE_USR_DATA_LEN_MAX(proto)) { ESP_APPTRACE_LOGE("Too large user data size %" PRIu32 "!", size); return NULL; } - // check for data in the pending buffer -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - if (esp_apptrace_rb_read_size_get(&proto->rb_pend) > 0) { - // if we have buffered data try to switch block - esp_apptrace_membufs_swap(proto); - // if switch was successful, part or all pended data have been copied to block - } - if (esp_apptrace_rb_read_size_get(&proto->rb_pend) > 0) { - // if we have buffered data alloc new pending buffer - ESP_APPTRACE_LOGD("Get %d bytes from PEND buffer", size); - buf_ptr = esp_apptrace_rb_produce(&proto->rb_pend, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); - if (buf_ptr == NULL) { - int pended_buf; - buf_ptr = esp_apptrace_membufs_wait4buf(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size), tmo, &pended_buf); - if (buf_ptr && !pended_buf) { - ESP_APPTRACE_LOGD("Get %d bytes from block", size); - // update cur block marker - ESP_APPTRACE_INBLOCK_MARKER_UPD(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); - } - } - } else { -#else - if (1) { -#endif - if (ESP_APPTRACE_INBLOCK_MARKER(proto) + ESP_APPTRACE_USR_BLOCK_RAW_SZ(size) > ESP_APPTRACE_INBLOCK(proto)->sz) { -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - ESP_APPTRACE_LOGD("Block full. Get %" PRIu32 " bytes from PEND buffer", size); - buf_ptr = esp_apptrace_rb_produce(&proto->rb_pend, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); -#endif - if (buf_ptr == NULL) { - int pended_buf; - ESP_APPTRACE_LOGD(" full. Get %" PRIu32 " bytes from pend buffer", size); - buf_ptr = esp_apptrace_membufs_wait4buf(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size), tmo, &pended_buf); - if (buf_ptr && !pended_buf) { - ESP_APPTRACE_LOGD("Got %" PRIu32 " bytes from block", size); - // update cur block marker - ESP_APPTRACE_INBLOCK_MARKER_UPD(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); - } - } - } else { - ESP_APPTRACE_LOGD("Get %" PRIu32 " bytes from buffer", size); - // fit to curr nlock - buf_ptr = ESP_APPTRACE_INBLOCK(proto)->start + ESP_APPTRACE_INBLOCK_MARKER(proto); - // update cur block marker - ESP_APPTRACE_INBLOCK_MARKER_UPD(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); + if (ESP_APPTRACE_INBLOCK_MARKER(proto) + ESP_APPTRACE_USR_BLOCK_RAW_SZ(size) > ESP_APPTRACE_INBLOCK(proto)->sz) { + int res = esp_apptrace_membufs_swap_waitus(proto, tmo); + if (res != ESP_OK) { + return NULL; } } - if (buf_ptr) { - buf_ptr = esp_apptrace_membufs_pkt_start(buf_ptr, size); - } + + uint8_t *buf_ptr = ESP_APPTRACE_INBLOCK(proto)->start + ESP_APPTRACE_INBLOCK_MARKER(proto); + // update cur block marker + ESP_APPTRACE_INBLOCK_MARKER_UPD(proto, ESP_APPTRACE_USR_BLOCK_RAW_SZ(size)); + buf_ptr = esp_apptrace_membufs_pkt_start(buf_ptr, size); + ESP_APPTRACE_LOGD("Got %" PRIu32 " bytes from block", size); return buf_ptr; } @@ -366,7 +261,7 @@ esp_err_t esp_apptrace_membufs_flush_nolock(esp_apptrace_membufs_proto_data_t *p ESP_APPTRACE_LOGI("Ignore flush request for min %" PRIu32 " bytes. Bytes in block: %" PRIu32, min_sz, ESP_APPTRACE_INBLOCK_MARKER(proto)); return ESP_OK; } - // switch block while size of data (including that in pending buffer) is more than min size + // switch block while size of data is more than min size while (ESP_APPTRACE_INBLOCK_MARKER(proto) > min_sz) { ESP_APPTRACE_LOGD("Try to flush %" PRIu32 " bytes", ESP_APPTRACE_INBLOCK_MARKER(proto)); res = esp_apptrace_membufs_swap_waitus(proto, tmo); diff --git a/components/app_trace/port/xtensa/port.c b/components/app_trace/port/xtensa/port.c index edc4e66b23..6dce040d39 100644 --- a/components/app_trace/port/xtensa/port.c +++ b/components/app_trace/port/xtensa/port.c @@ -106,16 +106,7 @@ // Data which are transffered from host to target are also prepended with a header. Down channel data header is simple and consists of one two bytes field // containing length of host data following the header. -// 4.3 Data Buffering -// ------------------ - -// It takes some time for the host to read TRAX memory block via JTAG. In streaming mode it can happen that target has filled its TRAX block, but host -// has not completed reading of the previous one yet. So in this case time critical tracing calls (which can not be delayed for too long time due to -// the lack of free memory in TRAX block) can be dropped. To avoid such scenarios tracing module implements data buffering. Buffered data will be sent -// to the host later when TRAX block switch occurs. The maximum size of the buffered data is controlled by menuconfig option -// CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX. - -// 4.4 Target Connection/Disconnection +// 4.3 Target Connection/Disconnection // ----------------------------------- // When host is going to start tracing in streaming mode it needs to put both ESP32 cores into initial state when 'host connected' bit is set diff --git a/components/app_trace/private_include/esp_app_trace_membufs_proto.h b/components/app_trace/private_include/esp_app_trace_membufs_proto.h index fb1ef53a5d..a48fb5f4bc 100644 --- a/components/app_trace/private_include/esp_app_trace_membufs_proto.h +++ b/components/app_trace/private_include/esp_app_trace_membufs_proto.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -38,12 +38,6 @@ typedef struct { esp_apptrace_membufs_proto_hw_t * hw; volatile esp_apptrace_membufs_state_t state; // state esp_apptrace_mem_block_t blocks[2]; // memory blocks -#if CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX > 0 - // ring buffer control struct for pending user blocks - esp_apptrace_rb_t rb_pend; - // storage for pending user blocks - uint8_t pending_data[CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX + 1]; -#endif // ring buffer control struct for data from host (down buffer) esp_apptrace_rb_t rb_down; } esp_apptrace_membufs_proto_data_t; diff --git a/components/app_trace/sdkconfig.rename b/components/app_trace/sdkconfig.rename index 838b7f768b..03babc3d8c 100644 --- a/components/app_trace/sdkconfig.rename +++ b/components/app_trace/sdkconfig.rename @@ -8,7 +8,6 @@ CONFIG_ESP32_APPTRACE_ENABLE CONFIG_APPTRACE_ENABLE CONFIG_ESP32_APPTRACE_LOCK_ENABLE CONFIG_APPTRACE_LOCK_ENABLE CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH -CONFIG_ESP32_APPTRACE_PENDING_DATA_SIZE_MAX CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX CONFIG_ESP32_GCOV_ENABLE CONFIG_APPTRACE_GCOV_ENABLE CONFIG_SYSVIEW_ENABLE CONFIG_APPTRACE_SV_ENABLE diff --git a/docs/en/api-guides/app_trace.rst b/docs/en/api-guides/app_trace.rst index bb644edc62..d9243167d2 100644 --- a/docs/en/api-guides/app_trace.rst +++ b/docs/en/api-guides/app_trace.rst @@ -31,7 +31,7 @@ The library supports two modes of operation: **Post-mortem mode:** This is the default mode. The mode does not need interaction with the host side. In this mode, tracing module does not check whether the host has read all the data from *HW UP BUFFER*, but directly overwrites old data with the new ones. This mode is useful when only the latest trace data is interesting to the user, e.g., for analyzing program's behavior just before the crash. The host can read the data later on upon user request, e.g., via special OpenOCD command in case of working via JTAG interface. -**Streaming mode:** Tracing module enters this mode when the host connects to {IDF_TARGET_NAME}. In this mode, before writing new data to *HW UP BUFFER*, the tracing module checks that whether there is enough space in it and if necessary, waits for the host to read data and free enough memory. Maximum waiting time is controlled via timeout values passed by users to corresponding API routines. So when application tries to write data to the trace buffer using the finite value of the maximum waiting time, it is possible that this data will be dropped. This is especially true for tracing from time critical code (ISRs, OS scheduler code, etc.) where infinite timeouts can lead to system malfunction. In order to avoid loss of such critical data, developers can enable additional data buffering via menuconfig option :ref:`CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX`. This macro specifies the size of data which can be buffered in above conditions. The option can also help to overcome situation when data transfer to the host is temporarily slowed down, e.g., due to USB bus congestions. But it will not help when the average bitrate of the trace data stream exceeds the hardware interface capabilities. +**Streaming mode:** Tracing module enters this mode when the host connects to {IDF_TARGET_NAME}. In this mode, before writing new data to *HW UP BUFFER*, the tracing module checks that whether there is enough space in it and if necessary, waits for the host to read data and free enough memory. Maximum waiting time is controlled via timeout values passed by users to corresponding API routines. So when application tries to write data to the trace buffer using the finite value of the maximum waiting time, it is possible that this data will be dropped. This is especially true for tracing from time critical code (ISRs, OS scheduler code, etc.) where infinite timeouts can lead to system malfunction. Configuration Options and Dependencies diff --git a/docs/en/migration-guides/release-6.x/6.0/system.rst b/docs/en/migration-guides/release-6.x/6.0/system.rst index 699a78edfa..f7f564c36e 100644 --- a/docs/en/migration-guides/release-6.x/6.0/system.rst +++ b/docs/en/migration-guides/release-6.x/6.0/system.rst @@ -43,3 +43,8 @@ Bootloader ---------- Removed option for compiling bootloader with no optimization level (-O0, `CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE`). On most targets it was no longer possible to compile the bootloader with -O0, as IRAM sections would overflow. For debugging purposes, it is recommended to use the -Og (:ref:`CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG`) optimization level instead. This provides a good balance between optimization and debuggability. + +App Trace +---------- + +Removed extra data buffering option. `CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX` is no longer supported. diff --git a/docs/zh_CN/api-guides/app_trace.rst b/docs/zh_CN/api-guides/app_trace.rst index 2cda75773b..94644a0041 100644 --- a/docs/zh_CN/api-guides/app_trace.rst +++ b/docs/zh_CN/api-guides/app_trace.rst @@ -31,7 +31,7 @@ ESP-IDF 中提供了应用层跟踪功能,用于分析应用程序的行为。 **后验模式:** 后验模式为默认模式,该模式不需要和主机进行交互。在这种模式下,跟踪模块不会检查主机是否已经从 *HW UP BUFFER* 缓冲区读走所有数据,而是直接使用新数据覆盖旧数据。如果用户仅对最新的跟踪数据感兴趣,例如想要分析程序在崩溃之前的行为,则推荐使用该模式。主机可以稍后根据用户的请求来读取数据,例如在使用 JTAG 接口的情况下,通过特殊的 OpenOCD 命令进行读取。 -**流模式:** 当主机连接到 {IDF_TARGET_NAME} 时,跟踪模块会进入此模式。在这种模式下,跟踪模块在新数据写入 *HW UP BUFFER* 之前会检查其中是否有足够的空间,并在必要的时候等待主机读取数据并释放足够的内存。最大等待时间是由用户传递给相应 API 函数的超时时间参数决定的。因此当应用程序尝试使用有限的最大等待时间值来将数据写入跟踪缓冲区时,这些数据可能会被丢弃。尤其需要注意的是,如果在对时效要求严格的代码中(如中断处理函数、操作系统调度等)指定了无限的超时时间,将会导致系统故障。为了避免丢失此类关键数据,开发人员可以在 menuconfig 中开启 :ref:`CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX` 选项,以启用额外的数据缓冲区。此宏还指定了在上述条件下可以缓冲的数据大小,它有助于缓解由于 USB 总线拥塞等原因导致的向主机传输数据间歇性减缓的状况。但是,当跟踪数据流的平均比特率超出硬件接口的能力时,该选项无法发挥作用。 +**流模式:** 当主机连接到 {IDF_TARGET_NAME} 时,跟踪模块会进入此模式。在这种模式下,跟踪模块在新数据写入 *HW UP BUFFER* 之前会检查其中是否有足够的空间,并在必要的时候等待主机读取数据并释放足够的内存。最大等待时间是由用户传递给相应 API 函数的超时时间参数决定的。因此当应用程序尝试使用有限的最大等待时间值来将数据写入跟踪缓冲区时,这些数据可能会被丢弃。尤其需要注意的是,如果在对时效要求严格的代码中(如中断处理函数、操作系统调度等)指定了无限的超时时间,将会导致系统故障。 配置选项与依赖项 diff --git a/examples/system/gcov/sdkconfig.defaults b/examples/system/gcov/sdkconfig.defaults index fc57db37a0..92f37bc103 100644 --- a/examples/system/gcov/sdkconfig.defaults +++ b/examples/system/gcov/sdkconfig.defaults @@ -4,5 +4,4 @@ CONFIG_APPTRACE_ENABLE=y CONFIG_APPTRACE_LOCK_ENABLE=y CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO=-1 CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH=0 -CONFIG_APPTRACE_PENDING_DATA_SIZE_MAX=0 CONFIG_APPTRACE_GCOV_ENABLE=y