Commit Graph
48 Commits
Author SHA1 Message Date
TermiNexus 030d0fd149 feat(tpc): PROF 输出按编译启动时间分目录,不再清理旧目录
需求(2026-09-29):PROF 按启动时间分组新建文件夹生成,不清理旧的 PROF。

改动:
- Phase2Translator:新增 `StartProfRun()`(在 PROF 根目录下按 `YYYYmmdd_HHMMSS`
  新建本次编译专属子目录,同名补 `_N`;失败回落 PROF 根目录)与
  `GetProfRunDir()`(主进程用已选定目录,worker 用继承的环境变量
  `TPC_PROF_RUN_DIR` 复用同一目录)。原 `_CleanProfFiles()` 删除——它的语义
  是"每次编译删掉 PROF 下全部 *.prof",与"保留历次"直接冲突。
- worker_prof_*.prof 落 `PROF/<启动时间>/`。
- main_prof_{pid}.prof 与 main_time.txt 同样落该目录(Projectrans.py)。
- Config.main 启动时调用 StartProfRun 并打印本次输出目录。

子目录名经环境变量传子进程:ProcessPoolExecutor 用 spawn 起新解释器,进程内
模块态不共享,环境变量随进程继承 ⇒ 同一次编译的所有 worker 落在同一目录,
不会各建各的。
2026-09-29 16:26:44 +08:00
TermiNexus 4fc067e3bf perf(tpc): 按 profile 消掉两处主热点(stub 索引每 miss 重扫目录 / vtable 每类全扫函数)
依据 PROF/main_prof_10152.prof(main_time.txt: 失败 2362.46s,72 个文件全部走
顺序 _translate_file,tottime 合计 2288.9s):

  tottime      calls   函数
  491.7s      723782   nt._path_isdir            ← 总时长 21%
  268.6s       15762   StructGen._generate_structs
  182.9s      479819   nt.listdir                ← 8%
  87.2s    657640754   builtins.isinstance
  78.6s     41514263   ntpath.join
  75.9s     83047878   ntpath.splitroot
  75.7s         1631   StructGen._create_Vtable_globals   (46ms/次)
  66.6s       238007   HandlesImports._build_stub_index
  63.0s    317868145   str.startswith
  38.4s    175751378   str.endswith
  ...
  ── 仅 isdir + listdir + join/splitroot/endswith ≈ 850s ≈ 总时长的 37%

一、_build_stub_index 的零 syscall 快路径(HandlesImports + Phase2Translator)
    它由 _TryLoadStructFromStub 的**每次索引 miss** 调用(238k 次),每次都要
    2× os.path.isdir + 2× os.listdir + 全量 endswith/join 重拼文件集合 ——
    这正是上面 isdir 723k / listdir 479k 的主要来源。
    改为:写入方显式置脏(ImportHandle.MarkStubSetDirty),未置脏时直接返回。
    置脏点:① 每个文件翻译入口(_translate_file,顺序与 worker 模式皆按文件粒度
    覆盖)② 写 temp/<sha1>.stub.ll 之后 ③ 注册 include 写 output/<sha1>.stub.ll
    之后。索引建完即清脏。语义:增量重扫、output 覆盖 temp 全部不变,只是把
    "集合是否变化"由目录扫描改为写入方免费告知(编译进程内 stub 只增不改)。

二、_create_Vtable_globals 的 O(类数 × 函数数) → O(函数数)
    原实现对每个候选类都遍历一遍 self.functions 找 "{ClassName}." 前缀且非
    declare 的函数;改为一次性预计算"非 declare 函数名的全部点分前缀"集合,
    每类只做一次集合查询。判据等价(startswith(prefix) ⟺ prefix 在点分前缀集)。

重编后请再抓一次 profile 复核收益;下一梯队热点是 _generate_structs
(268.6s tottime / 35k 次调用)与 _parse_llvm_type(3.5M 次调用)。
2026-09-29 14:36:57 +08:00
TermiNexus 74ccd31c19 fix(tpc): 裸名解析处理同名冲突 + 声明阶段多轮,消除跨模块类型解析残余失败
承接上一条(两阶段加载)后仍有 11 个模块签名解析失败,两类根因:

① 同名冲突:平坦符号表(无前缀)一个名字只能留一个条目,不同模块可用不同类型

   种类声明同名符号,且谁后插入谁占住裸名 —— stdint.vp:9 `INT: t.CTypedef = t.CInt`

   与 argparse.vp:33 `define INT = 1`(sig: `INT: t.CDefine = 1`)撞名 ⇒ posix 的

   `oflag: INT` 解析失败;llvmlite/__function.vp:77 `class Function` 与

   ast/tokens.vp:95 枚举成员 `Function: t.State` 撞名 ⇒ 5 个模块的 `func: rawptr[Function]`

   失败;ast/exprs.vp:18 `class Name` 同型(ast/parser.vp)。

   修法:_resolve_name 在平坦条目不是 typedef/类/枚举时,跨 _namespaces 找回同名

   typedef / 类 / 枚举(注解位置只可能是这三种)。

② 声明阶段的顺序依赖:typedef 右侧可引用其它模块的 typedef(win32base 的

   `HANDLE: t.CTypedef = VOIDPTR`,VOIDPTR 在 stdint)⇒ 单轮仍与顺序有关。

   修法:Phase2Translator 声明阶段多轮(未解析 typedef 的模块下一轮重 stage,

   无进展即停,_CountUnresolvedTypedefs 判定),签名阶段仍是全部声明入表后统一跑。

③ 顺带修:两阶段是两个 TypeResolver 实例,签名阶段也须注入本模块类型名

   (TypeResolver.inject_known_type_names 供两阶段共用)。

验证(TransPyV 全量 127 个 sig 模拟 ①→②):commit 失败数 11 → 0;

posix.open ret=i32 params=[i8*,i32]、read ret=i64 params=[i32,i8*,i64] 解析正确。
2026-09-28 18:25:57 +08:00
TermiNexus 05f4adb233 fix(tpc): 符号表加载改两阶段,消除模块加载顺序依赖
a 类(编译器缺陷/机制漏豁免):签名解析要通过符号表查其它模块的类型名

(from X import * 的裸名如 posix 的 INT;跨模块类如 rawptr[Constant]),而加载器

按 os.listdir 字典序逐个「提取→解析→插入」⇒ posix 排在 stdint 之前时 INT 查不到。

旧口径静默降级 i32 掩盖了它,fail-fast 后暴露。

修法:加载拆两趟 —— ① StageModuleSymbols:提取 + 只解析/插入声明

(类/枚举/typedef/匿名类型)② CommitModuleSymbols:解析签名 + 插入函数/define +

命名空间重导出。批量加载器(Phase2Translator._build_shared_symbol_data)先收集全部

模块、跑完所有①再统一跑② ⇒ 任一模块的签名都能看到全部声明,与顺序无关。

单模块 LoadModuleSymbols 语义不变(①紧接②)。

验证(探针,posix 先 stage、stdint 后 stage 的“坏顺序”):

  posix.open ret=i32 params=[i8*,i32](INT=stdint 的 typedef);read ret=i64 params=[i32,i8*,i64];

  同样顺序走旧的单模块路径则 RAISE(对照组)。
2026-09-28 18:14:45 +08:00
TermiNexus 96d8e13c5a fix(err): 成员查找 fail-fast 改用可读异常 + 报错语句栈不再重复长报文
① 新增 MemberLookupFailFast(KeyError):_get_member_offset 的 fail-fast 原用 raise KeyError(消息),而 KeyError.__str__ = repr(消息) ⇒ 报文被加上引号、换行被转义成字面 \n(含"源代码 (文件, 行号): 行号 | 源码"的多行报文彻底不可读)。新类继承 KeyError(保住 HandlesExprAttr 两处 except KeyError 兜底点)但 __str__ 返回裸消息。

② 顺带删除该处的 traceback.print_stack 调试转储(遗留调试语句,输出噪音)。

③ Phase2Translator 语句栈渲染:原格式把同一条异常消息贴在每一层帧后面 ⇒ 一句话被打印 N 次;改为外层→内层的调用路径逐帧印位置、异常消息只在最内层印一次。
2026-09-28 16:48:58 +08:00
TermiNexus c83fc752c6 fix(sizeof,parse): 尺寸链去静默兜底,解析报错可定位,补 C 解析器缺口
StructGen: _get_struct_size/_get_align 去 opaque→8/ptr_size、未知→4 兜底并补 VectorType;LiteralStructType.fields→.elements(llvmlite 无 fields,必然 AttributeError)

HandlesClassDef: union 载荷尺寸经不存在的 ir.DataLayout 静默退化成 8 字节;HandlesExprCall/ExprBuiltin: sizeof 各静默 0 分支改 fail-fast,数组元素 sizeof 统一走 _get_struct_size

HandlesFor: nonlocal struct/array 堆分配不再退化成 malloc(8)

vast/vast_c: 补一元 * / & 解析,装饰器后 extern/export 分派修复,C 侧报错带 token 与行号;StubGen.Converter: 宏展开丢尾随空行修 .pyi 缩进非法

其余为 rawptr 迁移 / fail-fast 口径等历史改动一并入库
2026-09-26 19:27:22 +08:00
TermiNexus 53a345a59a feat(ctrlc-stack): 新增 --ctrlc-stack 编译期开关(按键打印 .vp 调用栈)
Config/Phase2Translator: --ctrlc-stack 自动开 DWARF;缓存失效;链接后 llvm-dwarfdump 导出 <exe>.stackmap(逐条归一化为 RVA——旧的整体判据会被 lld 去重产生的 0 地址行带偏,导致全表差一个 ImageBase);链接参数追加 -ldbghelp;include 也生成 DWARF 并隔离到 includes.binary_ctrlcstack(_asan);llc 追加 -frame-pointer=all。

BaseGen._RegisterDbgStackInstallViaCtor + StructGen.finalize 钩子: 注入 llvm.global_ctors(priority 65535) 在启动期调用 dbgstack.Install(),写盘前核对 global_ctors 否则 fail-fast。

FuncGen._adjust_args: 指针到整数的 fail-fast 补逐项类型诊断。
2026-09-25 13:11:13 +08:00
TermiNexus 6af2dea917 修复了一些问题 2026-09-17 14:52:37 +08:00
TermiNexus 43e7cdd2cc feat(tpc): 函数级 DWARF 调试元数据 + 合并 IR 元数据规整
DWARF: 新增 LLVMCG/DebugInfo.py(DebugInfoEmitter)——每模块一个 DIFile/DICompileUnit、每个 define 一个 DISubprogram 并在函数入口首条指令挂 DILocation,模块落盘前补 !llvm.dbg.cu 与 !llvm.module.flags(Debug Info Version 3)。开关:新增 --dwarf(默认关闭),dwarf_enabled = args.dwarf or args.asan,沿 Phase2Translator → _translate_file → Translator.DwarfEnabled → LlvmCodeGenerator.dwarf_enabled 下传。define 之外的 declare 不挂。include 库刻意不给 DI(其 .obj 进跨项目共享的 includes.binary 缓存,注入会污染缓存)

关键约束(踩过的坑,已在探针中实测):DICompileUnit 与 DISubprogram 必须 is_distinct=True;emissionKind 用 FullDebug 而非 Full;spFlags 用 DISPFlagDefinition;DISubprogram 必带 type=DISubroutineType,缺了 llc 会崩 0xC0000005;模块级必须有 !llvm.dbg.cu + Debug Info Version 3

IRMetadataFix: 新增 SanitizeIRMetadata,在 _llc_compile 入口统一规整 IR——BuildCombinedIR 是多模块 IR 文本直接拼接,--dwarf 后每个片段自带 !0..!N 与两份命名元数据,22383 行样本里 !0/!1 各重复 67 次导致 opt/llc 报 Metadata id is already used。实现:按块重编号 !N 并改写 !dbg/命名元数据引用、!llvm.dbg.cu 全量聚合、其它命名元数据全同去重;无元数据文件逐字节 no-op、幂等(1.7MB/0.30s)

顺带修 _AddWeakComdat:函数头正则跨行吞换行,--dwarf 把 !dbg 放到 define 行尾后 comdat 被插到 ! 附着之后,llc 报 expected { in function body(现场 52 个 define 中 36 个中招);改为插在附着之前,无 !dbg 时产物逐字节不变

已自证:llc/opt RC=0、行表含 .vp 文件名与行号、opt -passes=forceattrs,asan 与 llvm-link/always-inline 均不丢 !dbg。已知待办:llc 现报 inlinable function call ... must have a !dbg location ⇒ 需补语句/调用点级 !dbg(否则警告 ignoring invalid debug info 会丢弃整份 DI)
2026-09-16 19:29:51 +08:00
TermiNexus d0f69eb90a fix(phase2): 热点插桩时强制失效 include 模块的旧目标文件
include 模块同样会被插桩(hotspot_sites_file 经 worker 透传),但 _compile_include_py_files 对预编译缓存 precompiled_obj 与 output 缓存 obj_path 存在即跳过,且没有 hotspot_on 强制重译分支,导致复用上一次未插桩的 .obj,使 include 内热点模块(MemBuddy.alloc、ast.tokens、ast.base、llvmlite 窥孔等)的计数/计时 IR 静默缺失、其耗时被计入调用者 self。

启用热点时先删除这两类旧 .obj(沿用 App 主循环同一写法:用未缓存的 os.path.isfile 判定,避免把已存在写入只写存在性缓存后被删除导致后续判定读到过期值而漏编),删除失败仅告警不中断、不静默吞错。

include 路径本就每次无条件重译 .ll(无跳过逻辑),故只需处理 .obj;.dso.ll/.stub.ll/.text.ll/.vpi/.deps.json 经核对无同类隐患。未启用热点时行为逐字节不变。
2026-09-14 14:42:01 +08:00
TermiNexus ac77287f20 fix(phase2): 热点插桩强制重译时同步失效旧目标文件
启用 --hotspot-sites 时会跳过 .ll 与 .stub.ll+.text.ll 两个缓存分支而强制重译,但既有的 {sha1}.obj 未被清理:_compile_ll_files 的三处跳过判定只按 obj 是否存在(收集阶段、_compile_one、need_compile 二次过滤),会复用上一次未插桩的目标文件,导致部分模块的热点计时/计数静默缺失、其耗时被计入调用者 self。

在 App 源文件主循环内,hotspot_on 为真时先删除对应 {sha1}.obj;用未缓存的 os.path.isfile 判定而非 _CachedIsFile,避免把已存在写入只写存在性缓存后被删除、使后续三处判定读到过期值而漏编;删除失败仅告警不中断、不静默吞错。

该循环遍历全部可达源文件且本轮所有文件都进入 need_translate(串行与批处理共享同一列表),故覆盖本轮全部被强制重译的模块。未启用时整块被跳过,行为逐字节不变。
2026-09-14 14:40:30 +08:00
TermiNexus fc5a6134ca feat(hotspot)!: 下线 --func-hotspot 并为 --hotspot-sites 增加每函数计时器
移除 --func-hotspot 全链路(CLI 解析与绑定、Config argparse 与注入、Translator 属性、LlvmGenerator 收口与透传、BaseGen 专属实现、Phase2Translator 透传、帮助文本);全仓已无 FuncHotspot/func-hotspot 残留引用。

通用截断逻辑保留并改名为 _InstallHotspotTruncate,供 --hotspot-sites 使用(分别清空 hotspot_sites.txt 与 hotspot_time.txt);ctor 注册改为直接新建并接收处理器列表(sites 与 time 两个处理器在同一 ctor 内注册)。

--hotspot-sites 现附带每函数计时:入口读一次 @llvm.readcyclecounter() 存起始 tick,在函数所有 ret 之前再读一次并累加差值到 internal i64 __fhs_ftime_N,同时 __fhs_ftime_enter_N 记录进入次数;单位为 tick(x86_64 即 CPU 周期),语义为 inclusive(包含内层调用)。

计时结果按耗时降序写入同目录 hotspot_time.txt(# time <module_sha1> 分段 + 函数名/累计 tick/进入次数),不改变 hotspot_sites.txt 的既有格式与字段。不传 --hotspot-sites 时零影响。
2026-09-14 13:10:06 +08:00
TermiNexus 2021c0edb7 feat(hotspot): 新增 --hotspot-sites 逐调用点计数并带源码 file:line
为匹配白名单的直接 call 点插桩 internal i64 __fhs_site_<K>(call 前 +1),计数天然包含循环内放大的真实执行次数,可把热点定位到具体调用点。

新增 --hotspot-callees 覆盖白名单、--hotspot-sites-all 全量;按去 16 位 sha1 前缀后的基名匹配。Ctrl+C 落盘独立文件 hotspot_sites.txt(# sites 分段,含调用方/被调方/计数/源码位置),按计数降序;不破坏既有 hotspot.txt 格式。

在 AST->IR 生成期由 _HotspotSiteBuilder 为每条新生成的 call 指令轻量挂载 _src_file/_src_line,插桩时作为可选尾字段输出;取不到则留空不伪造。开关关闭时改用原生 ir.IRBuilder,零影响。
2026-09-13 23:29:32 +08:00
TermiNexus 5680592f37 feat(tpc): 新增 --func-hotspot 函数热点统计,Ctrl+C 时落盘
启用后为每个函数定义生成 internal i64 计数器并在入口递增;各模块 Ctrl+C 处理器以追加方式写最终文件(含 main 的模块启动时清空一次),经 llvm.global_ctors 自注册;未传参数时零影响。
2026-09-13 17:50:01 +08:00
TermiNexus cc2f5d34eb feat(tpc): includes 只认项目配置;ASan 改为显式链接 clang64 运行库
includes 目录不再回退仓库硬编码 TransPyCRoot/includes:Phase2Translator 新增 PROJECT_INCLUDE_DIRS(INCLUDE_DIRS 置空以兼容旧引用),Config.py 从 project.vpj 的 includes 同步;HandlesImports 的模块搜索、TypeAnnotationResolver._builtins_include_dirs 一律只读项目目录。

ASan:mingw64 clang 没有 x86_64-w64-windows-gnu 目标的 ASan runtime,新增 _FindAsanRuntimeDir 定位 clang64 运行库并按 -l: 显式链接(asan_dynamic-x86_64.dll.a + runtime_thunk),定位失败即报错退出。HandlesExprFormat:i32 不再写 'l' 长度修饰符(LP64 下 printf 会按 64 位读实参)。
2026-09-11 22:47:21 +08:00
TermiNexus b02bedae9a fix(link): 为 weak/linkonce 函数与全局补 COMDAT,修复 COFF 下跨模块重复符号
COFF 下无 COMDAT 的 weak/linkonce 定义会被 llc 展开成强符号 .weak.<name>.default(weak external 实现副本)。rowptr 新一代 includes 让泛型特化(list[rowptr[AST]].__before_init__)与跨模块共享常量(PYI_BUF_SIZE)在多个模块重复定义 → ld.lld duplicate symbol。

在 Phase2Translator 三处 dso_local 后处理簇后调用 _AddWeakComdat:函数定义补 ' comdat'、全局补 ', comdat'(置于 align/section 前),并在模块头加 comdat any 声明。llc/ld.lld 端到端已验证(双 obj 同符号链接无重复报错)。
2026-09-05 12:02:48 +08:00
TermiNexus 49631ccf9b feat(linker): TPC 支持 project.vpj linker.dynamic_libs 动态链接 .dll/.so(解析为绝对路径,作为链接输入文件) 2026-09-01 22:01:18 +08:00
TermiNexus 5ba5fb5ff3 fix(linker): include 模块自动扫描支持 .no_autobuild 标记与构建目录排除
- _scan_dir_for_libs:模块目录含 .no_autobuild 时跳过 C 源编译与库文件自动发现

- 递归时跳过 build/cmake-build*/.git/__pycache__/. 开头目录

- 防止 fltk 等内嵌完整第三方源码的 include 模块被误编译
2026-09-01 20:16:34 +08:00
TermiNexus e33792a9ad feat(linker): TPC 支持 project.vpj 静态链接 .a/.obj
- Config.py 读取 linker.static_libs(相对 vpj 目录解析为绝对路径)

- Phase2Translator 新增 static_libs 参数,并入 extra_link_files 参与链接(位于 -o 之后、-l 之前)
2026-09-01 20:15:17 +08:00
TermiNexus 3b0a73db5e fix(tpc): _translate_file 以 out_path 文件名作 sha1,修复前缀漂移链接失败 - 原实现重读文件重算 sha1 覆盖 _module_sha1:主流程收集与翻译间隙文件变化时,函数定义前缀与文件名/调用方引用前缀不一致(696d41ca86e0a29a.BuildTopoSortedIndices 被生成成 5536… 前缀)→ ld.lld undefined symbol - 改为以 out_path 文件名(主流程 sha1)为准并告警内容变化,保证链接一致 2026-08-23 14:03:34 +08:00
TermiNexus 1dc23ffdde feat(tpc): llc 编译阶段日志带进度/源文件/耗时
- 用户反馈 SUCCESS: xxx.ll 只有 sha1 看不到对应源文件与进度
- 改为 '[i/N] sha1.ll  源文件相对路径 (耗时s)'(sha1_map 反查源文件,提交时刻计时含排队)
2026-08-22 08:05:19 +08:00
TermiNexus 7b04b72d4b feat(tpc): 翻译进度日志带源文件路径与耗时——并行时不再只有 sha1
- 用户反馈并行分支日志只有 -> xxx.ll(sha1 无文件名无耗时),看不到进度
- _translate_file 加计时,打印改为 '-> xxx.ll  <源文件相对路径> (Xs)'(含仅声明分支)
2026-08-22 07:41:58 +08:00
TermiNexus ebfaacf7bf fix(tpc): worker cProfile 默认禁用——环境变量 TPC_WORKER_PROF=1 开启
- 之前 getprofile 互斥检查仍冲突(用户环境仍报 Another profiling tool is already active,viztracer --log_multiprocess 场景)
- 彻底修复:cProfile 默认不启用(TPC_WORKER_PROF=1 显式开启才启用),与 viztracer 等外部 profiler 完全解耦;开启时仍有 getprofile 让位 + enable 异常兜底双保险
- 冲突根源:Python 只允许一个 profiling tool 活跃,TPC worker cProfile.enable() 检测到 viztracer 注入的 profiler 即抛错 -> worker 崩溃 -> batch 异常 -> 编译终止
2026-08-22 07:31:06 +08:00
TermiNexus c2f07e10cd fix(tpc): worker cProfile 与 viztracer 互斥——外部 profiler 活跃时跳过
- 冲突机制:viztracer --log_multiprocess 经 sys.setprofile 注入 profiler 到 worker,TPC _ProfileWorker 的 cProfile.enable() 检测到已激活 profiler 抛 'Another profiling tool is already active' -> worker 崩溃 -> batch 0 异常 -> 编译终止
- 修复:_ProfileWorker 先查 sys.getprofile(),非 None(viztracer 等外部 profiler 活跃)时跳过 cProfile 让 viztracer 独占;正常编译(无外部 profiler)仍保留 cProfile(PROF 数据不受影响)
2026-08-22 07:16:52 +08:00
TermiNexus d092b4d31f perf(tpc): 并行 worker 决策放宽——per_worker_mb 700 降至 350
- 根因:_PickWorkerCount 按可用内存/700MB 决定 worker 数,实测翻译 worker 稳态 ~110MB/峰值 ~300MB,700 过保守——可用内存稍紧即整体降级单 worker 串行(76 文件逐个翻译 1180s vs 并行 ~400s,2-3 倍波动,用户反馈编译不稳定)
- 修复:per_worker_mb 700 -> 350(留峰值余量),更多场景走并行
2026-08-22 06:54:56 +08:00
TermiNexus 567d925235 perf(tpc): PROF 热点优化——vast 节点 _Init unroll 特化 + isfile 结果缓存
- vast/Nodes.py:_MakeNodeClass 动态生成 __init__,全位置参数路径按字段
  索引直赋(unroll,去 zip 迭代器),语义与通用路径完全等价
  (PROF:_Init 158 万次 29s 最大纯 Python 热点,实测 ~1.4x)
- Phase2Translator.py:新增模块级 _CachedIsFile(编译进程内文件状态稳定),
  替换全部 os.path.isfile 存在性检查(PROF:2.6 万次 16.4s)
2026-08-22 03:08:29 +08:00
TermiNexus 12207e91d8 fix(phase2): 并行编译 worker 数按可用内存动态限制,修复内存不足 OOM
系统可用内存低(Trae CN/Java 占用后仅剩 ~1GB)时,ProcessPoolExecutor
按 cpu_count 开满 worker,多进程编译内存叠加在 StructGen.finalize 拼接
module IR 时 MemoryError(编译 StubMergerTopo.vp 报错即此)。新增
_PickWorkerCount:GlobalMemoryStatusEx 读 ullAvailPhys,按 per_worker_mb
估算 worker 上限(翻译 700MB / llc 400MB),内存不足自动降为单 worker
串行,内存充足回落 cpu_count。StructGen.finalize 拼接改中间变量拆分,
降低单 worker 峰值副本。
2026-08-21 09:04:40 +08:00
TermiNexus 0db1ccd1bb refactor(asan): TPC_ASAN 环境变量改 args 直传
--asan 不再写 TPC_ASAN 环境变量,改为 Config 解析后直接经
asan_mode=args.asan 传给 Phase2Translator(主进程 .ll→.obj 插桩与
链接 -fsanitize=address 均读 self.asan_mode),消除环境变量在
worker 子进程/外部调用链下的不可靠性。
2026-08-19 08:47:32 +08:00
TermiNexus fbd132284b perf(phase2): 按 PROF 热点优化编译耗时
- HandlesImports: _TryLoadClassMembersFromPyi 复用 _pyi_cache 跳过重复 isfile(-12.8s);_LookupStubFuncType 类级缓存 + 签名增量扫描新增 stub,去掉每文件 isfile(-6.5s+)
- Phase2Translator: pyi cache 仅主进程构建(worker 只读 pkl,-23s+pickle 10.4s);include 源文件 sha1/存在性缓存消除 _build_current_ModuleSha1Map 重复磁盘 I/O
- StructGen.finalize: 行过滤改 startswith(tuple) 预计算,消除 O(lines×structs×patterns) 嵌套循环(tottime 84.8s → 预期数秒)
- 附带 fail-fast(任意文件出错立即终止)+ 子进程 PROF 硬编码
2026-08-19 00:28:40 +08:00
TermiNexus 6613542d8e perf(compile): pyi 缓存落盘改增量构建,Phase2 新增 vpi 不再全量重建
- _BuildPyiCacheFile 原每次签名变化(Phase2 过程新增 include .vpi)都全量 ast.parse 所有 vpi(prof 43 次 × 0.28s = 12.2s)
- 增量:加载旧 pkl,按 (basename, size, mtime) 复用未变化文件的 vast 树,只 parse 新增/变化文件
- 验证:147 个 vpi 新增 1 文件时仅 0.006s(原全量需数秒);无旧 pkl 时自然退化为全量
2026-08-18 07:27:02 +08:00
TermiNexus e3886a244d perf(compile): 批次加权分桶消除长尾 + 共享符号表去重复序列化 + typedef 收集走 AST 缓存
- Phase2 批次切分:原按文件数均分(batch_size=ceil(N/n)),大文件集中批次拖长尾、worker 空等;改为按源文件大小 LPT 贪心分桶,各批次总成本均匀(任务颗粒度不均匀)
- 共享符号表序列化:shared_data 同时含 symbol_table 对象与 symbol_table_bytes 双重序列化(_shared_sym.json 4.65MB 近半冗余);统一为仅传 symbol_table_bytes,worker/批次端从字节反序列化(includes 与 App 两阶段同步修改)
- Phase1 _collect_typedef_map / _process_file_pyi:直读+ast.parse 改为 parse_python_file mtime AST 缓存,Phase1 内重复收集与 Phase2 主进程解析共享同一缓存
2026-08-18 05:36:12 +08:00
TermiNexus b760082be8 perf(compile): pyi 树 pickle 落盘 + worker initializer 预热,消除进程间重复 parse
43 个 worker 任务分 ~16 个 spawn 进程,每进程重新 parse 全部依赖
.vpi(4479 次 vast.parse、245s)。主进程把 temp 下全部 .vpi 的 vast
AST 树 pickle 落盘 temp/_pyi_cache_v1.pkl(签名=(名,size,mtime),
变化才重建),两处 ProcessPoolExecutor 加 initializer 预热 ImportHandle
类级 _pyi_cache(优先 pickle.load,失败回退逐文件 parse)。
TPC_WORKER_WARMUP=0 可关闭对比。预计进程内首次解析尖峰降为一次 load。
2026-08-17 23:27:44 +08:00
TermiNexus 50c0703afd feat(profiling): worker 进程导出 cProfile——TPC_WORKER_PROF 环境变量开关
主进程 cProfile 只能看到进程池等待(WaitForMultipleObjects/as_completed
约 280s),看不到 worker 进程内部 CPU 分布(vast parse 等真实热点)。
新增 _ProfileWorker 装饰器包裹 _parallel_translate_worker 与
_parallel_translate_batch:设置环境变量 TPC_WORKER_PROF 为输出目录时,
每个任务导出 worker_prof_{pid}_{seq}.prof(可用 pstats 合并分析);
未设置时零开销(原样返回函数)。
2026-08-17 22:42:14 +08:00
TermiNexus c2b04f5026 fix(compile): _LoadSha1Map 缓存补充只加载当前编译有效 sha1,修 9026a429f5e2d0e0.new_builder undefined symbol
.transpyc_cache 残留旧版 llvmlite/__builder.vp 的 9026a429f5e2d0e0.pyi/
.stub.ll(当前版本是 d9b3d06934cd1898)。_LoadSha1Map 从全局缓存补充
temp 缺失文件时不检查 sha1 有效性,把旧版 .vpi/.stub.ll 也加载进
sig_files/stub_files → 同名类 IRBuilder 按旧 sha1 前缀注册 →
new_builder 用 9026a429f5e2d0e0 前缀拼接,链接 undefined symbol。
补充逻辑移到 sha1_map 加载之后,仅补充 sha1_map 中存在的 sha1。
2026-08-17 21:51:21 +08:00
TermiNexus ecdb5c34c5 Revert "refactor(compile): 完全去除多进程,翻译/编译全部改顺序阻塞执行"
This reverts commit 15e8bc7c7d.
2026-08-17 20:28:24 +08:00
TermiNexus 15e8bc7c7d refactor(compile): 完全去除多进程,翻译/编译全部改顺序阻塞执行
ProcessPoolExecutor 批次/波次子任务模型导致跨模块 struct 类型前缀错位
(7cadfe07e983fd90.Translator != 6ccfee1e5bd522ed.Translator,见 1.log),
且 cProfile 墙钟被进程池等待支配(223s 中 173s 耗在 WaitForMultipleObjects)。
删除 _parallel_translate_worker/_parallel_translate_batch、_executor_pool
及两处 llc ThreadPoolExecutor,App/includes 翻译按依赖拓扑顺序阻塞翻译,
llc 编译逐文件阻塞执行,消除 pickle 序列化共享符号表与进程池等待开销。
2026-08-17 20:22:45 +08:00
TermiNexus f66e119d1f perf(compile): App 翻译改批次子任务模型(多文件/任务 + 每文件重置 SymbolTable)
原"一文件一任务":200+ 文件每个都经 ProcessPool 调度 + worker 内创建 Phase2Translator + pickle.load 全部共享数据。改为批次模型:need_translate 按 worker 数分块,每 worker 一个批次子任务——Phase2Translator 创建 + pickle.load 仅一次,批内顺序翻译。

防污染:SymbolTable 是编译期唯一被写的共享对象,dump 时额外存 symbol_table_bytes(独立 pickle),批内每文件前 pickle.loads 出干净副本,前文件 import 写入不残留后文件(避免 7cadfe07e983fd90 类前缀错位)。includes 阶段保持拓扑单文件任务不变。
2026-08-17 20:01:33 +08:00
TermiNexus a28aacda0b fix(compile): 回退 worker 进程级复用,消除共享 SymbolTable 跨文件污染
复用后同一 worker 的 trans 处理多文件,_translate_file 编译过程会向共享 SymbolTable 写入符号(import insert/类注册),前文件符号污染后文件 → 跨模块 struct 类型前缀错位(7cadfe07e983fd90 即 _list 前缀混入 CompilerFactory/Translator/File,Type of #1 arg mismatch)。每任务从 pickle 反序列化独立副本(原实现)。

收益评估:worker 复用仅省 pickle.load ~0.5s/次 × 每 worker 12 次 ≈ 6s 并行墙钟,远小于 worker 内翻译计算(百秒级),不值得以正确性为代价。n_workers 满核优化保留。
2026-08-17 19:58:28 +08:00
TermiNexus 3aebf402bb perf(compile): worker 进程级复用 Phase2Translator,消除每文件重复 pickle.load
cProfile 显示 ~163s 墙钟在 ProcessPool 等待(非计算)。App 阶段 200+ 文件分散到 worker,原实现每个任务都新建 Phase2Translator 并 pickle.load 2.5MB 共享符号表(_shared_sym.json)→ 每 worker 12+ 次重复反序列化。

- _parallel_translate_worker 增加进程级缓存:以 shared_sym_pickle_path 为 key,首次遇到才创建 trans + 加载 pickle,后续任务直接复用 trans._translate_file
- _translate_file 每次新建内部 TransPyC 且对 self 的写均为覆盖型(translator 引用/错误栈),复用安全
- App/includes 两阶段 pickle 路径不同,key 变化时每 worker 各自重建一次
2026-08-17 19:04:22 +08:00
TermiNexus 58ce673f01 perf(compile): TPC 编译提速——并行 worker 满核 + vast 解析器热点优化
cProfile 分析(206s 全量重编译 TPV):~163s 为 ProcessPool 等待(16 核机器仅用 8 worker),vast.parse 35.9s(1231 次)为最大 Python 计算热点。

- Phase2Translator:4 处 n_workers 上限 8 → os.cpu_count()(16 核满负荷),并行翻译/llc 编译利用率翻倍
- vast/Tokenizer._PosInfo:isascii 快速路径 + 行索引增量查找(~300 万次调用,免每次 bisect+encode)
- vast/Tokenizer._EmitOp:运算符按首字符分组,58 万次调用从 42 项全表 startswith 降到 2-3 项
- vast/Tokenizer._ScanName:内联 _IsIdentPart(70 万次循环免函数调用)
- Projectrans/Utils:find_reachable 用 deque + 后缀索引替代 pop(0)/全表扫描;topological_sort 用反向邻接表 + heapq 替代每轮 sort+全图扫描
2026-08-17 18:56:55 +08:00
TermiNexus 6fc9e19e24 feat(vast): 新增自研 Viper/Python 语法解析器取代标准库 ast
TPC 侧取缔对 Python 标准库 ast 模块的依赖,改用 lib/vast 包:
- Nodes: 与 CPython 3.12 ast 完全同构的 131 个节点类(含抽象基类继承)
- Tokenizer: 词法分析(缩进/字符串/f-string/数字/运算符/软关键字)
- ExprParser: 表达式递归下降解析(优先级/lambda/推导式/f-string/切片)
- Parser: 语句解析(def/class/if/for/try/with/match/import/注解)
- Utils/Unparser: walk/dump/unparse/copy_location/literal_eval 等辅助
- 软关键字 fn/fun/func/function 并入解析器, 废除 ExpandSoftKeywords 预处理
- lib/_bootstrap 将 lib 目录加入 sys.path, import vast as ast 零修改替换
- 52 个文件 import ast 替换为 import vast as ast; 94 文件差分测试 0 失败
2026-08-17 09:36:38 +08:00
TermiNexus 9b190ac73e fix(TPC): --asan 假生效修复 —— opt -passes=asan 需先 forceattrs 加 sanitize_address 属性(LLVM>=20 只插桩带属性函数) 2026-08-15 13:25:12 +08:00
TermiNexus d2d319eb21 fix(includes): ASan 集成支持 + 越界写封堵 + TypePrint 类型名截断 40→255
1. Phase2Translator 增加 TPC_ASAN 支持(opt asan 插桩+链接 -fsanitize=address),配合 clang64 定位 0xbe 崩溃。2. llvmlite/memhub/viperio/viperlib 多处理无界 strcpy/strcat/下溢/递归守卫/栈数组钳制。3. memhub alloc 块尾 canary(MEMBUDDY_CANARY)+check_alive_blocks 校验+chk_stack realloc 扩容。4. TypePrint Ptr(Struct) 类型名截断上限 40→255:含 sha1 前缀类型名(如 bbdf3bbd4c3bc28c.CONSOLE_SCREEN_BUFFER_INFO=42)被截断产生未定义类型引用(llc undefined type)。
2026-08-10 18:09:13 +08:00
TermiNexus cfc30d735c 将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名 2026-07-30 16:33:56 +08:00
TermiNexus 3633be1995 Some simple information syncing 2026-07-28 21:08:58 +08:00
TermiNexus 1837339f69 修正了一些错误 2026-07-26 20:32:26 +08:00
TermiNexus ca7c2120b8 修正了种子编译器的错误 2026-07-22 21:55:36 +08:00
t 796222a300 snapshot before regression test 2026-07-18 19:25:40 +08:00