From 992b2f75c501e1188975952efe644cda455539f7 Mon Sep 17 00:00:00 2001 From: Zhou Xiao Date: Fri, 20 Mar 2026 17:21:33 +0800 Subject: [PATCH] fix(bt/ble_log): use aligned counters in ble_log_stat_mgr_t Replace embedded ble_log_enh_stat_t (packed wire struct) inside ble_log_stat_mgr_t with flat uint32_t counters. Natural 4-byte alignment ensures each load/store compiles to a single l32i/s32i on Xtensa/RISC-V, making individual field access atomic without locks. Build the packed wire format on the stack inside a critical section in ble_log_write_enh_stat() so the full snapshot is consistent. --- .../bt/common/ble_log/src/ble_log_lbm.c | 34 ++++++++++++------- .../src/internal_include/ble_log_lbm.h | 11 +++++- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/components/bt/common/ble_log/src/ble_log_lbm.c b/components/bt/common/ble_log/src/ble_log_lbm.c index 55a21c7edb..d5bd87e96a 100644 --- a/components/bt/common/ble_log/src/ble_log_lbm.c +++ b/components/bt/common/ble_log/src/ble_log_lbm.c @@ -137,14 +137,14 @@ void ble_log_stat_mgr_update(ble_log_src_t src_code, uint32_t len, bool lost) /* Get statistic manager by source code */ ble_log_stat_mgr_t *stat_mgr = stat_mgr_ctx[src_code]; - /* Update statistics */ + /* Update aligned counters */ uint32_t bytes_cnt = len + BLE_LOG_FRAME_OVERHEAD; if (lost) { - stat_mgr->enh_stat.lost_frame_cnt++; - stat_mgr->enh_stat.lost_bytes_cnt += bytes_cnt; + stat_mgr->lost_frame_cnt++; + stat_mgr->lost_bytes_cnt += bytes_cnt; } else { - stat_mgr->enh_stat.written_frame_cnt++; - stat_mgr->enh_stat.written_bytes_cnt += bytes_cnt; + stat_mgr->written_frame_cnt++; + stat_mgr->written_bytes_cnt += bytes_cnt; } } @@ -212,9 +212,6 @@ bool ble_log_lbm_init(void) goto exit; } BLE_LOG_MEMSET(stat_mgr_ctx[i], 0, sizeof(ble_log_stat_mgr_t)); - - stat_mgr_ctx[i]->enh_stat.int_src_code = BLE_LOG_INT_SRC_ENH_STAT; - stat_mgr_ctx[i]->enh_stat.src_code = i; } /* Initialization done */ @@ -304,9 +301,23 @@ void ble_log_write_enh_stat(void) goto deref; } + /* Snapshot all sources under one critical section so the set of + * counters is mutually consistent, then write outside the lock. */ + ble_log_enh_stat_t snapshots[BLE_LOG_SRC_MAX]; for (int i = 0; i < BLE_LOG_SRC_MAX; i++) { - ble_log_enh_stat_t *enh_stat = &(stat_mgr_ctx[i]->enh_stat); - ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)enh_stat, sizeof(ble_log_enh_stat_t)); + snapshots[i].int_src_code = BLE_LOG_INT_SRC_ENH_STAT; + snapshots[i].src_code = i; + } + BLE_LOG_ENTER_CRITICAL(); + for (int i = 0; i < BLE_LOG_SRC_MAX; i++) { + BLE_LOG_MEMCPY(&snapshots[i].written_frame_cnt, + &stat_mgr_ctx[i]->written_frame_cnt, + 4 * sizeof(uint32_t)); + } + BLE_LOG_EXIT_CRITICAL(); + + for (int i = 0; i < BLE_LOG_SRC_MAX; i++) { + ble_log_write_hex(BLE_LOG_SRC_INTERNAL, (const uint8_t *)&snapshots[i], sizeof(ble_log_enh_stat_t)); } deref: @@ -389,9 +400,6 @@ void ble_log_flush(void) /* Reset statistics manager after all operations complete */ for (int i = 0; i < BLE_LOG_SRC_MAX; i++) { BLE_LOG_MEMSET(stat_mgr_ctx[i], 0, sizeof(ble_log_stat_mgr_t)); - /* Reinitialize enhanced statistics fields */ - stat_mgr_ctx[i]->enh_stat.int_src_code = BLE_LOG_INT_SRC_ENH_STAT; - stat_mgr_ctx[i]->enh_stat.src_code = i; } /* Resume enable status */ diff --git a/components/bt/common/ble_log/src/internal_include/ble_log_lbm.h b/components/bt/common/ble_log/src/internal_include/ble_log_lbm.h index 26def47e5c..111cbac37b 100644 --- a/components/bt/common/ble_log/src/internal_include/ble_log_lbm.h +++ b/components/bt/common/ble_log/src/internal_include/ble_log_lbm.h @@ -138,7 +138,16 @@ typedef struct { /* -------------------------------------- */ typedef struct { uint32_t frame_sn; - ble_log_enh_stat_t enh_stat; + /* Aligned live counters — updated by ble_log_stat_mgr_update(), + * snapshot by ble_log_write_enh_stat(). Natural 4-byte alignment + * ensures each load/store compiles to a single l32i/s32i on + * Xtensa/RISC-V, so individual field access is atomic without locks. + * The packed ble_log_enh_stat_t wire format is built on the stack + * only when serializing to UART. */ + uint32_t written_frame_cnt; + uint32_t lost_frame_cnt; + uint32_t written_bytes_cnt; + uint32_t lost_bytes_cnt; } ble_log_stat_mgr_t; #define BLE_LOG_GET_FRAME_SN(VAR) __atomic_fetch_add(VAR, 1, __ATOMIC_RELAXED)