Commit Graph
64 Commits
Author SHA1 Message Date
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 5d1620505e fix(decl): 声明端看穿「装饰器标记 + 裸类引用」联合,修 t.CExtern|X|t.CPtr 多外包一层指针
根因:vpi 记录的模块级全局是 `_mbuddy: t.CExtern | memhub.MemBuddy | t.CPtr` 形态,_get_type_str 把该联合展开为 %"sha1.MemBuddy"*(标记 t.CExtern 展开为空串,已被 BinOp 分支丢弃),但外层 | t.CPtr 走 _is_bare_class_ref_annotation 时对 ast.BinOp 一律 return False ⇒ 未吸收"裸类引用自身即指针"那一层 ⇒ 声明端 %X** 与定义端 %X* 差一层。

后果:Phase1 生成的 .stub.ll 声明 @_mbuddy = external global %X**,消费模块按下声明取值得到 %X**,赋给 %X* 字段(VLogger.vp:105 self.__mbuddy__ = _mbuddy)即报"指针隐式转换已禁止(层数不同)"。

修法:BinOp 分支内若恰一侧展开为空/void(纯装饰器标记 CExtern/CExport/State/CStatic...)则按另一侧递归判定,对齐 TPV TypeGenResolve.vp:2596 第 3 条语义「ActualType | DecoratorMarker → ActualType」(TPV 无此问题,故只改 TPC)。

探针验证:t.CExtern|X|t.CPtr / X|None|t.CPtr / t.State|X|t.CPtr → %X*(修正);X|t.CPtr、rawptr[X]|t.CPtr → %X**、bytes|t.CPtr → i8**、int|t.CPtr → i32*(均不变)。注意 .stub.ll 有全局缓存,需 --clear-cache 重编生效。
2026-09-28 16:35:53 +08:00
TermiNexus 35de6321f6 refactor(return): 移除 @c.CReturn 多返回值处理器,只保留 -> tuple[ty1, ty2, ...],遇到 CReturn 一律报错
DeclarationGenerator:tuple[...] 分支逐字保留(仅 CReturnTypes 机械改名 MultiRetTypes),装饰器分支改为 SyntaxError,报文含函数名与“请改用 -> tuple[ty1, ty2, ...]”提示

HandlesAssign(a, b = f() 解包路径):删除装饰器收集分支并改为报错;tuple[...] 恢复与逐个解包逻辑逐字不变

HandlesFunctions:新增 _CRETURN_REMOVED_HINT 与 _RejectCReturnDecorator,在函数定义入口(_GetFunctionSignatureLlvm / _EmitFunctionLlvm)fail-fast——即使只有装饰器、没有 -> 注解,也不会让返回类型静默退化成 i32

HandlesImports:外部函数声明处同样报错,并删除下游已失效的 CReturnTypes 参数拼接死代码

HandlesReturn / HandlesFor / BaseTranslator:CurrentCReturnTypes 等机械改名(读写端一致,无行为变化)

includes/c.py:保留 CReturn 名字作墓碑(删掉会让 @c.CReturn 变成未知属性、可能被静默忽略),docstring 写明已移除并指路 -> tuple[...];README 措辞同步
2026-09-28 13:57:04 +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 2cc816ac13 修复了一些错误 2026-09-18 20:00:59 +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 8d950f5d43 fix(declgen): 联合中 t.CPtr[T] 下标段按 Ptr^N 叠加,与 LLVMTypeMapper 口径对齐
_get_type_str 的 BinOp 段原先在右段非 i8* 时落到 星号在左值则直接返回左值 的启发式,左值已是指针(BYTEPTR=>i8*)时会吞掉右段层数(BYTEPTR | t.CPtr[t.CPtr] 得 i8*,Mapper 得 i8***,同份 stub 自相矛盾)

新增 t.CPtr[T] 分支(两侧对称,置于该启发式之前),复用文件内既有 _ptr_level_of 取层数并按定义侧 TypeGenResolve 口径改为纯外包 N 层(去掉原 struct 吸收半截语义);LLVM 聚合左值显式排除。A/B 实测 135 个 .pyi 输出逐字节相同,现有语料零影响
2026-09-16 07:11:23 +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 84d91d53e5 perf(hotspot): 计时串行化并改为自身耗时(exclusive)统计
--hotspot-sites 的每函数计时原为裸 rdtsc 的 inclusive 耗时,导致 _parse_* 一条调用链各项数值几乎相同、无法定位自身成本,且短函数测量不可信。

新增 _EmitReadTimestamp:x86_64 用 lfence 加 readcyclecounter 串行化读(业界通行的 lfence;rdtsc),非 x86_64 编译期降级为裸 readcyclecounter;入口与每个 ret 前共用。选 intrinsic 组合而非内联汇编,避免约束串转义与渲染风险。

用深度栈实现自身耗时:全局 __fhs_tdepth 与 [512 x i64] __fhs_tstart/__fhs_tchild,self = inc 减去本帧内被插桩子调用 inc 之和;递归靠每调用独立 slot 与深度索引天然正确;深度溢出或终结指令非 ret 的块明确跳过不记账(仅计进入次数),不伪造数值。入口段用 select 而非条件分支,避免改动 CFG。

hotspot_time.txt 行为 函数名 self inc 进入次数(仍按 self 降序),段头注明单位 tick 与 self 口径;hotspot_sites.txt 格式保持不变;帮助文本同步更新。未插桩的被调方(含 libc)耗时计入调用者 self,属该方法固有性质并已注明。
2026-09-14 13:42:14 +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 015fbf17cf fix(tpc): 跨模块模块级变量类登记与 Mod.Var.Field 链解析;并停止跟踪 __pycache__/*.pyc 2026-09-12 11:51:42 +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 a433f79f54 基线重置,TransPyC 不再作为直接脚手架主仓库 2026-09-09 14:44:44 +08:00
TermiNexus 45e78ad107 基线重置,修复了一些 bug 2026-09-07 14:46:02 +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 2f0d52e736 fix(gentype): list[t.CPtr] 特化与 list[对象] elem_size 根本修复
两处根因:
1. list[t.CPtr] 报 Undefined method 'append':
   - _resolve_generic_slice_type 对 t.CPtr 返回裸名 'CPtr',type_map['T']='CPtr'
     替换进模板(item: CPtr)后 CPtr 不在顶层作用域 → append 声明注册失败
   - 改保留带前缀 't.CPtr'(可解析)
   - 查找端(SymbolUtils.FindStructNameInAnnotation)与声明端
     (DeclarationGenerator)的 CPtr 统一规范化为 'ptr',与特化端
     _mangle_generic_class_name 一致(list[CPtr]/list[i8*] vs list[ptr])
   - _specialize_generic_class 的 cptr_params/class_type_names 判定改 tn_bare
2. list[对象] elem_size=0(get(0)==get(1) 同槽根因):
   - T.__sizeof__() 特化后为 'X | t.CPtr'(BinOp 联合),_HandleSizeofLlvm
     对 BinOp 落到 else 返回 0 → list.__elem_size__=0 → 元素全写同槽
   - 改含 t.CPtr 的联合类型返回 8(指针大小)
2026-08-19 22:44:15 +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 1808e90fd3 feat(projectrans): 主进程 PROF 自动落盘 + 编译耗时统计 + 分析脚本升级
- Projectrans.py 入口包 cProfile,整次编译自动导出 main_prof_{pid}.prof 到 ./PROF;成功/失败均输出 [TIMING] 总耗时(stderr)并落盘 main_time.txt
- Config.py 新增 --asan(透传 TPC_ASAN=1)+ 每次编译自动清理 PROF 目录 *.prof
- PROF/1.py 升级为综合报告(tottime/cumtime top + callers 定位 + 模块聚合 + 上次编译耗时)
2026-08-19 00:28:18 +08:00
TermiNexus 7c6a497111 fix(DeclarationGenerator): 按自有字段展平时补齐祖先 vtable 指针
_FlattenInheritedDecl 递归只取类自有字段,而原 _get_inherited_members 返回完整 struct 天然含 vtable。改造后 Module(AST CVTable) 等子类 struct 缺 vtable 指针 → 字段错位 → 编译报 'cannot store i8* to %AST**'(写 vtable 到 parent 槽位)。新增 _ShouldEmitOwnVtablePtr 判定,递归各祖先类时在自有字段前补齐 vtable。
2026-08-18 13:19:51 +08:00
TermiNexus 81ad712475 fix(Handles): 多继承字段展平按继承源去重,消除菱形重复
Generator 同时继承 ClassGenMixin/ClassGenEnum/ClassGenGeneric/ClassGenVTable/ClassGenDef/ClassGenBase,而前 5 个都继承 ClassGenBase → ClassGenBase 41 字段被重复展平 6 次(struct 707 元素),class_members 索引与 struct 布局错位 → 跨 Mixin 方法 this_adjust 失效 → is_exception_name 读错位内存 strcmp 越界(ASAN heap-buffer-overflow)。

修复:HandlesClassDef 与 DeclarationGenerator 的多继承展平改为递归按继承源去重(每类只展平一次,只取自有字段;同名字段如 TempDir 跨非继承 Mixin 仍各自保留,避免 2026-08-10 历史去重缺陷回归)。
2026-08-18 13:13:25 +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 3326c41702 perf(compile): 依赖扫描缓存键 abspath 归一化 + compute_sha1 缓存
parse_python_file/get_file_dependencies 缓存键改用 abspath 归一化:
同一文件以相对/绝对、正斜杠/反斜杠/含 .. 等形式传入会产生多条缓存
条目导致重复 open+read+ast.parse(439 次 get_file_dependencies 25.2s、
1496 次 parse 33.1s 的浪费来源)。compute_sha1 加有界结果缓存。
验证:同文件 4 种路径形式缓存合并为 1 条,find_reachable 二次调用
显著加速,相对导入解析结果不变。
2026-08-17 22:20:29 +08:00
TermiNexus 5692e9b097 perf(stubgen): pyi 转换加缓存——convert 纯函数缓存 + Phase1 mtime 缓存
Converter.convert 147 次调用 45s、_process_file_pyi 98 次 50s。convert
按 (内容, 模块名) 纯函数缓存并合并内部两次 ast.parse;Phase1 按
(绝对路径, 模块名)+mtime+size 缓存 pyi 转换结果与 docstrings,未变化
跳过 open+read+parse。缓存上限 4096 条防内存膨胀,配置变更时清空。
2026-08-17 22:20:28 +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