perf(全仓库/正则): 字面量正则全部改模块级预编译常量(15 文件 / 115 个调用点)
背景(prof 基线 PROF/20260930_224857,主进程 433.69s):正则这一族合计 ≈45s —— `re.match`(未预编译入口)被调 1970 万次 / 自身 10.70s、它内部 `Pattern.match` 占 8.06s, `re._compile`(缓存查找)1975 万次 / 7.19s,`re._make`(真正编译)274 万次 / 7.62s (说明 re 的 512 条缓存已被打穿,每 7 次调用就有 1 次重新编译)。 每次 `re.match(字面量, s)` 都要做"模式串哈希 → 缓存查找";预编译后这层全省掉。 改动:把 15 个文件里 97 处"字面量当模式"的 `re.match/search/sub/subn/fullmatch/ findall/finditer/split(...)` 提升为模块级 `_RE_*: re.Pattern[str] = re.compile(...)`, 共 115 个调用点(含同字面量跨处共用)。模式串与 flags 一字未改(flags 从调用处 搬进 re.compile,含原先以**位置参数**传入的 flags)。4 处拼接型动态模式按设计不动 (FuncGen 2 处、HandlesImports 2 处)。 核验(不靠肉眼):写了 AST 指纹对拍脚本,对每个文件取 HEAD 版与新工作区版,把 "旧 re.<m>(字面量, 其余实参, 关键字) + flags" 与 "新 _RE_X.<m>(实参, 关键字) + 常量 (模式, flags)" 做多重集比对 —— 15 个文件、115 个调用点全部逐一等价(0 失败), 另查无重名常量、无遗留字面量调用、GetDiagnostics 全空。 对拍过程中查出一处子代理抄写错误:`_RE_GLOBAL_DSOLOCAL_MULTILINE` 丢了行首锚 `^` (原文注释明确"使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare"),已修正。 同轮经查证后**未做改动**的两项(避免把假热点当真事修): - VLogger 的 `re.sub` 6.43s:profile 当时的 VLogger 版本里根本没有 `import re` (`git show 3658ab06:lib/core/VLogger.py` 已确认),属 C 帧错挂,不做。 - tokenize 274 万次:那是 `_generate_tokens_from_c_tokenizer` 的 **token 产出次数** (≈350 个整文件的词法量),SymbolUtils 的 4 个 tokenize 调用点 nc 仅数百,且已有 `_EXPAND_CACHE` 去重;再加一层 token 缓存无收益,不做。
This commit is contained in:
1 parent
4641777db1
commit
b18d57fa38
15 files changed
+318
-96
No files matched your search
@@ -49,6 +49,35 @@ _LLVM_PRIMITIVE_TYPE_MAP: dict[str, ir.Type] = {
|
||||
}
|
||||
|
||||
|
||||
# 字面量正则的模块级预编译(性能:这些调用点做逐行扫描/逐条解析,命中次数极高;
|
||||
# 每次 `re.match(字面量, s)` 都要做"模式串哈希 → re 缓存查找"。预编译成模块级常量
|
||||
# 后省掉该查找,且匹配路径更短。模式串一字未改。
|
||||
# 解析异常报文里兜底取 `at line N`
|
||||
_RE_AT_LINE: re.Pattern[str] = re.compile(r'at line (\d+)')
|
||||
# stub 里 `%<sha1>.Name = type <...>` 结构体定义行
|
||||
_RE_STRUCT_TYPE_DEF: re.Pattern[str] = re.compile(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)')
|
||||
# `[N x <T>]` 数组类型
|
||||
_RE_ARRAY_TYPE: re.Pattern[str] = re.compile(r'\[(\d+)\s*x\s+(.+)\]')
|
||||
# declare 行(函数名限定 `[\w.]+` 字符集)
|
||||
_RE_DECLARE_SIMPLE: re.Pattern[str] = re.compile(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$')
|
||||
# declare 行(函数名允许任意非括号字符)
|
||||
_RE_DECLARE_GENERIC: re.Pattern[str] = re.compile(r'declare\s+(.+?)\s+@("?[^()]+"?)\s*\((.*)\)$')
|
||||
# 剥离 LLVM IR 参数名:`\s+%name` 或 `\s+%"quoted.name"` 结尾
|
||||
_RE_PARAM_NAME_TRAILING: re.Pattern[str] = re.compile(r'\s+%("[^"]*"|[\w.]+)\s*$')
|
||||
# 剥离 LLVM IR 参数名:`\s+%name`(无引号形式)
|
||||
_RE_PARAM_NAME_PLAIN: re.Pattern[str] = re.compile(r'\s+%[\w.]+\s*$')
|
||||
# stub 里引用到的 sha1 前缀 `%<16hex>.`
|
||||
_RE_SHA1_PREFIX_REF: re.Pattern[str] = re.compile(r'%\"?([a-f0-9]{16})\.')
|
||||
# `@name = external global <...>` 全局变量定义行
|
||||
_RE_EXTERNAL_GLOBAL_DEF: re.Pattern[str] = re.compile(r'@("?)(?:([a-f0-9]{16})\.)?([\w.\[\]]+)\1\s*=\s*external\s+global\s+(\S.*)')
|
||||
# 去掉全局类型尾部 zeroinitializer
|
||||
_RE_STRIP_ZEROINIT: re.Pattern[str] = re.compile(r'\s+zeroinitializer.*$')
|
||||
# 去掉全局类型尾部 `, align N`
|
||||
_RE_STRIP_ALIGN: re.Pattern[str] = re.compile(r'\s*,\s*align\s+\d+.*$')
|
||||
# struct 定义名(不强制 `= type ...` 后缀)
|
||||
_RE_STRUCT_NAME: re.Pattern[str] = re.compile(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]*]+)"?')
|
||||
|
||||
|
||||
def _HasRealParentClass(Node: ast.ClassDef) -> bool:
|
||||
"""类是否声明了**真实父类**(排除 Object/CVTable/NoVTable/CEnum/... 标记基类)。"""
|
||||
for base in getattr(Node, 'bases', None) or []:
|
||||
@@ -106,7 +135,7 @@ def _ParseFailureSite(Exc: BaseException) -> str:
|
||||
Line: int = int(getattr(Exc, 'lineno', 0) or 0)
|
||||
Col: int = int(getattr(Exc, 'offset', 0) or 0)
|
||||
if not Line:
|
||||
Matched: re.Match | None = re.search(r'at line (\d+)', str(Exc))
|
||||
Matched: re.Match | None = _RE_AT_LINE.search(str(Exc))
|
||||
if Matched:
|
||||
Line = int(Matched.group(1))
|
||||
if not Line:
|
||||
@@ -2921,7 +2950,7 @@ class ImportHandle(BaseHandle):
|
||||
content = f.read()
|
||||
for line in content.splitlines():
|
||||
stripped = line.strip()
|
||||
match = re.match(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)', stripped)
|
||||
match = _RE_STRUCT_TYPE_DEF.match(stripped)
|
||||
if match:
|
||||
full_name = match.group(1)
|
||||
short_name = match.group(2)
|
||||
@@ -3593,7 +3622,7 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
stub_func_name = name_match[1].split('(', 1)[0].strip().strip('"')
|
||||
|
||||
match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', stripped)
|
||||
match = _RE_DECLARE_SIMPLE.match(stripped)
|
||||
if match:
|
||||
stub_ret = match.group(1).strip()
|
||||
stub_params = match.group(3).strip()
|
||||
@@ -3646,7 +3675,7 @@ class ImportHandle(BaseHandle):
|
||||
"""剥离 LLVM IR 参数字符串中的参数名,仅保留类型部分"""
|
||||
param_str = param_str.strip()
|
||||
# 支持 %name 和 %"quoted.name" 两种参数名形式
|
||||
result = re.sub(r'\s+%("[^"]*"|[\w.]+)\s*$', '', param_str)
|
||||
result = _RE_PARAM_NAME_TRAILING.sub('', param_str)
|
||||
return result.strip()
|
||||
|
||||
def _parse_simple_llvm_type(self, type_str: str) -> ir.Type | None:
|
||||
@@ -3676,7 +3705,7 @@ class ImportHandle(BaseHandle):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
|
||||
if type_str.startswith('[') and ']' in type_str:
|
||||
arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
|
||||
arr_match = _RE_ARRAY_TYPE.match(type_str)
|
||||
if arr_match:
|
||||
size = int(arr_match.group(1))
|
||||
elem_type = self._parse_simple_llvm_type(arr_match.group(2).strip())
|
||||
@@ -3727,10 +3756,10 @@ class ImportHandle(BaseHandle):
|
||||
for line in content.splitlines():
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('%') and '=' in stripped and 'type' in stripped:
|
||||
for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
|
||||
for m in _RE_SHA1_PREFIX_REF.finditer(stripped):
|
||||
needed_sha1s.add(m.group(1))
|
||||
elif stripped.startswith('declare '):
|
||||
for m in re.finditer(r'%\"?([a-f0-9]{16})\.', stripped):
|
||||
for m in _RE_SHA1_PREFIX_REF.finditer(stripped):
|
||||
needed_sha1s.add(m.group(1))
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
@@ -3757,7 +3786,7 @@ class ImportHandle(BaseHandle):
|
||||
stripped = line.strip()
|
||||
|
||||
if stripped.startswith('%') and '=' in stripped and 'type' in stripped:
|
||||
struct_def_match = re.match(r'%"?((?:[a-f0-9]+\.)?([\w\[\]]+))"?\s*=\s*type\s*(.*)', stripped)
|
||||
struct_def_match = _RE_STRUCT_TYPE_DEF.match(stripped)
|
||||
if struct_def_match:
|
||||
raw_name = struct_def_match.group(1)
|
||||
# 治本修复:从 raw_name 提取类型定义的实际 sha1 前缀,
|
||||
@@ -3807,14 +3836,14 @@ class ImportHandle(BaseHandle):
|
||||
# Gen.module.globals → _lookup_module_global 恒 None → store/load
|
||||
# 全部丢失 → memset(null) 崩溃。此处兼容裸名 + sha1 前缀两种格式,
|
||||
# 名称与定义一致(temp/*.text.ll 均为裸名)。
|
||||
_gv_match = re.match(r'@("?)(?:([a-f0-9]{16})\.)?([\w.\[\]]+)\1\s*=\s*external\s+global\s+(\S.*)', stripped)
|
||||
_gv_match = _RE_EXTERNAL_GLOBAL_DEF.match(stripped)
|
||||
if _gv_match:
|
||||
_gv_name: str = _gv_match.group(3)
|
||||
_gv_sha1: str | None = _gv_match.group(2)
|
||||
_gv_type_str: str = _gv_match.group(4).strip()
|
||||
# 去掉尾部修饰(zeroinitializer / , align N),只保留类型
|
||||
_gv_type_str = re.sub(r'\s+zeroinitializer.*$', '', _gv_type_str)
|
||||
_gv_type_str = re.sub(r'\s*,\s*align\s+\d+.*$', '', _gv_type_str)
|
||||
_gv_type_str = _RE_STRIP_ZEROINIT.sub('', _gv_type_str)
|
||||
_gv_type_str = _RE_STRIP_ALIGN.sub('', _gv_type_str)
|
||||
if _gv_name not in Gen.module.globals:
|
||||
_gv_ty: ir.Type | None = self._parse_llvm_type(_gv_type_str, Gen, source_sha1=source_sha1)
|
||||
if _gv_ty is not None:
|
||||
@@ -4002,7 +4031,7 @@ class ImportHandle(BaseHandle):
|
||||
|
||||
def _parse_llvm_declare(self, declare_line: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
|
||||
"""解析 LLVM declare 语句"""
|
||||
match = re.match(r'declare\s+(.+?)\s+@("?[^()]+"?)\s*\((.*)\)$', declare_line)
|
||||
match = _RE_DECLARE_GENERIC.match(declare_line)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
@@ -4146,7 +4175,7 @@ class ImportHandle(BaseHandle):
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
|
||||
if type_str.startswith('[') and ']' in type_str:
|
||||
arr_match = re.match(r'\[(\d+)\s*x\s+(.+)\]', type_str)
|
||||
arr_match = _RE_ARRAY_TYPE.match(type_str)
|
||||
if arr_match:
|
||||
size = int(arr_match.group(1))
|
||||
elem_type = self._parse_llvm_type(arr_match.group(2).strip(), Gen, source_sha1=source_sha1, create_structs=create_structs)
|
||||
@@ -4160,7 +4189,7 @@ class ImportHandle(BaseHandle):
|
||||
# list[<sha1>.AST](少一层指针)并 declare_only 特化出无方法体的
|
||||
# 假类型 → 调用点引用未定义的 <模sha1>.list[<sha1>.AST].__len__
|
||||
# (链接期 undefined symbol 根因)。
|
||||
struct_match = re.match(r'%"?((?:[a-f0-9]+\.)?[\w.\[\]*]+)"?', type_str)
|
||||
struct_match = _RE_STRUCT_NAME.match(type_str)
|
||||
if struct_match:
|
||||
raw_name = struct_match.group(1)
|
||||
actual_source_sha1 = source_sha1
|
||||
@@ -4240,5 +4269,5 @@ class ImportHandle(BaseHandle):
|
||||
'i32' -> 'i32'
|
||||
"""
|
||||
param_str = param_str.strip()
|
||||
stripped = re.sub(r'\s+%[\w.]+\s*$', '', param_str)
|
||||
stripped = _RE_PARAM_NAME_PLAIN.sub('', param_str)
|
||||
return stripped.strip()
|
||||
Reference in new issue
Block a user