From 96855f6b6b9def47169fd9eaef58d0a5f7b33a56 Mon Sep 17 00:00:00 2001 From: Wanderingss <1624155937@qq.com> Date: Mon, 21 Sep 2026 05:10:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=86=85=E5=AD=98=E5=B8=83=E5=B1=80=E5=9B=BE?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=88=B009-21=E6=9C=80=E6=96=B0=EF=BC=9A?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E6=A0=88=E9=A2=84=E7=AE=97=E5=90=AB=E5=AE=9E?= =?UTF-8?q?=E6=B5=8B=E5=B3=B0=E5=80=BC=E4=B8=8E=E5=88=A4=E5=AE=9A=EF=BC=8C?= =?UTF-8?q?RAM=E5=8F=8C=E5=8C=BA/Flash=E5=B8=83=E5=B1=80=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/images/任务栈预算.svg | 68 +++++--- docs/images/内存布局_FLASH.svg | 53 +++--- docs/images/内存布局_RAM.svg | 89 +++++----- tools/arch_diagram/gen_memory_svg.py | 250 ++++++++++++++++----------- 4 files changed, 266 insertions(+), 194 deletions(-) diff --git a/docs/images/任务栈预算.svg b/docs/images/任务栈预算.svg index 06d27e35..ed02c6e0 100644 --- a/docs/images/任务栈预算.svg +++ b/docs/images/任务栈预算.svg @@ -1,4 +1,4 @@ - + -FreeRTOS 任务栈分配 (48KB 堆池) -分配栈大小 (Bytes) - defaultTask - - 2048B (2.0KB) - netTask - - 4096B (4.0KB) - ftpTask - - 4096B (4.0KB) - testTask - - 4096B (4.0KB) - uiTask - - 16384B (16.0KB) - timeSyncTask - - 2048B (2.0KB) -堆总量: 49,152B (48KB) 任务栈合计: ~34304B (33.5KB) 空闲: ~13736B (13.4KB) - - Normal 优先级 - - BelowNormal 优先级 +FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM) +数据: 2026-09-21 @build + FTP 128KB 实测(data/stack_report_20260921.md) +浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定 + defaultTask + + + 配置 4096B | 实测峰值 2136B | 最坏 2776B | 余量 1320B (32%) PASS + netTask + + + 配置 4096B | 实测峰值 588B | 最坏 588B | 余量 3508B (85%) PASS + ftpTask + + + 配置 4096B | 实测峰值 1184B | 最坏 1184B | 余量 2912B (71%) PASS + testTask + + + 配置 8192B | 实测峰值 348B | 最坏 348B | 余量 7844B (95%) PASS + uiTask + + + 配置 16384B | 实测峰值 3824B | 最坏 3824B | 余量 12560B (76%) PASS + timeSyncTask + + + 配置 2048B | 实测峰值 420B | 最坏 420B | 余量 1628B (79%) PASS + idle + + 512B(未实测) + timer + + 1024B(未实测) +堆总量: 49152B (48KB, RW_CCM) 任务栈合计: 38912B (38.0KB) + 内核栈 1536B +实测: free=8784B / min_ever=4848B(2026-09-21,含 FTP 负载) 判定: 6/6 PASS(余量 ≥ max(1024B, 配置×30%)) + + Normal 优先级 + + BelowNormal 优先级 + + 内核任务栈 (idle/timer) diff --git a/docs/images/内存布局_FLASH.svg b/docs/images/内存布局_FLASH.svg index b59cf628..07e91eb9 100644 --- a/docs/images/内存布局_FLASH.svg +++ b/docs/images/内存布局_FLASH.svg @@ -7,29 +7,32 @@ .bar-seg { stroke:#fff; stroke-width:0.5; } -Flash (1MB) 使用布局 - - 代码段 (Code) 214.8KB - - 只读数据 (RO) 11.2KB - - Flash 空闲 797.4KB -已用: 226.6KB (22.1%) 空闲: 797.4KB (77.9%) 总量: 1024KB -代码段明细 (214.8KB) - - LVGL 库 67.7KB - - 应用代码/UI 41.5KB - - C 库 (microlib) 4.1KB - - FatFS + dhara 11.3KB - - CH395F 网络 8.6KB - - HAL 驱动 9.2KB - - FreeRTOS 4.1KB - - 其他 68.2KB +Flash (1MB) 使用布局 — 2026-09-21 @build + + 代码段 (Code) 229.5KB + + 只读数据 (RO) 13.5KB + + Flash 空闲 780.4KB +已用: 243.6KB (23.8%) 空闲: 780.4KB (76.2%) 总量: 1024KB +代码段明细 (229.5KB) + + LVGL 库 95.7KB + + 应用代码/UI 33.3KB + + FatFS 8.0KB + + dhara / FTL 4.9KB + + HAL 驱动 + 15.6KB + + FreeRTOS 内核 9.9KB + + CH395F 网络 2.7KB + + C 库 (microlib) 4.1KB + + 其他 (长尾) 55.3KB diff --git a/docs/images/内存布局_RAM.svg b/docs/images/内存布局_RAM.svg index fbd8dfaa..a6a98cb3 100644 --- a/docs/images/内存布局_RAM.svg +++ b/docs/images/内存布局_RAM.svg @@ -1,4 +1,4 @@ - + -SRAM (128KB) 使用布局 - - FreeRTOS 堆 (48KB heap_4) - - LVGL 内存池 (40KB) - - UI 帧缓冲 - (~13KB) - - FTL / 存储 - (~11KB) - - 网络 / - CH395F - (~7KB) - - 内核 / CMSIS (~3KB) - - HAL 驱动 (~1.4KB) - - 其他静态 (~0.5KB) - - - FreeRTOS 堆 (48KB heap_4): 48.0KB (37.5%) - - LVGL 内存池 (40KB): 40.0KB (31.2%) - - UI 帧缓冲 (~13KB): 12.8KB (10.0%) - - FTL / 存储 (~11KB): 12.1KB (9.5%) - - 网络 / CH395F (~7KB): 6.9KB (5.4%) - - 内核 / CMSIS (~3KB): 3.0KB (2.3%) - - HAL 驱动 (~1.4KB): 1.4KB (1.1%) - - 其他静态 (~0.5KB): 0.5KB (0.4%) - - SRAM 空闲: 5.8KB (4.6%) -已用: 122.2KB (95.4%) 空闲: 5.8KB (4.6%) 总量: 128KB +SRAM (192KB) 使用布局 — 2026-09-21 @build +主 SRAM RW_IRAM1 @0x20000000(128KB,DMA 可达) + + LVGL + + UI + + + + + + + + + free +已用: 82048B (62.6%) 空闲: 49024B (37.4%) 总量: 128KB +CCM RW_CCM @0x10000000(64KB,仅 CPU 可达,DMA 不可达) + + heap + + free +已用: 49184B (75.0%) 空闲: 16352B (25.0%) 总量: 64KB + + 主SRAM LVGL: 40.5KB (31.6%) + + 主SRAM UI: 13.2KB (10.3%) + + 主SRAM FTL/BBT: 8.6KB (6.7%) + + 主SRAM lftpd: 5.2KB (4.1%) + + 主SRAM CMSIS: 4.9KB (3.8%) + + 主SRAM NET: 4.3KB (3.4%) + + 主SRAM HAL: 1.2KB (1.0%) + + 主SRAM C stack: 1.0KB (0.8%) + + 主SRAM other: 1.1KB (0.9%) + + 主SRAM free: 47.9KB (37.4%) + + CCM heap: 48.0KB (75.0%) + + CCM free: 16.0KB (25.0%) diff --git a/tools/arch_diagram/gen_memory_svg.py b/tools/arch_diagram/gen_memory_svg.py index 5d9623d4..db0bcb49 100644 --- a/tools/arch_diagram/gen_memory_svg.py +++ b/tools/arch_diagram/gen_memory_svg.py @@ -17,28 +17,38 @@ import sys # Diagram data # --------------------------------------------------------------------------- -# ── RAM breakdown (128KB = 131,072 B) ──────────────────────────────────────── -SRAM_TOTAL = 131072 -SRAM_USED = 125104 -SRAM_FREE = SRAM_TOTAL - SRAM_USED +# ── RAM breakdown (2026-09-21 @build, map Grand Totals; data/ram_report_20260921.md) ── +# Region 1: main SRAM RW_IRAM1 @0x20000000 (128KB = 131,072 B, DMA-reachable) +SRAM1_TOTAL = 131072 +SRAM1_USED = 82048 +SRAM1_FREE = SRAM1_TOTAL - SRAM1_USED +# Region 2: CCM RW_CCM @0x10000000 (64KB = 65,536 B, CPU only, DMA NOT reachable) +CCM_TOTAL = 65536 +CCM_USED = 49184 +CCM_FREE = CCM_TOTAL - CCM_USED -RAM_CATEGORIES = [ - ("FreeRTOS 堆\n(48KB heap_4)", 49152, "#2196F3"), - ("LVGL 内存池\n(40KB)", 40960, "#4CAF50"), - ("UI 帧缓冲\n(~13KB)", 13158, "#FF9800"), - ("FTL / 存储\n(~11KB)", 12416, "#9C27B0"), - ("网络 / CH395F\n(~7KB)", 7110, "#F44336"), - ("内核 / CMSIS\n(~3KB)", 3024, "#00BCD4"), - ("HAL 驱动\n(~1.4KB)", 1400, "#607D8B"), - ("其他静态\n(~0.5KB)", 498, "#795548"), - ("SRAM 空闲", SRAM_FREE, "#E0E0E0"), +RAM1_CATEGORIES = [ + ("LVGL", 41460, "#4CAF50"), + ("UI", 13532, "#FF9800"), + ("FTL/BBT", 8812, "#9C27B0"), + ("lftpd", 5324, "#8BC34A"), + ("CMSIS", 5016, "#00BCD4"), + ("NET", 4445, "#F44336"), + ("HAL", 1280, "#607D8B"), + ("C stack", 1024, "#795548"), + ("other", 1155, "#9E9E9E"), + ("free", SRAM1_FREE, "#E0E0E0"), +] +RAM2_CATEGORIES = [ + ("heap", 49184, "#2196F3"), + ("free", CCM_FREE, "#E0E0E0"), ] -# ── Flash breakdown (1MB = 1,048,576 B) ───────────────────────────────────── +# ── Flash breakdown (1MB = 1,048,576 B; 2026-09-21 @build) ────────────────── FLASH_TOTAL = 1048576 -FLASH_CODE = 219976 -FLASH_RO = 11496 -FLASH_RW = 528 +FLASH_CODE = 234976 +FLASH_RO = 13824 +FLASH_RW = 632 FLASH_USED = FLASH_CODE + FLASH_RO + FLASH_RW FLASH_FREE = FLASH_TOTAL - FLASH_USED @@ -49,30 +59,37 @@ FLASH_CATEGORIES = [ ("Flash 空闲", FLASH_FREE, "#E0E0E0"), ] -# Flash code sub-breakdown (top categories from map analysis) +# Flash code sub-breakdown (2026-09-21; top items from data/ram_report_20260921.md, +# long-tail .o objects below the report's top-44 threshold are counted in "其他") FLASH_CODE_SUB = [ - ("LVGL 库", 69364, "#4CAF50"), - ("应用代码/UI", 42540, "#2196F3"), + ("LVGL 库", 98000, "#4CAF50"), + ("应用代码/UI", 34110, "#2196F3"), + ("FatFS", 8146, "#9C27B0"), + ("dhara / FTL", 4982, "#FF9800"), + ("HAL 驱动", 16000, "#607D8B"), + ("FreeRTOS 内核", 10132, "#00BCD4"), + ("CH395F 网络", 2738, "#F44336"), ("C 库 (microlib)", 4230, "#795548"), - ("FatFS + dhara", 11540, "#9C27B0"), - ("CH395F 网络", 8776, "#F44336"), - ("HAL 驱动", 9400, "#607D8B"), - ("FreeRTOS", 4240, "#00BCD4"), - ("其他", 69886, "#E0E0E0"), # remainder + ("其他 (长尾)", 56638, "#E0E0E0"), # remainder ] -# ── Task stack budgets ───────────────────────────────────────────────────── +# ── Task stack budgets (2026-09-21 @build + FTP 128KB 实测; data/stack_report_20260921.md) ── +# (name, cfg, prio, worst, peak_used, margin, margin_pct, verdict, desc) +# worst = max(静态最坏深度, 实测峰值); margin = cfg - worst TASK_STACKS = [ - ("defaultTask", 2048, "Normal", "FatFS 挂载、LED"), - ("netTask", 4096, "Normal", "CH395F 轮询、消息处理"), - ("ftpTask", 4096, "Normal", "lftpd FTP 服务"), - ("testTask", 4096, "BelowNormal", "测试套件"), - ("uiTask", 16384, "BelowNormal", "LVGL UI 主循环"), - ("timeSyncTask", 2048, "Normal", "TCP 时间同步"), + ("defaultTask", 4096, "Normal", 2776, 2136, 1320, 32, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + 栈探针"), + ("netTask", 4096, "Normal", 588, 588, 3508, 85, "PASS", "CH395F 轮询、消息处理"), + ("ftpTask", 4096, "Normal", 1184, 1184, 2912, 71, "PASS", "lftpd FTP 服务(大缓冲已静态化)"), + ("testTask", 8192, "BelowNormal", 348, 348, 7844, 95, "PASS", "测试套件(产品构建空转)"), + ("uiTask", 16384, "BelowNormal", 3824, 3824, 12560, 76, "PASS", "LVGL UI 主循环"), + ("timeSyncTask", 2048, "Normal", 420, 420, 1628, 79, "PASS", "TCP 时间同步"), ] +KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words -HEAP_FREE = 49152 - (2048+4096+4096+4096+16384+2048+512+1024+80*8+448+24) -# = 49152 - 35304 = 13848 (approximate; stacks+TCBs+queue+eventgroup) +HEAP_TOTAL = 49152 # configTOTAL_HEAP_SIZE(位于 RW_CCM) +HEAP_FREE = 8784 # 2026-09-21 实测(含 FTP 负载) +HEAP_MIN_EVER = 4848 +TOTAL_STACKS = sum(t[1] for t in TASK_STACKS) # 38,912 # --------------------------------------------------------------------------- # SVG helpers @@ -148,44 +165,69 @@ def _draw_bar_segment(x, y, w, h, fill, label_inside, label_outside="", # --------------------------------------------------------------------------- def gen_ram_svg(): - """内存布局_RAM.svg — horizontal stacked bar with legend.""" - W, H = 820, 320 - BAR_X, BAR_Y, BAR_H = 60, 50, 50 - SCALE = (W - 80) / SRAM_TOTAL + """内存布局_RAM.svg — 两条堆叠条:主 SRAM(DMA 可达)+ CCM(仅 CPU)。""" + W, H = 820, 360 + BAR_X, BAR_H = 60, 44 + SCALE = (W - 80) / SRAM1_TOTAL # 128KB 占满宽;CCM (64KB) 占半宽 svg = svg_header(W, H) - svg += f'SRAM (128KB) 使用布局\n' + svg += f'SRAM (192KB) 使用布局 — 2026-09-21 @build\n' + # Region 1: 主 SRAM + y1 = 50 + svg += f'主 SRAM RW_IRAM1 @0x20000000(128KB,DMA 可达)\n' x = BAR_X - for label, size, color in RAM_CATEGORIES: + for label, size, color in RAM1_CATEGORIES: w = size * SCALE if w < 1: continue - inside = label.replace("\n", " ") if w > 30 else "" - outside = "" if w > 30 else label.replace("\n", " ") - svg += _draw_bar_segment(x, BAR_Y, w, BAR_H, color, inside, outside) + inside = label if w > _text_width(label) + 10 else "" + svg += _draw_bar_segment(x, y1, w, BAR_H, color, inside, "") x += w - - # Legend - lx, ly = 60, 130 - for label, size, color in RAM_CATEGORIES: - pct = size / SRAM_TOTAL * 100 - kb = size / 1024 - display = label.replace("\n", " ") - svg += f' \n' - svg += f' ' - svg += f'{display}: {kb:.1f}KB ({pct:.1f}%)\n' - ly += 16 - if ly > H - 20: - lx += 260 - ly = 130 - - # Summary text - svg += f'' - svg += f'已用: {SRAM_USED/1024:.1f}KB ({SRAM_USED/SRAM_TOTAL*100:.1f}%)' - svg += f' 空闲: {SRAM_FREE/1024:.1f}KB ({SRAM_FREE/SRAM_TOTAL*100:.1f}%)' + svg += f'' + svg += f'已用: {SRAM1_USED}B ({SRAM1_USED/SRAM1_TOTAL*100:.1f}%)' + svg += f' 空闲: {SRAM1_FREE}B ({SRAM1_FREE/SRAM1_TOTAL*100:.1f}%)' svg += f' 总量: 128KB\n' + # Region 2: CCM + y2 = y1 + BAR_H + 50 + svg += f'CCM RW_CCM @0x10000000(64KB,仅 CPU 可达,DMA 不可达)\n' + x = BAR_X + for label, size, color in RAM2_CATEGORIES: + w = size * SCALE + if w < 1: + continue + inside = label if w > _text_width(label) + 10 else "" + svg += _draw_bar_segment(x, y2, w, BAR_H, color, inside, "") + x += w + svg += f'' + svg += f'已用: {CCM_USED}B ({CCM_USED/CCM_TOTAL*100:.1f}%)' + svg += f' 空闲: {CCM_FREE}B ({CCM_FREE/CCM_TOTAL*100:.1f}%)' + svg += f' 总量: 64KB\n' + + # Legend(主 SRAM 两列 + CCM 两行) + ly = y2 + BAR_H + 40 + lx = 60 + half = (len(RAM1_CATEGORIES) + 1) // 2 + for i, (label, size, color) in enumerate(RAM1_CATEGORIES): + pct = size / SRAM1_TOTAL * 100 + kb = size / 1024 + if i >= half: + lx2 = 420 + else: + lx2 = 60 + yy = 226 + (i % half) * 16 + svg += f' \n' + svg += f' ' + svg += f'主SRAM {label}: {kb:.1f}KB ({pct:.1f}%)\n' + for i, (label, size, color) in enumerate(RAM2_CATEGORIES): + pct = size / CCM_TOTAL * 100 + kb = size / 1024 + yy = 322 + i * 16 + svg += f' \n' + svg += f' ' + svg += f'CCM {label}: {kb:.1f}KB ({pct:.1f}%)\n' + svg += svg_footer() return svg @@ -197,7 +239,7 @@ def gen_flash_svg(): SCALE = (W - 80) / FLASH_TOTAL svg = svg_header(W, H) - svg += f'Flash (1MB) 使用布局\n' + svg += f'Flash (1MB) 使用布局 — 2026-09-21 @build\n' x = BAR_X for label, size, color in FLASH_CATEGORIES: @@ -234,57 +276,63 @@ def gen_flash_svg(): def gen_taskstack_svg(): - """任务栈预算.svg — horizontal bars for each task's stack allocation.""" - W, H = 740, 340 - BAR_X = 180 + """任务栈预算.svg — 每任务:分配栈条 + 最坏占用叠加条 + 实测余量/判定。""" + W, H = 880, 440 + BAR_X = 190 MAX_STACK = 16384 SCALE = (W - BAR_X - 40) / MAX_STACK - ROW_H = 30 - Y_START = 60 + Y_START = 64 + ROW_PITCH = 40 + BAR_H = 16 svg = svg_header(W, H) - svg += f'FreeRTOS 任务栈分配 (48KB 堆池)\n' - - # Header - svg += f'分配栈大小 (Bytes)\n' + svg += f'FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM)\n' + svg += f'数据: 2026-09-21 @build + FTP 128KB 实测(data/stack_report_20260921.md)\n' + svg += f'浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定\n' y = Y_START - for name, stack, prio, desc in TASK_STACKS: - w = stack * SCALE - color = "#2196F3" if "Normal" in prio else "#FF9800" + for name, cfg, prio, worst, peak, margin, pct, verdict, desc in TASK_STACKS: + w = cfg * SCALE + wc = worst * SCALE + dark = "#2196F3" if prio == "Normal" else "#FF9800" + light = "#BBDEFB" if prio == "Normal" else "#FFE0B2" + vc = "#2E7D32" if verdict == "PASS" else "#C62828" - # Task name label - svg += f' {name}\n' + # 任务名(左侧) + svg += f' {name}\n' + # 分配栈条(浅色)+ 最坏占用叠加条(深色) + svg += f' \n' + svg += f' \n' + # 数据行 + svg += f' ' + svg += f'配置 {cfg}B | 实测峰值 {peak}B | 最坏 {worst}B | 余量 {margin}B ({pct}%) ' + svg += f'{verdict}\n' + y += ROW_PITCH - # Bar - svg += f' \n' - - # Size inside bar - if w > 60: - svg += f' {stack}B ({stack/1024:.1f}KB)\n' - else: - svg += f' {stack}B\n' - - y += ROW_H + 4 - - # FreeRTOS heap summary - total_stacks = sum(s for _, s, _, _ in TASK_STACKS) + 512 + 1024 # app + idle + timer + # 内核任务(静态小栈,未取句柄实测) y += 4 - svg += f'' - svg += f'堆总量: 49,152B (48KB) ' - svg += f'任务栈合计: ~{total_stacks}B ({total_stacks/1024:.1f}KB) ' - svg += f'空闲: ~{HEAP_FREE}B ({HEAP_FREE/1024:.1f}KB)\n' + for name, stack in KERNEL_STACKS: + w = max(stack * SCALE, 2) + svg += f' {name}\n' + svg += f' \n' + svg += f' {stack}B(未实测)\n' + y += 22 - # Color legend - y += 18 + # 堆汇总(实测值) + y += 8 + svg += f'' + svg += f'堆总量: {HEAP_TOTAL}B (48KB, RW_CCM) 任务栈合计: {TOTAL_STACKS}B ({TOTAL_STACKS/1024:.1f}KB) + 内核栈 {512+1024}B\n' + y += 16 + svg += f'' + svg += f'实测: free={HEAP_FREE}B / min_ever={HEAP_MIN_EVER}B(2026-09-21,含 FTP 负载) 判定: 6/6 PASS(余量 ≥ max(1024B, 配置×30%))\n' + y += 24 + # 颜色图例 svg += f' \n' svg += f' Normal 优先级\n' svg += f' \n' svg += f' BelowNormal 优先级\n' + svg += f' \n' + svg += f' 内核任务栈 (idle/timer)\n' svg += svg_footer() return svg