perf(gen): 结构体/CTypedef 查名加索引,热点线性查名补首字符预筛
StructGenMixin.find_struct:索引可信且查询名非空时,未命中即判定确无同名条目,跳过 O(n) 精确扫描(此前索引只短路命中、未命中仍全表扫描,实测 527 万次逐条 strcmp 即源于此)。 TypeGenCType:新增 CTypedef 名索引(开放寻址、槽存 index+1、Built==len 才可信、不可信或未命中回退线性扫描、clear_ctypedefs 同步复位),消除 lookup_ctypedef 约 445 万次 strcmp。 补首字符预筛:StubMergerIR._FindSha1ByModName、CallGenBase._ensure_method_declare、VarGenMixin.find_var、CallGenLeafKit.find_func_entry_in_table(_owned)(首字符不等即判不等,匹配结果与顺序不变)。
This commit is contained in:
1 parent
e8db102b9e
commit
cb430bf00a
7 files changed
+155
-11
No files matched your search
@@ -364,7 +364,9 @@ def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
# 第一遍:精确匹配
|
||||
for i in range(count):
|
||||
idx: sizet = sizet(i) * 64
|
||||
if string.strcmp(mod_arr + idx, mod_name) == 0:
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||||
# (热点:本函数全表逐条 strcmp 查名)。
|
||||
if mod_arr[idx] == mod_name[0] and string.strcmp(mod_arr + idx, mod_name) == 0:
|
||||
sidx: sizet = sizet(i) * 17
|
||||
return sha1_arr + sidx
|
||||
# 第二遍:包名回退("ast" → "ast.__init__")
|
||||
@@ -374,7 +376,7 @@ def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name)
|
||||
for i in range(count):
|
||||
idx2: sizet = sizet(i) * 64
|
||||
if string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||||
if mod_arr[idx2] == init_buf[0] and string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||||
sidx2: sizet = sizet(i) * 17
|
||||
stdlib.free(init_buf)
|
||||
return sha1_arr + sidx2
|
||||
|
||||
@@ -645,7 +645,10 @@ class CallGenBase:
|
||||
stdio.printf("[CALLGEN] 链表异常: module funcs(call_name=%s,遍历超限,终止)\n", call_name)
|
||||
stdlib.exit(1)
|
||||
if existing.Name is not None:
|
||||
if string.strcmp(existing.Name, call_name) == 0:
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||||
# (热点:本函数对模块函数链逐节点命名比对)。
|
||||
if existing.Name[0] == call_name[0] \
|
||||
and string.strcmp(existing.Name, call_name) == 0:
|
||||
# 已存在:仅当是 declare 且参数数量不足时追加缺失参数
|
||||
if existing.IsDeclared == 1:
|
||||
# 变长函数(*args,IsVarArg=1)不追加参数:多余实参由
|
||||
|
||||
@@ -1498,7 +1498,8 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
entry_addr: uint64 = uint64(funcs) + i * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||||
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
return None
|
||||
|
||||
@@ -1524,7 +1525,9 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry is None or entry.Name is None:
|
||||
continue
|
||||
if string.strcmp(entry.Name, name) != 0:
|
||||
# 快速路径:strcmp 判等要求首字符相等,首字符不同者跳过 strcmp
|
||||
# (热点:本函数对函数表逐条按裸名 + 定义模块 SHA1 比对)。
|
||||
if entry.Name[0] != name[0] or string.strcmp(entry.Name, name) != 0:
|
||||
continue
|
||||
if owner_sha1 is None:
|
||||
return entry
|
||||
|
||||
@@ -791,11 +791,22 @@ class StructGenMixin:
|
||||
fi: int = self._struct_name_idx_find(name)
|
||||
if fi >= 0:
|
||||
return self._get_struct_entry(fi)
|
||||
for i in range(self.StructCount):
|
||||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||||
if entry is not None and entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
# 名索引可信(Built==Count | 索引存在 | 查询名非空)时,索引未命中即
|
||||
# "确无同名条目":条目在注册时即命名并同步入索引,之后名至多被中和为 ""
|
||||
# (ClassGenDef/ClassGenEnum 置 Name[0]=0),故任何非空查询名的命中项必在
|
||||
# 索引探测链上 ⇒ 可跳过下方 O(n) 精确扫描(热点:本扫描占 find_struct 的
|
||||
# 全部 strcmp)。索引不可信 / 无索引 / 空名查询时仍回退原线性扫描
|
||||
# (正确性保证,非兜底)。
|
||||
name_idx_trusted: int = 0
|
||||
if self.StructNameIdx is not None and self.StructIdxCap > 0 \
|
||||
and self.StructIdxBuilt == self.StructCount:
|
||||
name_idx_trusted = 1
|
||||
if name_idx_trusted == 0 or name[0] == '\0':
|
||||
for i in range(self.StructCount):
|
||||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||||
if entry is not None and entry.Name is not None:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
return entry
|
||||
# 模块限定名(module.Class):模块可解析时按模块归属精确匹配,
|
||||
# 防止裸名回退抓跨模块同名类。模块未命中时若裸名类唯一(无冲突)
|
||||
# 仍回退,避免误杀未登记模块的既有解析。
|
||||
|
||||
@@ -79,6 +79,13 @@ class TypeGenBase:
|
||||
CTypedefNames: list[str] | t.CPtr
|
||||
CTypedefTypeStrs: list[str] | t.CPtr
|
||||
CTypedefFound: int
|
||||
# CTypedef 名 → 槽下标 索引(开放寻址 | 线性探测;槽存 index+1,0=空槽)。
|
||||
# 与 CTypedefNames 同池分配、同 clear_ctypedefs 复位;CTypedefNames 只追加
|
||||
# 不重排(同名注册原地更新类型串)⇒ 存槽下标稳定;Built == len(CTypedefNames)
|
||||
# 才可信,不可信/未命中一律回退线性扫描(正确性保证)。
|
||||
CTypedefNameIdx: sizet | t.CPtr
|
||||
CTypedefNameIdxCap: int
|
||||
CTypedefNameIdxBuilt: int
|
||||
CTypedefResolveDepth: int
|
||||
CTypedefVisiting: list[str] | t.CPtr
|
||||
# builtins 源扫描标记:注解解析"最后匹配"兜底(_lookup_builtins_typedef)
|
||||
@@ -151,6 +158,9 @@ class TypeGenBase:
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
self.CTypedefFound = 0
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
self.CTypedefResolveDepth = 0
|
||||
self.CTypedefVisiting = None
|
||||
self.BuiltinsTypedefScanned = 0
|
||||
|
||||
@@ -16,6 +16,33 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
|
||||
# ============================================================
|
||||
# CTypedef 名索引(名 → 槽下标,开放寻址 | 线性探测)
|
||||
#
|
||||
# 槽数 = 4096(2 的幂;负载 < 0.5 上限 2048 条,超限标记不可信回退线性扫描)。
|
||||
# 槽存槽下标 + 1(0=空槽)。CTypedefNames 只追加不重排(同名注册原地更新类型串)
|
||||
# ⇒ 槽下标稳定;Built == len(CTypedefNames) 才可信。
|
||||
# ============================================================
|
||||
CTYPEDEF_IDX_CAP: t.CDefine = 4096
|
||||
# 索引哈希常量(32 位 FNV-1a,与 StructGenMixin 范式一致)
|
||||
CTYPEDEF_IDX_FNV_OFFSET: t.CDefine = 2166136261
|
||||
CTYPEDEF_IDX_FNV_PRIME: t.CDefine = 16777619
|
||||
CTYPEDEF_IDX_FNV_MASK: t.CDefine = 4294967295
|
||||
|
||||
|
||||
def _ctypedef_idx_hash(name: str) -> uint64:
|
||||
"""CTypedef 名 → 64 位哈希(32 位 FNV-1a,逐字节到 NUL 结束)"""
|
||||
h: uint64 = uint64(CTYPEDEF_IDX_FNV_OFFSET)
|
||||
if name is None:
|
||||
return h
|
||||
i: sizet = 0
|
||||
while name[i] != '\0':
|
||||
h = (h ^ uint64(int(name[i]))) * uint64(CTYPEDEF_IDX_FNV_PRIME)
|
||||
h = h & uint64(CTYPEDEF_IDX_FNV_MASK)
|
||||
i += 1
|
||||
return h
|
||||
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCType - TypeGenMixin 拆分(阶段 D):CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)
|
||||
#
|
||||
@@ -27,6 +54,74 @@ import lib.core.Gen.Type.TypeSpec as TSpec
|
||||
class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
"""CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)"""
|
||||
|
||||
# ============================================================
|
||||
# CTypedef 名索引(开放寻址;槽存 index+1,0=空槽)
|
||||
# ============================================================
|
||||
def _ctypedef_idx_slot(self, si: sizet) -> sizet | t.CPtr:
|
||||
"""取索引第 si 个槽(8 字节,存槽下标+1;0=空槽)"""
|
||||
return (sizet | t.CPtr)(t.CVoid(uint64(self.CTypedefNameIdx) + uint64(si) * 8, t.CPtr))
|
||||
|
||||
def _ctypedef_idx_init(self, pool: rowptr[memhub.MemBuddy]) -> None:
|
||||
"""创建/清零名索引(与 CTypedefNames 同池);失败则标记不可信"""
|
||||
idx: sizet | t.CPtr = pool.alloc(sizet(CTYPEDEF_IDX_CAP) * 8)
|
||||
if idx is None:
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
return
|
||||
string.memset(idx, 0, sizet(CTYPEDEF_IDX_CAP) * 8)
|
||||
self.CTypedefNameIdx = idx
|
||||
self.CTypedefNameIdxCap = CTYPEDEF_IDX_CAP
|
||||
self.CTypedefNameIdxBuilt = 0
|
||||
|
||||
def _ctypedef_idx_find(self, name: str) -> int:
|
||||
"""在名索引中探测 name,返回命中槽下标(>=0);未命中/不可用返回 -1"""
|
||||
if self.CTypedefNameIdx is None or self.CTypedefNameIdxCap <= 0 or name is None:
|
||||
return -1
|
||||
if self.CTypedefNameIdxBuilt != int(len(self.CTypedefNames)):
|
||||
return -1
|
||||
h: uint64 = _ctypedef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CTypedefNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CTypedefNameIdxCap:
|
||||
slot: sizet | t.CPtr = self._ctypedef_idx_slot(si)
|
||||
sv: sizet = slot[0]
|
||||
if sv == 0:
|
||||
return -1
|
||||
se: int = int(sv) - 1
|
||||
nm: str = self.CTypedefNames.get(sizet(se))
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
return se
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
def _ctypedef_idx_insert(self, slot_index: int, name: str) -> int:
|
||||
"""把 (name → slot_index) 记入索引;0=成功 / 1=失败"""
|
||||
if self.CTypedefNameIdx is None or self.CTypedefNameIdxCap <= 0 or name is None:
|
||||
return 1
|
||||
h: uint64 = _ctypedef_idx_hash(name)
|
||||
mask: sizet = sizet(self.CTypedefNameIdxCap - 1)
|
||||
si: sizet = sizet(h) & mask
|
||||
i: int = 0
|
||||
while i < self.CTypedefNameIdxCap:
|
||||
slot: sizet | t.CPtr = self._ctypedef_idx_slot(si)
|
||||
if slot[0] == 0:
|
||||
slot[0] = sizet(slot_index + 1)
|
||||
return 0
|
||||
si = (si + 1) & mask
|
||||
i += 1
|
||||
return 1
|
||||
|
||||
def _ctypedef_idx_sync_append(self, name: str) -> None:
|
||||
"""CTypedefNames.append 后同步索引(槽下标 = len-1);不可信则保持不可信"""
|
||||
n: int = int(len(self.CTypedefNames))
|
||||
if self.CTypedefNameIdxBuilt == n - 1 and self._ctypedef_idx_insert(n - 1, name) == 0:
|
||||
self.CTypedefNameIdxBuilt = n
|
||||
else:
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
|
||||
def register_ctypedef(self, pool: rowptr[memhub.MemBuddy],
|
||||
name: str, type_str: str) -> None:
|
||||
"""注册 CTypedef 到本地表
|
||||
@@ -60,6 +155,8 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
if self.CTypedefNames is None:
|
||||
self.CTypedefNames = list[str](pool, 64)
|
||||
self.CTypedefTypeStrs = list[str](pool, 64)
|
||||
# 名索引随表创建(同池;分配失败则标记不可信,查找回退线性扫描)
|
||||
self._ctypedef_idx_init(pool)
|
||||
# 去重:若已存在同名 CTypedef,更新其类型字符串
|
||||
if self.CTypedefNames is not None:
|
||||
exist_n: sizet = len(self.CTypedefNames)
|
||||
@@ -72,6 +169,8 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
self.CTypedefNames.append(name_copy)
|
||||
self.CTypedefTypeStrs.append(type_copy)
|
||||
# 追加后同步名索引(槽下标 = 追加前 len = 新 len-1)
|
||||
self._ctypedef_idx_sync_append(name_copy)
|
||||
def store_builtins_diag(self, which: int, text: str) -> str:
|
||||
"""把 builtins 诊断串复制进自有缓冲并返回该缓冲(which: 0=Name, 1=Result)
|
||||
|
||||
@@ -120,6 +219,17 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
return None
|
||||
n: sizet = len(self.CTypedefNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选槽下标。CTypedef 表
|
||||
# 注册时按名去重(register_ctypedef 已存在则原地更新类型串)⇒ 名唯一,
|
||||
# 索引未命中 ⇒ 确实不存在,直接返回;索引不可用/不可信 → 回退原全表扫描。
|
||||
if self.CTypedefNameIdxBuilt == int(n) \
|
||||
and self.CTypedefNameIdx is not None and self.CTypedefNameIdxCap > 0:
|
||||
ti: int = self._ctypedef_idx_find(name)
|
||||
if ti < 0:
|
||||
return None
|
||||
ts_hit: str = self.CTypedefTypeStrs.get(sizet(ti))
|
||||
self.CTypedefFound = 1
|
||||
return ts_hit
|
||||
for i in range(n):
|
||||
nm: str = self.CTypedefNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
@@ -284,6 +394,10 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
"""清空 CTypedef 表(模块切换时调用)"""
|
||||
self.CTypedefNames = None
|
||||
self.CTypedefTypeStrs = None
|
||||
# 名索引随表复位(下次 register 重建);不同步会使 Built 与空表错配
|
||||
self.CTypedefNameIdx = None
|
||||
self.CTypedefNameIdxCap = 0
|
||||
self.CTypedefNameIdxBuilt = -1
|
||||
self.CTypedefResolveDepth = 0
|
||||
self.CTypedefVisiting = None
|
||||
# builtins 源扫描标记随表清空复位:每文件最多读一次 includes/builtins.vp
|
||||
|
||||
@@ -75,7 +75,8 @@ class VarGenMixin:
|
||||
entry_addr: uint64 = uint64(vars_ptr) + i * entry_size
|
||||
entry: GenTypes.VarEntry | t.CPtr = (GenTypes.VarEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
if entry.Name is not None and entry.Used != 0:
|
||||
if string.strcmp(entry.Name, name) == 0:
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp
|
||||
if entry.Name[0] == name[0] and string.strcmp(entry.Name, name) == 0:
|
||||
return entry.Alloca
|
||||
return None
|
||||
|
||||
|
||||
Reference in new issue
Block a user