perf(lookup): 恢复名字索引可信未命中即确无的短路(Ty 索引保持停用)
4ed7f39 因 Ty 索引不等价,把名字索引的未命中短路一并回退了,导致 find_struct(8.25M)/lookup_ctypedef(5.64M) 等又回到全表扫描。
经逐处自证不变量后仅恢复名字键索引:名字或键只在注册时写入一次(中和仅置空名,空名查询显式回退扫描);索引在所有写入路径同步维护,判据 Built==Count 失败即失效回退;探测用 live 键且同键条目沿链按注册顺序排列(无空槽夹层)⇒ 可信未命中即原线性扫描亦无所获,短路逐字节等价。
恢复点:StructGenMixin.find_struct、TypeGenCType.lookup_ctypedef、CallGenLeafKit.find_func_in_table/find_func_entry_global、TypeGenCDef.lookup_cdefine_{constant,double,string}、VpiReader._lookup_vpi_param_annots/_lookup_vpi_ret_annot(后者保留泛型特化归一化兜底)。
find_struct_by_type 的 Ty 索引判定保持停用(事故根因);首字符预筛、Function.NameLen/FUNC_SIZE、includes 均未改动。
This commit is contained in:
1 parent
4ed7f3909a
commit
ce612c8e57
5 files changed
+65
-45
No files matched your search
@@ -687,14 +687,14 @@ def _lookup_vpi_param_annots(src_sha1: str, cls_name: str, method_name: str) ->
|
||||
r: str = None
|
||||
ki: int
|
||||
# 索引快速路径:索引可信(Built==Count)时一次探测返回命中槽下标(= 原线性
|
||||
# 扫描首个同名,首注册优先);未命中一律回退下方原线性扫描(索引只加速命中,
|
||||
# 未命中行为与未加索引前逐字节一致);此前"可信未命中即确无"的语义已回退。
|
||||
# 扫描首个同名,首注册优先);未命中即"确无"(键表只追加、键文本注册后不改写,
|
||||
# 索引随扩容整体重建且覆盖全表)⇒ 无需再线性扫描;索引不可信 → 回退线性扫描。
|
||||
hit_p: int = -1
|
||||
if _g_vpi_param_idx_built == _g_vpi_param_count \
|
||||
and _g_vpi_param_idx is not None and _g_vpi_param_idx_cap > 0:
|
||||
hit_p = _vpi_idx_find(_g_vpi_param_keys, VPI_PARAM_KEY_LEN,
|
||||
_g_vpi_param_idx, _g_vpi_param_idx_cap, key_buf)
|
||||
if hit_p < 0:
|
||||
else:
|
||||
# 回退原线性扫描:strcmp 判等蕴含首字节相等;键首字节 = src_sha1[0],缓存含
|
||||
# 多模块条目,首字节不同者必不相等,直接跳过其 strcmp(仅做否定判定,不改命中)。
|
||||
key_first: int = key_buf[0]
|
||||
@@ -1064,14 +1064,15 @@ def _lookup_vpi_ret_annot(src_sha1: str, cls_name: str, method_name: str) -> str
|
||||
viperlib.snprintf(key_buf, key_len + 1, "%s.%s", src_sha1, method_name)
|
||||
i: int
|
||||
# 索引快速路径:索引可信(Built==Count)时一次探测返回命中槽下标(= 原线性
|
||||
# 扫描首个同名,首注册优先);未命中一律回退下方原线性扫描(索引只加速命中,
|
||||
# 未命中行为与未加索引前逐字节一致);此前"可信未命中即确无"的语义已回退。
|
||||
# 扫描首个同名,首注册优先);未命中即"确无"精确键(键表只追加、键文本注册后
|
||||
# 不改写,索引随扩容整体重建且覆盖全表)⇒ 跳过精确线性扫描(下方泛型特化归一化
|
||||
# 匹配兜底仍保留,其键形态不同、不依赖精确键命中);索引不可信 → 回退线性扫描。
|
||||
hit_r: int = -1
|
||||
if _g_vpi_ret_idx_built == _g_vpi_ret_count \
|
||||
and _g_vpi_ret_idx is not None and _g_vpi_ret_idx_cap > 0:
|
||||
hit_r = _vpi_idx_find(_g_vpi_ret_keys, VPI_KEY_LEN,
|
||||
_g_vpi_ret_idx, _g_vpi_ret_idx_cap, key_buf)
|
||||
if hit_r < 0:
|
||||
else:
|
||||
# 回退原线性扫描:strcmp 判等蕴含首字节相等(键首字节 = src_sha1[0]),跳过首字节不同者。
|
||||
key_first: int = key_buf[0]
|
||||
for i in range(_g_vpi_ret_count):
|
||||
|
||||
@@ -1051,8 +1051,11 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
t.CVoid(uint64(self.GlobalFuncs) + fi_t * entry_size, t.CPtr))
|
||||
if fe_t is not None:
|
||||
return fe_t.Func
|
||||
# 索引未命中一律回退下方原线性扫描(索引只加速命中,未命中行为与未加
|
||||
# 索引前逐字节一致);此前"可信未命中即 return None"的语义已回退。
|
||||
# 索引可信(Built==GlobalFuncCount | 查询名非空)⇒ 未命中即"确无同名条目":
|
||||
# 全局表只经 _register_global_func 追加(每次追加即同步索引,失败则置
|
||||
# Built=-1),名注册后不再改写 ⇒ owner_sha1 为 None 时原线性扫描等价于
|
||||
# "首个同名条目的 Func",未命中必为 None。索引不可信时回退下方线性扫描。
|
||||
return None
|
||||
# 单遍扫描(合并原 owner 优先遍 + 通用遍,语义完全一致但省一半遍历):
|
||||
# 扫描中同时记录"首个同裸名条目"作通用兜底;一旦发现本模块条目
|
||||
# (mangled 名以 "{owner_sha1}." 开头,16 位前缀 + '.')立即返回。
|
||||
@@ -1273,8 +1276,9 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
return None
|
||||
entry_size: sizet = GenTypes.FuncEntry.__sizeof__()
|
||||
# 名索引快速路径:可信(Built==Count)时一次探测返回首个同名条目
|
||||
# (= 原线性扫描首个命中);未命中一律回退下方原线性扫描(索引只加速命中,
|
||||
# 未命中行为与未加索引前逐字节一致);此前"可信未命中即 return None"已回退。
|
||||
# (= 原线性扫描首个命中);可信且查询名非空时未命中即"确无同名条目"
|
||||
# (全局表只经 _register_global_func 追加并同步索引,名注册后不再改写),
|
||||
# 直接返回 None;索引不可信 → 回退下方原线性扫描。
|
||||
if self.GlobalFuncNameIdxBuilt == self.GlobalFuncCount \
|
||||
and self.GlobalFuncNameIdx is not None and self.GlobalFuncNameIdxCap > 0:
|
||||
gi: int = _gfn_idx_find(self.GlobalFuncs, self.GlobalFuncNameIdx,
|
||||
@@ -1283,6 +1287,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
entry_g: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(
|
||||
t.CVoid(uint64(self.GlobalFuncs) + gi * entry_size, t.CPtr))
|
||||
return entry_g
|
||||
return None
|
||||
for i in range(self.GlobalFuncCount):
|
||||
entry_addr: uint64 = uint64(self.GlobalFuncs) + i * entry_size
|
||||
entry: GenTypes.FuncEntry | t.CPtr = (GenTypes.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
|
||||
|
||||
@@ -784,18 +784,25 @@ class StructGenMixin:
|
||||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT")
|
||||
stdlib.exit(1)
|
||||
# 名索引快速路径:命中即首注册下标(语义 = 原精确匹配扫描首个命中)。
|
||||
# 未命中一律回退下方原精确匹配扫描(索引只加速命中,未命中行为与未加索引
|
||||
# 前逐字节一致);精确匹配确无时继续走模块限定名/裸名回退逻辑(不提前
|
||||
# return None)。此前"索引可信且查询名非空 ⇒ 未命中即确无、跳过 O(n) 扫描"
|
||||
# 的语义已回退(一旦判据有未覆盖情形就会把"找得到"变成"找不到")。
|
||||
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==StructCount | 索引存在 | 查询名非空)时,索引未命中即
|
||||
# "确无同名条目":条目在注册时即命名并同步入索引,之后名至多被中和为 ""
|
||||
# (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):模块可解析时按模块归属精确匹配,
|
||||
# 防止裸名回退抓跨模块同名类。模块未命中时若裸名类唯一(无冲突)
|
||||
# 仍回退,避免误杀未登记模块的既有解析。
|
||||
|
||||
@@ -339,17 +339,19 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return 0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个
|
||||
# 命中);未命中一律保持全表范围、回退下方原全表线性扫描(索引只加速命中,
|
||||
# 未命中行为与未加索引前逐字节一致);此前"未命中即确无、直接 return"已回退。
|
||||
# 名索引快速路径:可信(Built==n | 查询名非空)时直接定位唯一候选下标
|
||||
# (= 原扫描首个命中)。CDefine 名注册后不再改写、每次注册都同步入索引
|
||||
# (失败即置 Built=-1)⇒ 可信时未命中即"确无",直接返回 0(= 原全表扫描
|
||||
# 结果);索引不可用时回退下方原全表线性扫描。
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) \
|
||||
and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit >= 0:
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
if cd_hit < 0:
|
||||
return 0
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(cd_start, cd_end):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
@@ -379,17 +381,19 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return 0.0
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个
|
||||
# 命中);未命中一律保持全表范围、回退下方原全表线性扫描(索引只加速命中,
|
||||
# 未命中行为与未加索引前逐字节一致);此前"未命中即确无、直接 return"已回退。
|
||||
# 名索引快速路径:可信(Built==n | 查询名非空)时直接定位唯一候选下标
|
||||
# (= 原扫描首个命中)。CDefine 名注册后不再改写、每次注册都同步入索引
|
||||
# (失败即置 Built=-1)⇒ 可信时未命中即"确无",直接返回 0.0(= 原全表扫描
|
||||
# 结果);索引不可用时回退下方原全表线性扫描。
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) \
|
||||
and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit >= 0:
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
if cd_hit < 0:
|
||||
return 0.0
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(cd_start, cd_end):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
# 快速路径:strcmp 判等蕴含首字符相等,首字符不同者跳过 strcmp。
|
||||
@@ -420,17 +424,19 @@ class TypeGenCDef(TypeGenBase.TypeGenBase):
|
||||
return None
|
||||
n: sizet = len(self.CDefineNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选下标(= 原扫描首个
|
||||
# 命中);未命中一律保持全表范围、回退下方原全表线性扫描(索引只加速命中,
|
||||
# 未命中行为与未加索引前逐字节一致);此前"未命中即确无、直接 return"已回退。
|
||||
# 名索引快速路径:可信(Built==n | 查询名非空)时直接定位唯一候选下标
|
||||
# (= 原扫描首个命中)。CDefine 名注册后不再改写、每次注册都同步入索引
|
||||
# (失败即置 Built=-1)⇒ 可信时未命中即"确无",直接返回 None(= 原全表扫描
|
||||
# 结果);索引不可用时回退下方原全表线性扫描。
|
||||
cd_start: sizet = 0
|
||||
cd_end: sizet = n
|
||||
if name is not None and self.CDefineNameIdxBuilt == int(n) \
|
||||
and self.CDefineNameIdx is not None and self.CDefineNameIdxCap > 0:
|
||||
cd_hit: int = self._cdef_idx_find(name)
|
||||
if cd_hit >= 0:
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
if cd_hit < 0:
|
||||
return None
|
||||
cd_start = sizet(cd_hit)
|
||||
cd_end = sizet(cd_hit + 1)
|
||||
for i in range(cd_start, cd_end):
|
||||
nm: str = self.CDefineNames.get(i)
|
||||
if nm is not None and string.strcmp(nm, name) == 0:
|
||||
|
||||
@@ -219,17 +219,18 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
return None
|
||||
n: sizet = len(self.CTypedefNames)
|
||||
i: sizet
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选槽下标(CTypedef 表
|
||||
# 注册时按名去重 ⇒ 名唯一,命中即原全表扫描首个命中)。未命中一律回退下方
|
||||
# 原全表线性扫描(索引只加速命中,未命中行为与未加索引前逐字节一致);
|
||||
# 此前"可信未命中即确无、直接 return None"的语义已回退。
|
||||
# 名索引快速路径:可信(Built==n)时直接定位唯一候选槽下标。CTypedef 表
|
||||
# 注册时按名去重(register_ctypedef 已存在则原地更新类型串、不追加)⇒ 名
|
||||
# 唯一且注册后不再改写,索引完整覆盖全表 ⇒ 未命中即"确无",直接返回 None
|
||||
# (= 原全表扫描结果);索引不可用/不可信 → 回退下方原全表扫描。
|
||||
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:
|
||||
ts_hit: str = self.CTypedefTypeStrs.get(sizet(ti))
|
||||
self.CTypedefFound = 1
|
||||
return ts_hit
|
||||
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:
|
||||
|
||||
Reference in new issue
Block a user