相较上一版 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 通过。
238 lines
16 KiB
Markdown
238 lines
16 KiB
Markdown
# 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](../../test/local-probe-20260917/worker/properties.c) 第266–277行和 [orifice.c](../../test/local-probe-20260917/worker/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内,以下语句及其子调用均原样执行:
|
||
|
||
```c
|
||
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` 的调用也计入该尾部。
|
||
|
||
```c
|
||
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和分组关系](../../test/position379-tail-20260917/diagnostic-0/key-groups.json)。其他四轮也各自保存清单和原始记录,并得到相同分组计数。
|
||
|
||
### 数值重复不等于可以直接返回
|
||
|
||
本次读取: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,因为无优化时也必须执行。
|
||
|
||
```text
|
||
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成本后:
|
||
|
||
```text
|
||
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、不继续调小这套候选以追求过线。**
|
||
|
||
## 产物与复现
|
||
|
||
- [诊断构建/执行脚本](diagnose_valve_tail.py)、[只读汇总脚本](analyze_valve_tail.py)。
|
||
- [诊断接口](valve_tail_diag.h)、[诊断记录与计时](valve_tail_diag.c)。代码没有真实skip入口。
|
||
- [全部轮次统计、预算及FP变化](../../test/position379-tail-20260917/diagnostic-analysis.json)。
|
||
- [最终核验记录](../../test/position379-tail-20260917/verification.json):五轮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对照构建。
|
||
|
||
```powershell
|
||
.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性能测试。
|