perf(memhub): detection 采样探测,O(n²) 降为 O(n²/256)

每次 alloc 全表扫描(分配重叠 + _det_probe)是 O(n) ,2M 次 alloc = O(n²),detection 模式过慢。

改为每 MEMBUDDY_DET_PROBE_PERIOD(256) 次 alloc 采样扫描一次;记录追加保持 O(1)。损坏是持久性的,不依赖即时扫描,检测能力不损失。
This commit is contained in:
TermiNexus committed 2026-08-25 16:21:34 +08:00
1 parent b777d7c925
commit 7c7629852a
1 file changed
+26 -15
+26 -15
View File
@@ -47,6 +47,11 @@ MEMBUDDY_FILL_PATTERN: t.CDefine = 0xCD
MEMBUDDY_DET_MARKER: t.CDefine = 0xCDCD
# 检测记录区默认大小(32MB,每条记录 {ptr u64, size u64} = 16B)
MEMBUDDY_DET_RECORD_SIZE: t.CDefine = 33554432
# 采样周期(2 的幂):每 N 次 alloc 做一次全表扫描(分配重叠 + 探测)。
# 记录追加本身 O(1) 不受影响;损坏是持久性的,不依赖即时扫描,采样
# 不损失检测能力——2M 次 alloc 若每次全表 O(n) 扫描 = O(n²) 太慢
# (用户反馈 detection 模式过慢),采样把扫描次数降为 1/N。
MEMBUDDY_DET_PROBE_PERIOD: t.CDefine = 256
def _canary_pattern() -> t.CUInt64T:
@@ -674,20 +679,25 @@ class MemBuddy(MemManager):
m_t_d: t.CUInt16T | t.CPtr = (t.CUInt16T | t.CPtr)(t.CVoid(tail_d, t.CPtr))
m_t_d[0] = t.CUInt16T(MEMBUDDY_DET_MARKER)
if self._det_records is not None:
# 分配重叠即时检测:新块地址是否已在 active 记录(同一块重复
# 分配实锤——SlotsBugTest 7B buf 与 72B Token 同 ptr、cargs
# 只写 0/40 根因)。重叠 = MemBuddy free list 损坏(active 块
# 混入 free list),在第一次重叠处拦截并打印两个 size。
ff_d: t.CUInt64T = t.CUInt64T(1) << 63
dup_i: t.CSizeT = 0
while dup_i < self._det_count:
drp: t.CUInt64T = self._det_records[dup_i * 2]
drs: t.CUInt64T = self._det_records[dup_i * 2 + 1]
if drp == base_ret_d + 2 and (drs & ff_d) == 0:
stdio.printf("[DET] 分配重叠: 新alloc(size=%llu)与记录[%zu](sz=%llu)同地址 ptr=%llu(同一块重复分配,free list 损坏)\n",
t.CUInt64T(size), dup_i, drs & (ff_d - 1), base_ret_d + 2)
stdlib.exit(1)
dup_i += 1
# 采样:每 MEMBUDDY_DET_PROBE_PERIOD 次 alloc 做一次全表扫描
# (分配重叠 + 探测),其余只追加记录(O(1))。损坏是持久性的,
# 不依赖即时扫描——2M 次 alloc 若每次全表 O(n) = O(n²) 太慢
# (用户反馈 detection 模式过慢),采样把扫描降为 O(n²/PERIOD)。
if (self._det_count & (MEMBUDDY_DET_PROBE_PERIOD - 1)) == 0:
# 分配重叠即时检测:新块地址是否已在 active 记录(同一块重复
# 分配实锤——SlotsBugTest 7B buf 与 72B Token 同 ptr、cargs
# 只写 0/40 根因)。重叠 = MemBuddy free list 损坏(active 块
# 混入 free list),在第一次重叠处拦截并打印两个 size。
ff_d: t.CUInt64T = t.CUInt64T(1) << 63
dup_i: t.CSizeT = 0
while dup_i < self._det_count:
drp: t.CUInt64T = self._det_records[dup_i * 2]
drs: t.CUInt64T = self._det_records[dup_i * 2 + 1]
if drp == base_ret_d + 2 and (drs & ff_d) == 0:
stdio.printf("[DET] 分配重叠: 新alloc(size=%llu)与记录[%zu](sz=%llu)同地址 ptr=%llu(同一块重复分配,free list 损坏)\n",
t.CUInt64T(size), dup_i, drs & (ff_d - 1), base_ret_d + 2)
stdlib.exit(1)
dup_i += 1
if self._det_count >= self._det_cap:
# 记录表满:stdlib.realloc 翻倍扩容(防 is_alive/_det_probe
# 因容量耗尽漏检——SlotsBugTest 编译 includes 超 2M 次 alloc,
@@ -703,7 +713,8 @@ class MemBuddy(MemManager):
self._det_records[self._det_count * 2] = base_ret_d + 2
self._det_records[self._det_count * 2 + 1] = t.CUInt64T(size)
self._det_count += 1
self._det_probe()
if (self._det_count & (MEMBUDDY_DET_PROBE_PERIOD - 1)) == 0:
self._det_probe()
result = t.CVoid(base_ret_d + 2, t.CPtr)
if result is None:
# 分配失败诊断(定位"异常 size/池耗尽导致 None → 调用方解引用段错误")