Files
SystemSimulationApp/tests/manual/state_valve_tail_report.md
ljz 7611f13208 修复循环信号与事件采样并接入 LSTP 接触定位,补充八路验证及复用实验
相较上一版 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 通过。
2026-09-17 23:50:13 +08:00

16 KiB
Raw Permalink Blame History

position379:state_valve 数值尾部诊断

日期:2026-09-17。仅针对既有八路模型 0–10 s 轨迹中,Jacobian baseline/probe 实际执行的 position379 / PNVO001_1.port_2。没有改生产路径,没有研究其他 position,没有实现真实 memo skip。

四个问题的答案

  1. 尾部典型单次约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。
  2. 完整数值key重复率84.615%。 每个Jacobian有5种key,22个probe与baseline逐位相同;全轨迹理论命中19,712/23,296。包含完整x87状态字保护后,本次“无FP状态变化才可直接返回”的候选只允许8,734次,即37.491%。
  3. 当前严格候选未达到完整机制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。
  4. 不进入真实实现阶段,停止该方向。 数值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、不继续调小这套候选以追求过线。

产物与复现

.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性能测试。