perf(tpc): import 热路径优化——walk 结果缓存 + DebugPrint 参数惰性化

- import 兜底查找(_EmitModuleDeclarationsLlvm)每次解析失败都 os.walk 递归扫描 includes/工程目录,且多级模块名与 basename 永不匹配纯浪费:改为多级跳过 + 目录 walk 结果类级缓存(编译进程内目录不变)
- DebugPrint 调用点(HandlesTypeMerge 类型查询热路径)无条件构造 f-string 参数(含昂贵的 ast.dump),即使 DebugFile 未设置也执行:改为 getattr(DebugFile) 防护后才构造(单文件 profile:_io.open 1253 次 1.76s + DebugPrint cum 2.24s)
This commit is contained in:
TermiNexus committed 2026-08-22 06:05:43 +08:00
1 parent daf79af1cc
commit c62153a685
2 files changed
+27 -11

No files matched your search

+22 -9
View File
@@ -22,6 +22,10 @@ class ImportHandle(BaseHandle):
_pyi_cache = {}
_pyi_cache_dir = None
_project_root_cache = None
# 目录 os.walk 结果缓存(import 失败兜底查找用):目录 -> [(root, files)]。
# 编译进程内 SearchDirsForSubmodule(includes/LibraryPaths/工程目录)内容不变,
# 避免每次 import 解析失败都全量递归扫描目录树(PROF:import 热路径高频调用)。
_walk_cache: dict[str, list[tuple[str, list[str]]]] = {}
# 类级 stub 索引:class_name -> list of (full_name, struct_body, file_sha1, from_output)
# 一次扫描所有 .stub.ll 文件构建索引,避免 _TryLoadStructFromStub 每次调用都全量扫描
# (原 609 次调用 × ~100 stub 文件 × ~50 行 = 5.5M 正则匹配 → 一次扫描 ~5000 匹配)
@@ -647,18 +651,27 @@ class ImportHandle(BaseHandle):
SearchFromDirs = [os.getcwd()]
SearchDirsForSubmodule = SearchFromDirs + [os.path.join(TransPyCRoot, 'includes'), os.path.join(TransPyCRoot, 'lib', 'includes')] + list(self.Trans.LibraryPaths)
for SearchPath in SearchDirsForSubmodule:
if os.path.isdir(SearchPath):
for root, dirs, files in os.walk(SearchPath):
if '__pycache__' in root:
continue
for src_ext in ('.vp', '.py', '.vpi', '.pyi'):
if module_name + src_ext in files:
FullModulePath = os.path.join(root, module_name + src_ext)
break
if FullModulePath:
if not os.path.isdir(SearchPath):
continue
# 多级模块名(含 '.')与 basename 文件列表(files 无路径)
# 永不匹配 `module_name + ext in files`,walk 纯属浪费,跳过。
if '.' in module_name:
continue
# 目录 walk 结果缓存(编译进程内目录内容不变):import 热路径
# 高频解析失败时避免重复递归扫描 includes/工程目录(PROF 热点)
walk_entries: list[tuple[str, list[str]]] = ImportHandle._walk_cache.get(SearchPath)
if walk_entries is None:
walk_entries = [(r, fs) for r, dirs, fs in os.walk(SearchPath) if '__pycache__' not in r]
ImportHandle._walk_cache[SearchPath] = walk_entries
for root, files in walk_entries:
for src_ext in ('.vp', '.py', '.vpi', '.pyi'):
if module_name + src_ext in files:
FullModulePath = os.path.join(root, module_name + src_ext)
break
if FullModulePath:
break
if FullModulePath:
break
# fail-fast:模块在所有来源都"完全未知"时立即报错,暴露 import 路径错误
# (如目录重组后未更新的旧路径)。之前静默容忍导致引用方跨模块 mangled
# 前缀 fallback 当前模块 sha1,链接期才暴露 undefined symbol。
+5 -2
View File
@@ -37,7 +37,9 @@ class HandlesTypeMerge(BaseHandle):
"""鍐呴儴鏂规硶锛岃繑鍥?CTypeInfo"""
LineNum = getattr(Node, 'lineno', None)
self.Trans.DebugPrint(f"[GetCTypeInfo] Node type: {type(Node).__name__}, dump: {ast.dump(Node)[:60]}...")
if getattr(self.Trans, 'DebugFile', None):
# 仅 debug 模式构造参数(ast.dump 昂贵,非 debug 时无条件执行是隐藏热点)
self.Trans.DebugPrint(f"[GetCTypeInfo] Node type: {type(Node).__name__}, dump: {ast.dump(Node)[:60]}...")
if isinstance(Node, ast.Constant):
TypeName = Node.value
@@ -152,7 +154,8 @@ class HandlesTypeMerge(BaseHandle):
if resolved:
ModulePath = resolved
self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute] 查询: '{TypeName}' ModulePath: {ModulePath}")
if getattr(self.Trans, 'DebugFile', None):
self.Trans.DebugPrint(f"[GetCTypeInfo-Attribute] 查询: '{TypeName}' ModulePath: {ModulePath}")
if ModulePath == 't' and TypeName == 'State':
Info = CTypeInfo()