fix(mlirlitetest): 子池 arena 精确取 2MB 块 + 主池 80MB + arena 失败 fail-fast
现象一(池再次耗尽):alloc size=2097152 needed=2097168 order=17 失败,used=62914560/池容量=67108576。根因:按 2MB 申请,memhub 的 needed=size+HEADER(8)+CANARY(8) 使 2MB+16 放不进 order16(2MB) 块 ⇒ 向上取 order17(4MB),每块浪费一倍;16 个子池 = 64MB 把 64MB 主池吃干。 现象二(随之崩溃):alloc 失败返回 None 后 MemBuddy(None, size) 在 memhub.vp:653 `self.free_lists[i] = 0` 写空指针 → 0xC0000005 av_addr=0x0。 修复:SUB_POOL_SIZE 取 2097136(=2MB-16) 使 needed 恰为 2MB、正好取到 order16 块(不再浪费一倍);POOL_SIZE 64MB→80MB 留余量;新增 _sub_arena 只返回裸指针(可安全跨函数返回,MemBuddy 实例是栈值不可返回其指针)并对 arena 分配失败 fail-fast。
This commit is contained in:
1 parent
4203b4754f
commit
579eb52561
1 file changed
+49
-30
+49
-30
@@ -10,14 +10,20 @@ import viperlib
|
||||
import mlirlite
|
||||
|
||||
|
||||
# 主池大小:只用于给**每个测试切一块子池**(见 main / _sub_pool)。
|
||||
POOL_SIZE: t.CDefine = 67108864
|
||||
# 每个测试的子池大小。子池存在的意义:测试内的 IR 对象与 MLIR 渲染器每函数
|
||||
# **重分配**的 scratch/常量表/别名表(约 35–45KB/函数,见 mlirlite 的
|
||||
# _MlirTablesInit)都落在自己的子池里,互不叠加。若所有测试共用一个池,渲染器
|
||||
# 这套"按函数重分配、不释放"的开销会跨测试累积(此前 15 个测试共用 4MB,
|
||||
# 到第 14 个把池吃干 → "MLIR 渲染: 常量/别名表分配失败")。
|
||||
SUB_POOL_SIZE: t.CDefine = 2097152
|
||||
# 主池大小:只用于给**每个测试切一块子池**(见 main / _sub_arena)。
|
||||
# 给足:SUB_POOL_SIZE 取 2MB 块时每个测试占用 2MB,16 块 ≈ 32MB;即便伙伴分配器
|
||||
# 因 +16 头/canary 向上取整到 4MB 块(16 块 = 64MB)也仍在池内。
|
||||
POOL_SIZE: t.CDefine = 83886080
|
||||
# 每个测试的子池大小 = 2MB − 16(16 = memhub 的 HEADER 8 + CANARY 8)。
|
||||
# 取这个值是为了让 `main_pool.alloc()` 的 `needed = size + 16` 恰好等于 2MB,
|
||||
# 伙伴分配器正好给一个 order16(2MB) 块;若直接传 2MB,needed=2MB+16 会向上取到
|
||||
# order17(4MB) ⇒ 每块浪费一倍,15+ 个测试就把主池吃干(现场:alloc size=2097152
|
||||
# needed=2097168 order=17 失败,used=62914560/池容量=67108576)。
|
||||
# 子池存在的意义:测试内的 IR 对象与 MLIR 渲染器每函数**重分配**的
|
||||
# scratch/常量表/别名表(约 35–45KB/函数,见 mlirlite 的 _MlirTablesInit)都落在
|
||||
# 自己的子池里,互不叠加;若所有测试共用一个池,这套"按函数重分配、不释放"的开销
|
||||
# 会跨测试累积,最终 "MLIR 渲染: 常量/别名表分配失败"。
|
||||
SUB_POOL_SIZE: t.CDefine = 2097136
|
||||
|
||||
|
||||
# 把 buf 中的 MLIR 文本落盘到 Test/MLIRLiteTest/output/<name>,供
|
||||
@@ -1451,6 +1457,23 @@ def test_extractvalue_multi_asm(pool: memhub.MemBuddy | t.CPtr):
|
||||
"extractvalue result not referenced")
|
||||
|
||||
|
||||
def _sub_arena(main_pool: memhub.MemBuddy | t.CPtr) -> rawptr:
|
||||
"""从主池切一块子池 arena(返回**裸指针**,由调用方在自己帧内构造 MemBuddy)
|
||||
|
||||
为什么只返回裸指针、不返回构造好的 MemBuddy*:Viper 中无 __new__ 的类实例是
|
||||
值语义,`MemBuddy(...)` 被降级为栈 alloca;"返回指向本帧局部对象"的指针会
|
||||
悬空(IR 物证:助手函数内 `alloca %MemBuddy` … `ret %MemBuddy*`,随后第一次
|
||||
alloc 读 max_order 即落到复用的栈垃圾 → memhub 报"字段被写穿")。
|
||||
arena 分配失败必须在这里 fail-fast,否则 `MemBuddy(None, size)` 会在
|
||||
`self.free_lists[i] = 0` 处写空指针(现场 0xC0000005 av_addr=0x0)。
|
||||
"""
|
||||
mem: rawptr = main_pool.alloc(SUB_POOL_SIZE)
|
||||
if mem is None:
|
||||
stdio.printf("FAIL: sub pool arena alloc failed (raise POOL_SIZE)\n")
|
||||
stdlib.exit(1)
|
||||
return mem
|
||||
|
||||
|
||||
def main() -> int:
|
||||
testcheck.begin("MLIRLiteTest: mlirlite 库(MLIR llvm 方言文本生成)")
|
||||
|
||||
@@ -1464,58 +1487,54 @@ def main() -> int:
|
||||
stdio.printf("FAIL: memhub.MemBuddy init failed\n")
|
||||
return 1
|
||||
|
||||
# 子池必须在 **main 的帧内** 构造:Viper 中无 __new__ 的类实例是值语义,
|
||||
# `MemBuddy(...)` 被降级为栈 alloca;若把它放进"返回 MemBuddy*"的助手函数,
|
||||
# 返回的就是**指向已销毁栈帧的指针**(IR 物证:_sub_pool 内
|
||||
# `%13 = alloca %MemBuddy` … `ret %MemBuddy* %28`),随后第一次 alloc 读
|
||||
# `max_order` 即落到复用的栈垃圾 → memhub 报
|
||||
# "_split_to_order max_order 非法(字段被写穿)"。故此处在 main 内逐测试构造。
|
||||
sub: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
# 子池必须在 **main 的帧内** 构造:见 _sub_arena 注释(MemBuddy 实例是栈值,
|
||||
# 其指针不能跨函数返回)。每个测试一块,互不叠加。
|
||||
sub: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_type_print(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_value_print(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_build_add(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_build_if_else(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_build_void(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_module_print(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_const_materialize(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_phi_block_args(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_mem_call_cast(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_globals(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_verify_valid(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_struct_global(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_alloca_align_switch_asm(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_vararg_vaarg_cmpxchg(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_named_struct(sub)
|
||||
|
||||
sub = memhub.MemBuddy(pool.alloc(SUB_POOL_SIZE), SUB_POOL_SIZE)
|
||||
sub = memhub.MemBuddy(_sub_arena(pool), SUB_POOL_SIZE)
|
||||
test_extractvalue_multi_asm(sub)
|
||||
|
||||
return testcheck.end()
|
||||
Reference in new issue
Block a user