perf(diag): OOM 二分定位诊断 + 主池提升 1.5GB

BuildPipeline/Phase2/StmtGenMixin/HandlesAnnAssign 增加 [MEM] 限频打印
(parse/translate 前后、Phase A 前后、stmt 行级、AnnAssign 入口),
定位 NewAstTest 翻译内存暴涨起点;主池 1.5GB(2^30+2^29 二进制分解),
给单文件峰值与 Phase A 高并发翻译留足余量。
This commit is contained in:
TermiNexus committed 2026-08-15 00:15:59 +08:00
1 parent f9878e5a63
commit 0a0e6d3bab
5 files changed
+38 -5

No files matched your search

+6
View File
@@ -116,6 +116,8 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
ast._lexer_init(lx, src_buf, mb)
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
# OOM 诊断:parse 后主池用量(区分 parse/translate/dump 阶段)
stdio.printf("[MEM] TFGT parse后 used=%zu chk_depth=%zu\n", mb.used_bytes(), mb.chk_depth)
# parse 完成后 AST 树已独立,释放源代码缓冲区(避免 1MB/文件泄漏)
stdlib.free(src_buf)
if tree is None:
@@ -214,7 +216,11 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
# 0xffffffffffffffff 崩溃),docstring 提取与翻译状态无关,提前安全。
if gen is not None:
gen.extract_module_docstrings(tree, sha1_val)
# OOM 诊断:translate 前主池用量
stdio.printf("[MEM] TFGT translate前 used=%zu chk_depth=%zu\n", mb.used_bytes(), mb.chk_depth)
ret: int = tr.translate(tree)
# OOM 诊断:translate 后主池用量(对比 translate 前 → translate 内部增长量)
stdio.printf("[MEM] TFGT translate后 used=%zu chk_depth=%zu\n", mb.used_bytes(), mb.chk_depth)
if ret != 0:
fb_tf: str = VLogger.fmt_buf()
if fb_tf is not None:
+12
View File
@@ -5,6 +5,7 @@ import llvmlite
import memhub
import string
import stdlib
import stdio
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HT
@@ -78,6 +79,9 @@ class StmtGenMixin:
EnumTable: HandlesEnum.EnumEntry | t.CPtr
EnumCount: int
# --- OOM 语句级诊断计数(translate_stmt 限频打印 used) ---
DiagStmtCount: int
# ============================================================
# 簇 A:语句分派/流程语句(迁移自 HandlesBody.vp)
# ============================================================
@@ -87,6 +91,14 @@ class StmtGenMixin:
"""翻译单条语句,返回新增的变量数"""
if node is None:
return 0
# OOM 语句级诊断:每 10 语句打印主池用量+行号——定位单文件翻译
# (NewAstTest main.vp)从 6.4MB 暴涨到 1.6GB 发生在哪一行
self.DiagStmtCount += 1
if (self.DiagStmtCount % 10) == 1:
pool_diag: memhub.MemBuddy | t.CPtr = CompilerFactory.get_pool()
stdio.printf("[MEM] stmt %d line %d used=%zu chk_depth=%zu\n",
self.DiagStmtCount, node.lineno,
pool_diag.used_bytes(), pool_diag.chk_depth)
k: int = node.kind()
if k == ast.ASTKind.Expr:
+3
View File
@@ -420,6 +420,9 @@ class AnnAssignHandle(HandlesBase.Mixin):
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa is None:
return 0
# OOM 诊断:AnnAssign 入口 used(定位 Constant 构造语句的注解/值翻译段)
stdio.printf("[MEM] AnnAssign.Handle line %d used=%zu chk=%zu\n",
node.lineno, self.Trans.Pool.used_bytes(), self.Trans.Pool.chk_depth)
target: ast.AST | t.CPtr = aa.target
if target is None or target.kind() != ast.ASTKind.Name:
+10
View File
@@ -552,6 +552,10 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(entries)
return 1
string.memset(done_flags, 0, file_count)
# 二分诊断:Phase A 开始前主池用量——若已接近 1GB 说明
# pre-inc/pre 阶段的 reset_to(mark2) 未回收(记录栈/realloc 失效);
# 若用量低则泄漏发生在 Phase A 自身。
stdio.printf("[MEM] Phase A 前主池 used=%zu\n", mb.used_bytes())
PHASE_A_MAX_PASSES: t.CInt = 32
for pass_a in range(PHASE_A_MAX_PASSES):
completed_this_pass: int = 0
@@ -560,6 +564,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
continue
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
# OOM 二分诊断:翻译前 used —— 若逐文件递增 → reset_to(mark2) 未回收;
# 若单文件翻译中暴涨 → 单文件瞬时峰值/泄漏(定位 Phase A OOM)
stdio.printf("[MEM] PhaseA 翻译前 i=%d/%d used=%zu\n", i, file_count, mb.used_bytes())
if ent is None or ent.Path is None:
done_flags[i] = 1
completed_this_pass += 1
@@ -648,6 +655,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# OOM 清理:stub/text/deps 已写盘,回收本文件翻译瞬时数据
# (AST/tokens/lexer/IR/Handler);app_deps_buf 已深拷贝依赖,不受影响
mb.reset_to(mark2)
# OOM 二分诊断:reset 后 used —— 应回落到 mark2 水位(3MB 级),
# 若仍高 → reset 失效(记录栈缺失/coalesce 未归还)
stdio.printf("[MEM] PhaseA 翻译后 reset i=%d/%d used=%zu\n", i, file_count, mb.used_bytes())
# 收敛检查:所有文件完成则结束
all_done: int = 1
for i_ck in range(file_count):
+7 -5
View File
@@ -49,15 +49,17 @@ import viperlib
import hashlib
# 内存大小: fl_bytes=264 (33*8), POOL_SIZE-fl_bytes 必须是 2 的幂以避免浪费
# 1073742088 - 264 = 1073741824 (1024MB usable = 2^30)
# 注意: POOL_SIZE 必须是 2^N+264,否则 _largest_pow2_le 会取低一级 2 的幂
# 内存大小: fl_bytes=264 (33*8)。
# 主池 1.5GB(1.5×2^30 + 264 = 1610613000):memhub 二进制分解为 2^30+2^29 两块。
# 曾试 2GB(2^31+264):当前机器物理内存可用不足 1GB(已提交 76.6GB/81.3GB),
# 主池 2GB + perm_pool 512MB = 2.5GB 提交导致 malloc 失败 → TPV 启动即退出。
# 1.5GB + 512MB = 2GB 整提交,留 2.7GB 提交余量,稳妥且比 1.2GB 多 0.3GB。
# Phase1 翻译 87 个 includes 文件 + Phase2 翻译 30 个测试文件,512MB 不足导致 Phase2 崩溃
# 2026-08-13: NewAstTest 依赖 ast 模块(98 includes),Phase2 的 Phase A-pre-inc/Phase A
# 无 mark/reset 回收,98 个 includes 的 AST/IR 全量累积 pool 超 1GB → 曾增大到 2GB。
# → 已在 Phase2 对齐 Phase1 的 mark1/reset_to 清理机制(每文件翻译后回收瞬时数据),
# 峰值回落至单文件水平,恢复 1GB(1073742088 - 264 = 1073741824 = 2^30)
POOL_SIZE: t.CDefine = 1073742088
# 峰值回落至单文件水平;1.5GB 主池给单文件峰值与 Phase A 高并发翻译留足余量。
POOL_SIZE: t.CDefine = 1610613000
# 永久内存池大小:2^29 + 264 = 512MB usable(存跨 mark 持久数据:泛型模板
# 表/节点、struct/union/REnum 类型树、枚举 BaseTy、spec 缓存等)。
# 与主 pool 独立(MemBuddy 第二实例),永不 reset_to,不占主 pool 配额。