diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index c8009f6..8cc6cbf 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -1099,8 +1099,10 @@ class BaseGenMixin: tick(x86_64 上即一个 CPU 周期,~0.3ns 量级),故耗时单位记为 tick。 exclusive(自身耗时)算法——深度栈: - - 全局 internal i64 __fhs_tdepth:当前插桩深度,初值 0; - - 全局 internal [DEPTH x i64] __fhs_tstart / __fhs_tchild(零初始化, + - 全局 common i64 __fhs_tdepth:当前插桩深度,初值 0;common linkage 让每个 + 翻译单元各自发射同名 tentative 定义、由链接器合并为**全程序唯一一份**, + 故跨模块调用也共用同一张深度栈(独立翻译单元链接不产生重复符号)。 + - 全局 common [DEPTH x i64] __fhs_tstart / __fhs_tchild(零初始化, DEPTH = _HotspotDepth = 512):按深度索引的"本帧起始 tick"与"本帧内被 插桩子调用 inclusive 之和";另有一个 internal i64 抖动槽 __fhs_tscratch, 用于把"不应记账"的写入导向一个永不读取的位置(等价于不写,但不分支)。 @@ -1136,10 +1138,14 @@ class BaseGenMixin: 函数如 strcmp/memcpy、名字以 __fhs_ 开头的辅助函数、深度溢出而跳过的调用) 其耗时不会被本方法从调用者 self 中扣除,一律计入**调用者自身 self**。故 self 是"该函数自身指令 + 未插桩子调用"的墙钟时间,只是比 inc 更贴近自身成本。 + 深度栈为 common(全程序一份)后,跨模块被调方只要被插桩即能正确扣除;修复前 + 各模块各持一份 internal 深度栈,跨模块子调用的 inc 记不进调用方 tchild, + 表现为调用方 self ≈ inc 的假象(见 common linkage 说明)。 插桩规则与跳过条件: - - 只处理有基本块(即已定义)且名字不以 __fhs_ 开头的函数;计数器/深度栈 - 一律 internal,跨模块(独立翻译单元)链接不产生重复符号,初值 0。 + - 只处理有基本块(即已定义)且名字不以 __fhs_ 开头的函数;每函数计数器一律 + internal(同名索引跨模块并存,不可合并);深度栈用 common 由链接器合并为 + 全程序唯一一份,初值 0。 - 入口代码置于入口块最前(无终结指令,不改变 CFG);条件写入用 select 实现, 不新增基本块、不修改任何既有分支/终结指令。 - 只在该函数的 ret 终结指令之前插桩;以 unreachable 等其它终结指令结尾的 @@ -1154,18 +1160,24 @@ class BaseGenMixin: c0_64: ir.Constant = ir.Constant(i64, 0) c1_64: ir.Constant = ir.Constant(i64, 1) cneg1_64: ir.Constant = ir.Constant(i64, -1) + # 深度栈三件套用 common linkage:每模块各自发射一份同名 tentative 定义, + # 由链接器合并成"全程序唯一一份"(与 HandlesAssign 中多模块同名全局同法, + # 避免 ld.lld duplicate symbol)。跨模块调用链必须共用同一张深度栈,否则 + # 被调方在自模块栈里 slot=0(或 slot 落在错误父帧)→ 其 inc 永远记不到 + # 调用方 __fhs_tchild[slot-1] → 调用方 self ≈ inc(子时间一分不扣)。 + # 抖动槽 __fhs_tscratch 只写不读,留 internal 即可(各模块独立无影响)。 depth_gv: ir.GlobalVariable = ir.GlobalVariable( self.module, i64, name=self._UniqueGlobalName('__fhs_tdepth')) - depth_gv.linkage = 'internal' + depth_gv.linkage = 'common' depth_gv.initializer = c0_64 arr_ty: ir.ArrayType = ir.ArrayType(i64, depth) tstart_gv: ir.GlobalVariable = ir.GlobalVariable( self.module, arr_ty, name=self._UniqueGlobalName('__fhs_tstart')) - tstart_gv.linkage = 'internal' + tstart_gv.linkage = 'common' tstart_gv.initializer = ir.Constant(arr_ty, None) tchild_gv: ir.GlobalVariable = ir.GlobalVariable( self.module, arr_ty, name=self._UniqueGlobalName('__fhs_tchild')) - tchild_gv.linkage = 'internal' + tchild_gv.linkage = 'common' tchild_gv.initializer = ir.Constant(arr_ty, None) scratch_gv: ir.GlobalVariable = ir.GlobalVariable( self.module, i64, name=self._UniqueGlobalName('__fhs_tscratch'))