相较上一版 Jacobian 确定性复用更新,本次补齐事件边界一致性、结果两侧采样及接触事件定位;保留已有物性复用和组件力学公式。 - 统一 UD00 信号求值与下一事件查询的绝对时间边界,修复循环边界浮点舍入导致的阶段错位、重复或漏报,并覆盖零时长、多阶段及长周期场景。 - 引入原生输出语义 v2:保留规则网格真实时间,补充内部时间事件和状态事件的左邻及事件后采样,按保存时间、状态和离散模式重放结果。 - 两条代码生成路径均发出 LSTP 接触描述,默认定位间隙过零及非负力模式的力截断;仅在接受事件时更新防重复记录,增加 contactEvents 诊断计数。 - 补充 MASS/LSTP 独立事件实验、八路全曲线与驱动阶段配对评估,以及 Amesim 不连续点输出对照和力差定位报告;MASS 新增释放机制仍保留为独立实验。 - 保存局部 probe、context 访问与回退、shadow replay、R288 real skip/typed replay 及阀门数值尾部诊断工具和报告;未证明净收益的实验不启用为生产默认优化。 - 更新原生运行说明和元件建模规范,补充信号边界、输出语义、接触事件和实验依赖回归测试。 验证:五组专项回归共 34 项全部通过;37 个待提交 Python 文件语法检查通过;git diff --cached --check 通过。
16 KiB
position379:state_valve 数值尾部诊断
日期:2026-09-17。仅针对既有八路模型 0–10 s 轨迹中,Jacobian baseline/probe 实际执行的 position379 / PNVO001_1.port_2。没有改生产路径,没有研究其他 position,没有实现真实 memo skip。
四个问题的答案
- 尾部典型单次约0.618 µs。 在不做前置lookup/FP采样的三轮计时对照中,逐次中位数为0.611–0.628 µs;每轮均值为0.692–0.918 µs,均值的跨轮中位数0.803 µs。均值含调度长尾,不能当作纯CPU指令时间。该数值来自本次尾部计时,不是此前0.783 µs的state_valve exclusive。
- 完整数值key重复率84.615%。 每个Jacobian有5种key,22个probe与baseline逐位相同;全轨迹理论命中19,712/23,296。包含完整x87状态字保护后,本次“无FP状态变化才可直接返回”的候选只允许8,734次,即37.491%。
- 当前严格候选未达到完整机制break-even。 五轮hit lookup均值0.152–0.475 µs,baseline新增2.088–6.619 µs/J;全部miss成本也必须计入。两轮相对平稳的配对数据要求hit成本低于0.109/0.074 µs,实测分别为0.152/0.153 µs。五轮诊断净预算全部为负,−0.367至−8.269 ms/轨迹,中位数−2.341 ms。
- 不进入真实实现阶段,停止该方向。 数值key确实重复,但当前候选没有证明在保留完整FP语义后能获得净收益。这不证明任何kernel memo都不可能盈利;它说明本轮没有满足启动真实实现的门槛。没有通过忽略x87状态、过滤慢样本或扩大position范围来改变结论。
1. 源码边界与准确输入
依据归档 properties.c 第266–277行和 orifice.c 的 native_medium_orifice_context。使用与既有fallback诊断相同的归档worker,保证比较对象一致;这不是对工作区后来其他改动重新建模。
A. 必须保留的context/property行为
调用链:native_medium_orifice_context → native_temperature_ph_context → medium_valve → property_pt → state_valve。在state_valve内,以下语句及其子调用均原样执行:
double p=up->p,T=up->T;
pd=fmax(fmin(pd,p),0);
const NativeMedium *m=&up->medium;
double cp=m->cp+m->slope*(T-m->Tref);
double factor=m->real_helium?isentropic(cache,up,pd):(cp-m->R)/cp;
double g=fmax(1e-9,fmin(1-1e-9,factor));
double rho=fmax(property_density(up),1e-12);
这包括PH/PT查询、首次匹配、entry创建、count/valid变化、上游和下游等熵准备、density获取及温度observer行为。orifice后续的q计算、方向/opening处理、有限性检查和返回值仍执行。目标调用是orifice,没有额外跳过任何pipe逻辑;整个求解中的其他pipe/context路径保持原执行。
B. 已有memo/valid覆盖的工作
local_isentropic先观察温度,valid命中才直接返回;不能把观察和valid语义一起memo掉。property_density、PH context获取中的已有缓存/Jacobian scalar memo继续工作。- 先前fallback函数统计中,昂贵PH反算、密度求解、pipe resistance求根实际调用为0;本轮不把它们当作新可省工作。
C. 本次计时的数值尾部
起点:原源码第272行 double r=...;终点:第276行平滑修正完成。 subsonic_cm 的调用也计入该尾部。
double r=fmax(pd/p,0),critical=pow(2*g/(g+1),1/(1-g)),eff;
if(r<=critical) {
eff=critical;
*cm=sqrt(2/(1+g)*rho*T/p)*pow(2*g/(g+1),g/(1-g));
*vel=sqrt(2/(1+g)*p/rho);
} else {
eff=r;
*cm=subsonic_cm(r,g,rho,T,p);
*vel=sqrt(fmax(2/(1-g)*p/rho*(1-pow(r,1-g)),0));
}
double ref=subsonic_cm(.9999,g,rho,T,p);
if(*cm>0 && ref>0) {
double smooth=tanh(fmax(12*fabs(*cm/ref)*log(eff)/log(.9999),0));
*cm*=smooth; *vel*=smooth;
}
- 完整数值输入:
p, T, pd, g, rho,五个double的原始位,共40 B。pd已经限幅,g和rho已经完成上述准备/限幅。不能用原operation的p/h/opening作为替代key。 - 数值输出:
cm, vel,两个double原始位。 - 不再读取medium、entry、valid、count或pipe,不写property context;原输出指针的既有值不是尾部输入,两条分支均先写cm/vel。
- 这只表示“数值计算不依赖context”,不表示没有机器浮点状态副作用。数学库和x87运算会改变部分状态字位,因此不能把整个state_valve或这个尾部无条件当作可直接缓存返回的纯函数。
2. 诊断方法
独立worker复制既有local probe实现,只在目标position设置诊断scope;普通residual及其他position不进入记录。原whole-context guard及其成功恢复路径保留。
- 每次目标尾部仍执行一次原数学代码。诊断lookup只把可能的缓存结果写到临时记录,不用于operation输出,没有真实skip,也没有双路Reference执行。
- 使用invariant TSC,
lfence/rdtsc/lfence,全轨迹对QPC校准;原编译参数仍为O3、禁止fast-math与FP contraction。两端标记包围原尾部,没有循环重复同一个热key来替代实际轨迹。 - 所有详细记录先写预分配内存,积分结束后写盘;单记录128 B。候选baseline记录仅72 B:40 B key、16 B输出、12 B环境、4 B ready。
- 五轮完整诊断,同时直接测K、候选hit/miss lookup、baseline key/环境准备、结果捕获及每Jacobian重置。G包含外层调用、key构造、环境读取、完整比较及写回临时结果,不只测memcmp。
- 另三轮 K-only 对照:尾部之前只放计时标记,key/环境采样全部移到尾部之后。这三轮的环境不是入口环境,其hits/G/H字段不参与任何命中率或盈利判断。
- 原始单次均值、中位数和min/max全部保留,没有剔除抢占/缺页长尾。空标记中位约12–14 ns;预算只从可省K中扣除空标记,G/H保留原始计时,避免把微小收益做大。
归档初版构建与交付诊断版本的 model.o、properties.o、valve_tail_diag.o 字节一致;清理仅移除了未启用的预留接口,没有引入真实skip版本。
已检查两版 state_valve 目标码控制流:density/g准备先于起始标记,pd/p、critical及尾部数学调用位于计时范围内,输出写入完成后才取结束标记。汇编分别保存在构建目录的 state-valve.asm。
3. 全轨迹进入次数与尾部时间
所有轮次都完成896个Jacobian。目标物理operation进入和尾部执行次数均为 24,192:
| 类别 | 次数 |
|---|---|
| baseline | 896 |
| probe group0–25 | 23,296 |
| group26 | 0:已有whole-context复用使目标operation未执行 |
| 真实skip | 0 |
分母是Jacobian内实际执行的目标probe,不含普通residual,也不把group26已有的复用计成新memo收益。
K-only低扰动对照(每轮24,192次)
| 轮次 | 均值µs | 单次中位µs | 单次min–max µs | 原始累计ms | 扣空标记均值µs |
|---|---|---|---|---|---|
| tail-only-0 | 0.803447 | 0.610863 | 0.377976–3595.053 | 19.436981 | 0.791542 |
| tail-only-1 | 0.691729 | 0.617559 | 0.369792–459.269 | 16.734302 | 0.679824 |
| tail-only-2 | 0.917657 | 0.627976 | 0.369047–3031.652 | 22.199961 | 0.904264 |
三轮逐次中位数的中位数 0.617559µs,每轮均值的中位数 0.803447µs,累计时间中位数 19.436981ms。数千µs的max明显混有系统调度长尾,不代表一次数学计算通常要这么久;这些样本没有被删除。
与G/H同时采集的五轮K(盈亏使用同轮配对数据)
| 轮次 | 均值µs | 单次中位µs | 单次min–max µs | 原始累计ms |
|---|---|---|---|---|
| diagnostic-0 | 0.600212 | 0.575893 | 0.360863–33.676 | 14.520341 |
| diagnostic-1 | 0.759084 | 0.680059 | 0.396577–201.298 | 18.363768 |
| diagnostic-2 | 0.843411 | 0.677083 | 0.367559–1362.520 | 20.403801 |
| diagnostic-3 | 1.176682 | 0.691964 | 0.368303–8174.892 | 28.466296 |
| diagnostic-4 | 0.642986 | 0.577381 | 0.416666–243.518 | 15.555124 |
这些结果支持尾部是亚微秒级计算,不能支持“所有测得墙钟长尾都可通过memo省掉”。K-only与完整诊断的批次/代码布局不同,不跨轮拿最贵K减最便宜G来拼净收益。
4. 完整数值bit-key的真实重复率
每个Jacobian的27次物理进入(1 baseline + 26 probes)均有 5种不同key:
- baseline与 group0–5、10–25 共用同一key;每Jacobian22次重复。
- group6、7、8、9各有一个不同key,彼此及baseline不同。
- 896个Jacobian全部如此;baseline-only单槽候选已经覆盖所有数值重复,增加多条probe memo不会再增加理论hit。
| 统计 | 结果 |
|---|---|
| 理论memo hit | 19,712 |
| 理论probe miss | 3,584 |
| 数值key hit rate | 19,712 / 23,296 = 84.6153846% |
| 相同key的cm/vel逐位不同 | 0 |
| 各组与baseline相同次数 | 上述22组分别896次 |
每个Jacobian的baseline完整十六进制key、各组key和分组关系。其他四轮也各自保存清单和原始记录,并得到相同分组计数。
数值重复不等于可以直接返回
本次读取:errno、MXCSR全寄存器、x87 control word、x87 status word。尾部前后:
- errno、MXCSR、x87 control word变化次数均为0。
- x87 status word变化13,374次,其中baseline变化499/896次。
- 变化位是x87条件状态位,例如
0x120 → 0x320和0x320 → 0x120;本轨迹没有观察到标准浮点异常标志或舍入控制变化。不能把“标准异常标志没变”表述为“完整状态字没变”。
首版诊断候选保持保守边界:baseline key/output必须有限,所有异常被mask;baseline尾部前后上述环境完全相同,当前probe环境又与baseline一致,且完整40 B key相同,才计算为可直接返回的hit。其余情况仍原计算。没有尝试重放/修补x87状态字,也没有把条件位从比较中移除。
| 严格候选结果(每轮一致) | 次数 |
|---|---|
| 可直接返回候选hit | 8,734 = 397 × 22 |
| 候选hit rate | 37.4914148% |
| baseline改变x87状态,故记录不可直接复用 | 12,974次probe |
| 在可复用baseline下,probe环境不同 | 901 |
| 环境相同但key不同 | 687 |
| 总候选miss / 原执行 | 14,562 |
拒绝原因按实际检查优先级归类,环境不同和key不同可能重叠,不能将此表与3,584次纯数值miss相加。上述hit均进一步检查了真实原执行的出口环境和cm/vel:与baseline一致;但本轮没有把它接入真实skip。
这里的完整x87状态保护比仅核对C标准fenv的异常/舍入控制更严格。它明确对应本轮不放宽FP状态语义的候选;不能用其37.49%结果断言所有可能的FP兼容memo设计都只有这个命中率。
5. Break-even:必须收费的miss与baseline
本轮的H包括每Jacobian重置、baseline key/入口环境构造、出口环境检查、完整key/output捕获和ready判定。原baseline尾部计算本身未计为H,因为无优化时也必须执行。
net = sum(K_i for accepted hits)
− sum(G_hit_i)
− sum(G_miss_i)
− sum(H_j)
仅用 K > G_hit + H/22 会出错:严格候选平均每Jacobian只有 9.747768次hit,同时每Jacobian有 16.252232次miss lookup。miss不省任何尾部工作,却仍要支付查找开销。
同轮测量的开销及诊断预算
G为逐次成本的均值,H为总baseline新增除以896。下表净值使用该轮可接受hit对应的原尾部时间,扣一个空标记后计算;不是根据全体K均值估算命中部分。
| 轮次 | G_hit µs | G_miss µs | H µs/J | 可省尾部ms | 全部probe lookup ms | baseline新增ms | 诊断净预算ms |
|---|---|---|---|---|---|---|---|
| 0 | 0.151522 | 0.157994 | 2.161951 | 5.193716 | 3.624103 | 1.937108 | −0.367495 |
| 1 | 0.385920 | 0.575816 | 3.331597 | 6.472028 | 11.755655 | 2.985111 | −8.268738 |
| 2 | 0.415912 | 0.480126 | 3.563161 | 8.496013 | 10.624167 | 3.192592 | −5.320746 |
| 3 | 0.475128 | 0.507744 | 6.618877 | 15.133467 | 11.543533 | 5.930514 | −2.340579 |
| 4 | 0.152557 | 0.197271 | 2.087834 | 5.390453 | 4.205092 | 1.870699 | −0.685338 |
五轮G_hit均值中位数 0.385920µs,H中位数 3.331597µs/J。H不仅是几个孤立长尾:不含重置的逐baseline成本中位数也为 1.794–2.944µs。没有测出H≤1µs/J。
G_hit逐次中位数较低(约0.071–0.133µs),但不能只收hit的中位数费用,再把miss和baseline账单省略。要计算轨迹净收益,必须使用累计成本。
具体break-even门槛
固定同轮实测H和全部miss成本后:
G_hit_max = (saved_tail_work − baseline_cost − miss_lookup_cost) / hits
五轮上限分别为 0.109446、−0.560810、−0.193287、0.207143、0.074089µs。负数表示即使hit完全免费,该轮H+miss也已用完预算;其余轮的实际G_hit同样超过上限。
以较平稳的第0轮举例,命中尾部扣标记均值0.594655µs:
- 若H=1µs/J,hit与miss统一收费G,需要 G<0.184483µs/每次probe尝试 才盈利。因此“G≤0.25µs且H≤1µs/J”在37.49%可接受率下也不自动足够。
- 实测H=2.161951µs/J时,所有probe的平均查找预算约 0.13979µs;实测约0.15557µs,仍超过。
- 这是具体候选的盈亏边界,不是kernel memo的理论最低实现成本。没有测量未知的新FP状态重放设计,也不把这种未实现方案当作已有收益。
所有净预算是诊断阶段的候选费用估计,不是实测real-skip加速。系统负载和计时长尾较大,无法证明纯硬件成本存在绝对负收益下界;但是没有一轮形成完整账单上的正收益,故不满足“诊断显示可盈利才实现”的条件。
6. 数值验收与停止决定
8轮(5轮完整诊断、3轮K-only)全部与归档未修改local probe基线一致:states、outputs、events二进制、最终状态、warning和solver counters。diagnostic-0与tail-only-0另分别核对全部896个132×132 Jacobian及对应t/y,逐位一致。
| 计数 | 各轮结果 |
|---|---|
| accepted / rejected | 10840 / 918 |
| Newton iterations / convergence failures | 19371 / 798 |
| nfev / njev / nlu | 44467 / 896 / 3106 |
| solverStarts / stateTransitions | 4 / 1 |
| 目标原尾部实际执行 | 24,192 / 24,192 |
本轮没有真实skip版本,因此没有声称完成memo版的逐evaluator property/pipe context与memo生命周期双路验收。当前验证证明诊断插桩保持了上述完整轨迹数值;将来若提出另一种盈利方案,仍须重新完成用户要求的全context/FP等真实skip验收,不能借用本轮数值一致性代替。
停止决定:保留position379原尾部计算;不接入生产、不扩展其他position、不继续调小这套候选以追求过线。
产物与复现
- 诊断构建/执行脚本、只读汇总脚本。
- 诊断接口、诊断记录与计时。代码没有真实skip入口。
- 全部轮次统计、预算及FP变化。
- 最终核验记录:五轮key/output/FP记录投影逐字节相同,源文件/构建哈希及数值检查通过。
test/position379-tail-20260917/diagnostic-0..4/:原始128 B记录、每Jacobian key分组、空时钟标记、逐轮校验结果。tail-only-0..2/:独立K对照;其后置环境采样不作语义证据。diagnostic-build-v1/:原五轮使用的构建及哈希;diag-trace/为交付诊断构建,关键目标码一致;tail-only-trace/为K对照构建。
.venv-win/Scripts/python.exe -B tests/manual/diagnose_valve_tail.py prepare
.venv-win/Scripts/python.exe -B tests/manual/diagnose_valve_tail.py run --label diagnostic-new --matrices
.venv-win/Scripts/python.exe -B tests/manual/diagnose_valve_tail.py prepare --tail-only
.venv-win/Scripts/python.exe -B tests/manual/diagnose_valve_tail.py run --worker tail-only-trace --label tail-only-new --matrices
.venv-win/Scripts/python.exe -B tests/manual/analyze_valve_tail.py
路径均从脚本所在仓库解析;此实验使用Windows归档工具链和TSC/FP寄存器读数,没有进行Linux性能测试。