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:
TermiNexus committed 2026-09-30 23:47:36 +08:00
1 parent 4641777db1
commit b18d57fa38
15 files changed
+318 -96

No files matched your search

+10 -5
View File
@@ -11,9 +11,14 @@ from lib.includes.t import CTypeRegistry
from lib.core.SymbolUtils import (
IsListAnnotation, AnnotationContainsName, IsCPtrSubscriptNode, IsCPtrNode,
IsRawPtrSubscriptNode, IsPtrSubscriptNode, ResolveGenericTypeArgStr,
EnumClassIntWidth, ClassHasFuncLevelCVTable)
EnumClassIntWidth, ClassHasFuncLevelCVTable)
# 泛型特化(`_SubstituteTypeArgs`)把 `%"SHA1.T"` / `%"SHA1.T"*` 替换为 i8* 用的
# **预编译**正则(性能:字面量正则预编译避免 re 缓存查找与编译开销)。
_RE_T_TYPE_PTR: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"\*')
_RE_T_TYPE: re.Pattern[str] = re.compile(r'%"[a-f0-9]+\.T"')
class DeclarationGenerator:
"""从 .pyi AST 生成纯 LLVM IR 声明(不使用字符串操作)"""
@@ -1060,9 +1065,9 @@ class DeclarationGenerator:
for mt in member_types:
new_mt: str = mt
# 将 %"SHA1.T"* 替换为 i8*(不透明指针)
new_mt = re.sub(r'%"[a-f0-9]+\.T"\*', 'i8*', new_mt)
new_mt = _RE_T_TYPE_PTR.sub('i8*', new_mt)
# 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8*
new_mt = re.sub(r'%"[a-f0-9]+\.T"', 'i8*', new_mt)
new_mt = _RE_T_TYPE.sub('i8*', new_mt)
result.append(new_mt)
return result
+67 -20
View File
@@ -235,6 +235,53 @@ _RE_AT_EXTERNAL: re.Pattern[str] = re.compile(r'@\S+\s*=\s*external\s+')
_RE_DECLARE_FULL: re.Pattern[str] = re.compile(
r'^declare\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(')
# 其余字面量正则的模块级预编译(同一性能理由:省掉每次调用的"模式串哈希 →
# re 缓存查找";模式串一字未改,flags 原样保留)。凡模式串不同或 flags 不同
# (有/无 re.MULTILINE)之处都各自独立成常量,保证匹配语义逐字不变。
# `_AddWeakComdat`:定位函数头第一个元数据(`!...`)附着点 / 全局定义尾部属性插入点
_RE_METADATA_ATTACH: re.Pattern[str] = re.compile(r'\s![\w.]')
_RE_COMDAT_TAIL_ATTRS: re.Pattern[str] = re.compile(r',\s*(?:align|section|partition|code_model)\b')
# LLVM 22+ external global 带初值 → linkonce(带行首锚 + MULTILINE)
_RE_EXTERNAL_GLOBAL_VALUE: re.Pattern[str] = re.compile(
r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$',
re.MULTILINE)
# 同上但**不带行首锚**(opt 内联后整段内容替换处)
_RE_EXTERNAL_GLOBAL_VALUE_PLAIN: re.Pattern[str] = re.compile(
r'(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$',
re.MULTILINE)
# define/declare 后跟显式链接性关键字 → 其后补 dso_local
_RE_DEFINE_DECLARE_LINKAGE: re.Pattern[str] = re.compile(
r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+',
re.MULTILINE)
# define/declare 后无链接性/dso_local(含 `@` 分支)→ 直接补 dso_local
_RE_DEFINE_DECLARE_NO_LINKAGE_AT: re.Pattern[str] = re.compile(
r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)',
re.MULTILINE)
# 同上但**无 `@` 分支**(traceback include 模块专用)
_RE_DEFINE_DECLARE_NO_LINKAGE: re.Pattern[str] = re.compile(
r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)',
re.MULTILINE)
# 全局定义(非 llvm.*)带链接性关键字 → 补 dso_local(无 MULTILINE)
_RE_GLOBAL_LINKAGE: re.Pattern[str] = re.compile(
r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)')
# 同上但带 MULTILINE
_RE_GLOBAL_LINKAGE_MULTILINE: re.Pattern[str] = re.compile(
r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)',
re.MULTILINE)
# 全局定义无链接性 → 补 dso_local(无 MULTILINE)
_RE_GLOBAL_DSOLOCAL: re.Pattern[str] = re.compile(
r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)')
# 同上但带 MULTILINE(原文此处带行首锚 `^`:避免匹配到字符串常量内容里的 global/constant)
_RE_GLOBAL_DSOLOCAL_MULTILINE: re.Pattern[str] = re.compile(
r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)',
re.MULTILINE)
# 收集已定义函数名(define 头)
_RE_DEFINE_HEAD: re.Pattern[str] = re.compile(
r'^define\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(',
re.MULTILINE)
# 判定 IR 是否含 define 行(traceback 警告)
_RE_DEFINE_LINE: re.Pattern[str] = re.compile(r'^define ', re.MULTILINE)
def _ParseDwarfLineRows(dump_text: str) -> list[tuple[int, str, int]]:
"""从 llvm-dwarfdump 输出解析出 [(地址, 文件绝对路径, 行号)]。
@@ -989,7 +1036,7 @@ def _AddWeakComdat(ll_content: str) -> str:
# "expected '{' in function body"(`[^{]*` 会跨行吞掉换行,--dwarf 给
# 每个 define 行尾加了 !dbg 后插入点就落到了附着之后)。故插入点前移到
# 第一个元数据附着之前。
attach = re.search(r'\s![\w.]', head)
attach = _RE_METADATA_ATTACH.search(head)
if attach is None:
return head + ' comdat ' + m.group(4)
return head[:attach.start()] + ' comdat' + head[attach.start():] + m.group(4)
@@ -1004,7 +1051,7 @@ def _AddWeakComdat(ll_content: str) -> str:
if ' comdat' in line:
return line
comdat_names.append(m.group(3))
ins = re.search(r',\s*(?:align|section|partition|code_model)\b', line)
ins = _RE_COMDAT_TAIL_ATTRS.search(line)
if ins:
return line[:ins.start()] + ', comdat' + line[ins.start():]
return line + ', comdat'
@@ -2285,7 +2332,7 @@ class Phase2Translator:
'--traceback: traceback 模块未注入 @llvm.global_ctors '
'(模块级收尾钩子未生效,不静默降级)')
# 修复 LLVM 22+: external global 不能有初值,改为 linkonce
result = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', result, flags=re.MULTILINE)
result = _RE_EXTERNAL_GLOBAL_VALUE.sub(r'\1 = linkonce global \2 \3', result)
# 后处理:添加 llvmlite 不支持的 LLVM 属性(如 willreturn, mustprogress)
pending_str_attrs = getattr(trans.translator.LlvmGen, '_pending_str_attrs', None)
if pending_str_attrs:
@@ -2524,12 +2571,12 @@ class Phase2Translator:
else:
_vlog().info(" [内联] 跨模块内联优化完成")
opt_content = _ReadTextCached(optimized_ll)
opt_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', opt_content, flags=re.MULTILINE)
opt_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', opt_content, flags=re.MULTILINE)
opt_content = _RE_DEFINE_DECLARE_LINKAGE.sub(r'\1 \2 dso_local ', opt_content)
opt_content = _RE_DEFINE_DECLARE_NO_LINKAGE_AT.sub(r'\1 dso_local ', opt_content)
# LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义
opt_content = re.sub(r'(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', opt_content, flags=re.MULTILINE)
opt_content = re.sub(r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', opt_content)
opt_content = re.sub(r'(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', opt_content)
opt_content = _RE_EXTERNAL_GLOBAL_VALUE_PLAIN.sub(r'\1 = linkonce global \2 \3', opt_content)
opt_content = _RE_GLOBAL_LINKAGE.sub(r'\1 = \2 dso_local \3', opt_content)
opt_content = _RE_GLOBAL_DSOLOCAL.sub(r'\1 = dso_local \2', opt_content)
opt_content = _AddWeakComdat(opt_content)
with open(optimized_ll, 'w', encoding='utf-8') as f:
f.write(opt_content)
@@ -2756,16 +2803,16 @@ class Phase2Translator:
break
ll_lines = ll_content.splitlines(True)
ll_content = ''.join(ll_lines[:header_end]) + stub_prefix + ''.join(ll_lines[header_end:])
ll_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local|@)', r'\1 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = _RE_DEFINE_DECLARE_LINKAGE.sub(r'\1 \2 dso_local ', ll_content)
ll_content = _RE_DEFINE_DECLARE_NO_LINKAGE_AT.sub(r'\1 dso_local ', ll_content)
# LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义
ll_content = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content, flags=re.MULTILINE)
ll_content = _RE_EXTERNAL_GLOBAL_VALUE.sub(r'\1 = linkonce global \2 \3', ll_content)
ll_content = _RE_GLOBAL_LINKAGE_MULTILINE.sub(r'\1 = \2 dso_local \3', ll_content)
ll_content = _RE_GLOBAL_DSOLOCAL_MULTILINE.sub(r'\1 = dso_local \2', ll_content)
ll_content = _AddWeakComdat(ll_content)
# LLVM 22+: 移除同一模块中已有 define 的 declare 语句(LLVM 22 将 declare+define 视为重复定义)
defined_funcs: set[str] = set()
for m in re.finditer(r'^define\s+(?:dso_local\s+)?[^@]*@\"?([^"\s\(]+)\"?\s*\(', ll_content, re.MULTILINE):
for m in _RE_DEFINE_HEAD.finditer(ll_content):
defined_funcs.add(m.group(1))
if defined_funcs:
lines: list[str] = ll_content.splitlines(True)
@@ -3622,19 +3669,19 @@ class Phase2Translator:
# **只警告、不报错**:像 includes/stdarg.vp 这类模块的 define 是"合成"的
# (由 extern/sugar 派生、无 .vp 函数体),本就不会有源级 DI —— 按 fail-fast
# 报错会把这类模块全部误杀;而"行号缺失"只降低可读性,不是编译正确性问题。
if self.traceback_enabled and re.search(r'^define ', ll_content, re.MULTILINE) \
if self.traceback_enabled and _RE_DEFINE_LINE.search(ll_content) \
and '!llvm.dbg.cu' not in ll_content:
_vlog().warning(
f"--traceback: include 模块 {module_name}.py 发射了 define 但 IR 未携带 "
f"DWARF (!llvm.dbg.cu)——该模块内联帧在 Ctrl+C 栈里将只显示地址: {ll_path}")
# dso_local 正则标注(使用 ^ + MULTILINE 避免匹配字符串常量内容中的 define/declare)
ll_content = re.sub(r'^(define|declare)\s+(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external)\s+', r'\1 \2 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(define|declare)\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|external|dso_local)', r'\1 dso_local ', ll_content, flags=re.MULTILINE)
ll_content = _RE_DEFINE_DECLARE_LINKAGE.sub(r'\1 \2 dso_local ', ll_content)
ll_content = _RE_DEFINE_DECLARE_NO_LINKAGE.sub(r'\1 dso_local ', ll_content)
# LLVM 22+: external 不允许在带初值的全局定义上显式写出,改为 linkonce 保留多模块合并语义
ll_content = re.sub(r'^(@[\w.]+)\s*=\s*external\s+global\s+(\w[\w*]*)\s+(-?\d+|null|zeroinitializer|true|false)$', r'\1 = linkonce global \2 \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'(@(?!llvm\.)[\w.]+)\s*=\s*(private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr)\s+(global|constant)', r'\1 = \2 dso_local \3', ll_content, flags=re.MULTILINE)
ll_content = re.sub(r'^(@[\w.]+)\s*=\s+(?!private|internal|available_externally|linkonce|weak|common|appending|extern_weak|linkonce_odr|weak_odr|dso_local)(global|constant)', r'\1 = dso_local \2', ll_content, flags=re.MULTILINE)
ll_content = _RE_EXTERNAL_GLOBAL_VALUE.sub(r'\1 = linkonce global \2 \3', ll_content)
ll_content = _RE_GLOBAL_LINKAGE_MULTILINE.sub(r'\1 = \2 dso_local \3', ll_content)
ll_content = _RE_GLOBAL_DSOLOCAL_MULTILINE.sub(r'\1 = dso_local \2', ll_content)
ll_content = _AddWeakComdat(ll_content)
# stub_decls 注入(复用预收集的 stub_decls)