相较上一版 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 通过。
157 lines
22 KiB
Python
157 lines
22 KiB
Python
"""Reproducible accounting/validation report; never rescales categories to fit a target."""
|
||
from pathlib import Path
|
||
import hashlib,json,statistics
|
||
from profile_local_probe import ROOT,OUT,SOURCE,write
|
||
|
||
LABELS={
|
||
'other':'其余 callback 时间','perturbation_amount':'扰动量计算','state_copy_perturb':'状态复制/施加扰动',
|
||
'matrix_zero':'矩阵清零','difference_matrix_write':'差分计算/矩阵写回','baseline_compute':'baseline 原求值(不含 snapshot)',
|
||
'initialization':'probe initialization','gas_state_preparation':'probe gas state preparation',
|
||
'schedule_retained':'保守依赖保留的原计算','schedule_context_fallback':'context 失败后的 fallback 原计算',
|
||
'context_compare':'context/cache 比较','snapshot_capture_save':'baseline snapshot 捕获/保存',
|
||
'context_output_restore':'probe context/output restore','node_energy':'node energy','port_outputs':'端口输出赋值',
|
||
'mechanical_equations':'mechanical equations','gas_mass_energy':'气体质量/能量方程','remaining_outputs':'remaining outputs',
|
||
'pipe_diagnostics':'pipe diagnostics','finite_check':'finite check','schedule_dispatch':'schedule dispatch/管理',
|
||
'whole_probe_fallback':'整次 probe fallback'}
|
||
|
||
def read(label,file='measurement.json'):return json.loads((OUT/label/file).read_text(encoding='utf-8'))
|
||
def table(head,rows):
|
||
return '\n| '+' | '.join(head)+' |\n| '+' | '.join(['---']*len(head))+' |\n'+'\n'.join('| '+' | '.join(map(str,r))+' |' for r in rows)+'\n'
|
||
|
||
def profile(label):
|
||
p=read(label,'profile.json');f=p['frequency'];cal=statistics.median(p['calibrationTicksPerMarker'])
|
||
assert sum(sum(r['ticks']) for r in p['rows'])==p['ledgerSumTicks']==p['sampledCallbackTicks']
|
||
assert sum(sum(r['intervals']) for r in p['rows'])==p['markerCount']
|
||
assert all(r['evaluations']==p['sampledCallbacks'] for r in p['rows'][1:])
|
||
rows=[]
|
||
for r in p['rows']:
|
||
raw={n:t/f for n,t in zip(p['categories'],r['ticks'])}
|
||
corrected={n:(t-cal*c)/f for n,t,c in zip(p['categories'],r['ticks'],r['intervals'])}
|
||
assert min(corrected.values())>=0,(label,r['group'],'calibration below resolution',corrected)
|
||
rows.append({**r,'seconds':raw,'correctedSeconds':corrected})
|
||
boundary=p['sampledCallbackQpcTicks']/p['qpcFrequency']-p['sampledCallbackTicks']/f
|
||
# The two pairs of enclosing clocks delimit a real wrapper interval. Keep
|
||
# it visible, rather than rescale the TSC buckets to match QPC.
|
||
assert abs(boundary)<.01,(label,'clock cross-check',boundary)
|
||
rows[0]['seconds']['other']+=boundary
|
||
rows[0]['correctedSeconds']['other']+=boundary
|
||
return {**p,'rows':rows,'calibrationNs':cal/f*1e9,'timerSeconds':cal*p['markerCount']/f}
|
||
|
||
def aggregate(labels):
|
||
ps=[profile(n) for n in labels];categories=ps[0]['categories'];samples=sum(p['sampledCallbacks'] for p in ps)
|
||
rows=[]
|
||
for i in range(len(ps[0]['rows'])):
|
||
totals={key:{c:sum(p['rows'][i][key][c] for p in ps) for c in categories} for key in ('seconds','correctedSeconds')}
|
||
rows.append(dict(group=i-2,evaluations=sum(p['rows'][i]['evaluations'] for p in ps),**totals,
|
||
operations=[sum(p['rows'][i].get('operations',[0,0])[k] for p in ps) for k in range(2)]))
|
||
totals={key:{c:sum(r[key][c] for r in rows) for c in categories} for key in ('seconds','correctedSeconds')}
|
||
return dict(labels=labels,samples=samples,rows=rows,totals=totals,
|
||
callbackSeconds=sum(p['sampledCallbackQpcTicks']/p['qpcFrequency'] for p in ps),
|
||
timerSeconds=sum(p['timerSeconds'] for p in ps),
|
||
calibrationNs=[p['calibrationNs'] for p in ps])
|
||
|
||
def main():
|
||
# Compare every saved run, not only the runs chosen for timing summaries.
|
||
reference=json.loads((SOURCE.parent/'all-run-0/measurement.json').read_text(encoding='utf-8'))
|
||
keys=['statesSha256','outputsSha256','eventsSha256','finalState','final','propertyWarnings','acceptedSteps','rejectedSteps','stateTransitions','solverStarts','nfev','njev','nlu']
|
||
counter_keys=['newtonIterations','newtonConvergenceFailures','contextComparedBytes','contextCopiedBytes','modelCalls','groups']
|
||
checks=[]
|
||
for path in sorted(OUT.glob('*/measurement.json')):
|
||
r=json.loads(path.read_text(encoding='utf-8'))
|
||
diff=[k for k in keys if r[k]!=reference[k]]+[k for k in counter_keys if r['diagnostic'][k]!=reference['diagnostic'][k]]
|
||
assert not diff,(path,diff);checks.append(dict(run=path.parent.name,differences=diff))
|
||
full=profile('validate-all');plan=json.loads((SOURCE.parent/'plan.json').read_text(encoding='utf-8'))
|
||
audit=json.loads((SOURCE.parent/'all-audit/probe.json').read_text(encoding='utf-8'))
|
||
for g,row in enumerate(full['rows'][2:]):
|
||
retained=len(plan['groups'][g]['affectedOperations'])*896
|
||
total=sum(audit['groups'][g]['executed'])
|
||
assert row['operations']==[retained,total-retained]
|
||
assert full['rows'][28]['operations']==[0,0]
|
||
for name in ('jacobians','states','outputs','events'):
|
||
def digest(p):
|
||
with p.open('rb') as f:return hashlib.file_digest(f,'sha256').hexdigest()
|
||
assert digest(OUT/f'validate-all/{name}.bin')==digest(SOURCE.parent/f'all-audit/{name}.bin')
|
||
# Check the original sources, and the original numerical evaluator in the
|
||
# copied translation unit, have not been rewritten by this measurement.
|
||
build=json.loads((OUT/'build.json').read_text(encoding='utf-8'))
|
||
for name,expected in build['sourceHashes'].items():
|
||
assert hashlib.sha256((SOURCE/name).read_text(encoding='utf-8').encode()).hexdigest()==expected
|
||
old_model=(SOURCE/'model.c').read_text(encoding='utf-8')
|
||
assert old_model in (OUT/'worker/model.c').read_text(encoding='utf-8')
|
||
native=json.loads((SOURCE/'build-metadata.json').read_text(encoding='utf-8'))['sourceHashes']
|
||
for name,expected in native.items():assert hashlib.sha256((ROOT/'native'/name).read_text(encoding='utf-8').encode()).hexdigest()==expected
|
||
|
||
main_labels=[f'profile-{i}' for i in range(5)];data=aggregate(main_labels);scale=896/data['samples']
|
||
metrics=('jacobianSeconds','solveCpuSeconds','solveSeconds','processSeconds')
|
||
def metric(r,k):return r['diagnostic'][k] if k=='jacobianSeconds' else r[k]
|
||
controls=[read(f'control-{i}') for i in range(5)];runs=[read(n) for n in main_labels]
|
||
medians={mode:{k:statistics.median(metric(r,k) for r in rs) for k in metrics} for mode,rs in [('control',controls),('profile',runs)]}
|
||
deltas={k:medians['profile'][k]/medians['control'][k]-1 for k in metrics}
|
||
paired={k:[metric(b,k)/metric(a,k)-1 for a,b in zip(controls,runs)] for k in metrics}
|
||
densities={str(s):aggregate([f'density{s}-{i}' for i in range(2)]) for s in (8,32)}
|
||
coarse=aggregate([f'coarse-{i}' for i in range(3)])
|
||
result=dict(numericalChecks=checks,allMatrices=dict(count=896,entries=896*132*132,differentEntries=0),
|
||
originalSourcesUnchanged=True,main=data,medians=medians,deltas=deltas,pairedDeltas=paired,densityChecks=densities,
|
||
fullCoverageOperationCounts=[r['operations'] for r in full['rows'][2:]],allInstrumented=full,coarse=coarse)
|
||
write(OUT/'comparison.json',result)
|
||
|
||
report=['**局部 probe performance worker:互斥耗时分解(2026-09-17)**\n']
|
||
report.append('仅增加独立诊断构建/分析工具及计时副本;原局部优化脚本、生产实现、普通 residual、物性算法、accepted-step check、线性求解器均未修改。模型为 `tests/data/test-mql-8-corrected.json`,0–10 s、BDF、rtol=1e-8,原 atol/步长设置不变。\n')
|
||
estimate=sum(data['totals']['correctedSeconds'].values())*scale
|
||
cg=coarse['rows'][28];cg_us=sum(cg['seconds'].values())/cg['evaluations']*1e6
|
||
report.append(f'**先说明精度边界:** 低密度插桩相对未插桩的callback中位数变化{deltas["jacobianSeconds"]:+.2%}、积分CPU变化{deltas["solveCpuSeconds"]:+.2%};但细分数据扣空标记后折算{estimate:.6f}s,仍比未插桩{medians["control"]["jacobianSeconds"]:.6f}s高{estimate/medians["control"]["jacobianSeconds"]-1:.2%}。所以本轮完成了互斥分类、账本闭合和数值核验,但细分值尚未达到可直接当作未插桩精确耗时的精度。下面使用它判断热点量级与排序,不以这些百分比承诺优化收益。粗粒度独立对照中group26约{cg_us:.3f}µs,是固定底座总量的更可靠参考。\n')
|
||
report.append('**测量方法与互斥口径**\n')
|
||
report.append('主测量为5对交替串行运行,预热不计入。每连续16次 callback 分层随机抽1次,种子固定可复现;每轮56次,5轮共280次,baseline和每组probe各280次。未抽中callback走保留的原数值函数;抽中才进入计时副本,不开启shadow求值、物性内核入口计数或矩阵落盘。全量插桩+矩阵落盘仅用于数值核验。\n')
|
||
report.append('外层总时间仍用QPC;内部用带lfence的TSC读取及约10 KB互斥计数桶,避免每次记录事件数组。启动时要求CPU支持invariant TSC;用覆盖整个积分的QPC/TSC成对读数校准TSC频率。每个相邻区间只归属一个分类、一个row(外层/baseline/group),桶的TSC tick总和必须精确等于抽中callback内部总tick。外层QPC包络与内部TSC包络的差单列计入outer other,是时钟边界间的包装开销;不缩放内部分类。归并后的原始分类总和与抽中callback的QPC时间在浮点精度内相等。这只证明互斥账本闭合,不证明没有插桩扰动。\n')
|
||
report.append('在积分完成后,以相同的带屏障读时钟和计数桶更新测9批空标记,取每标记平均成本的中位数。保留原始时间,并另外给出“原始时间−标记数×空标记成本”的估计;未以未插桩总时间强制归一化,也不把任何负数截成0(出现负分类即报告失败)。校正不能消除屏障引起的执行串行化、编译布局、缓存、额外分支和操作分类的间接扰动;极短分类只作数量级参考。原QPC事件记录版保存在test/local-probe-profile-20260917,其校正后总量高估约10.8%,因此本报告继续展示残余偏差,而不宣称空标记校准能消除它。\n')
|
||
report.append(f'主测量标记成本:{min(data["calibrationNs"]):.2f}–{max(data["calibrationNs"]):.2f} ns/次。5轮被抽中callback合计 **{data["callbackSeconds"]:.9f} s**,原始分类加和完全相等;估计计时标记成本 **{data["timerSeconds"]:.9f} s**。\n')
|
||
report.append('baseline原求值列排除snapshot捕获/保存,baseline完整求值小计包含两者,只作小计不重复相加。snapshot包含入口t/y保存、选定property/pipe检查点复制、schedule结果数组保存。context比较包含元数据和memcmp;restore包含出口context/cache和区间结果恢复。schedule原计算在case原语句两侧划界,switch/循环/区间分派及测量分类开销另计schedule dispatch。\n')
|
||
report.append('initialization包括生成模型开头的数组/cache初始化及第一处gas求值前的准备赋值;gas state preparation从第一处gas求值到schedule入口,包括所有gas memo查找、必要物性计算、gas输出赋值及property context seed。schedule外的端口列仅为端口输出赋值。pipe diagnostics包括调用参数中的PH反算、诊断内核和acc累加;将acc写入w及ff的fmin限幅算remaining outputs。后者不是单纯memcpy,不能据名称假定廉价。\n')
|
||
report.append('**未插桩/插桩总耗时对照**\n')
|
||
labels={'jacobianSeconds':'Jacobian callback累计墙钟','solveCpuSeconds':'积分CPU','solveSeconds':'积分墙钟','processSeconds':'完整native进程墙钟'}
|
||
report.append(table(['5轮中位数','未插桩 / s','1/16插桩 / s','变化'],[(labels[k],f'{medians["control"][k]:.6f}',f'{medians["profile"][k]:.6f}',f'{deltas[k]:+.2%}') for k in metrics]))
|
||
report.append(table(['配对','control Jacobian','profile Jacobian','control积分','profile积分','control进程','profile进程'],[(i,*[f'{metric(r,k):.6f}' for k in ('jacobianSeconds','solveSeconds','processSeconds') for r in (controls[i],runs[i])]) for i in range(5)]))
|
||
report.append('所有样本保留,没有因较慢而删除。整进程包含启动、输出重放/落盘、诊断文件写入、标记校准和退出,不含预先完成的编译和浏览器/API流程。机器频率与调度噪声仍存在,不能把很小的负变化当作计时插桩带来的加速。\n')
|
||
report.append('**互斥分类:按抽样折算到一轮896次Jacobian**\n')
|
||
report.append('下面为5轮采样累计分类时间×896/280,未使用目标总时间做比例缩放。原始列含时间标记成本;估计列仅扣除空标记成本。\n')
|
||
raw=data['totals']['seconds'];adj=data['totals']['correctedSeconds'];total=sum(adj.values())
|
||
report.append(table(['分类','原始折算 / s','扣标记估计 / s','估计占比'],[(LABELS[c],f'{raw[c]*scale:.6f}',f'{adj[c]*scale:.6f}',f'{adj[c]/total:.2%}') for c in raw]))
|
||
report.append(f'原始折算合计 **{sum(raw.values())*scale:.6f} s**;扣标记估计合计 **{total*scale:.6f} s**;未插桩callback中位数 **{medians["control"]["jacobianSeconds"]:.6f} s**。估计合计与未插桩相差 **{(total*scale/medians["control"]["jacobianSeconds"]-1):+.2%}**,这部分不强行塞进其他分类。\n')
|
||
report.append(table(['范围(小计,不再相加)','原始每次 / µs','扣标记每次 / µs','一轮扣标记 / s'],[(name,f'{sum(data["rows"][i]["seconds"].values())/data["rows"][i]["evaluations"]*1e6:.3f}',f'{sum(data["rows"][i]["correctedSeconds"].values())/data["rows"][i]["evaluations"]*1e6:.3f}',f'{sum(data["rows"][i]["correctedSeconds"].values())*scale:.6f}') for name,i in [('baseline完整求值',1)]]))
|
||
report.append('**probe总体及逐group平均**\n')
|
||
probe_raw=sum(sum(r['seconds'].values()) for r in data['rows'][2:]);probe_adj=sum(sum(r['correctedSeconds'].values()) for r in data['rows'][2:])
|
||
report.append(f'共测量{data["samples"]*27:,}次probe,平均原始 **{probe_raw/(data["samples"]*27)*1e6:.3f} µs/probe**,扣标记估计 **{probe_adj/(data["samples"]*27)*1e6:.3f} µs/probe**。组平均范围为lp_eval入口至jac_rhs_reuse返回前,包含数值入口管理及后置统计;外层扰动/矩阵写回不归入probe。\n')
|
||
report.append(table(['group','次数','原始总均值 µs','扣标记总均值 µs','保留原计算 µs','fallback原计算 µs','全覆盖实际保留/回退操作'],[(r['group'],r['evaluations'],f'{sum(r["seconds"].values())/r["evaluations"]*1e6:.3f}',f'{sum(r["correctedSeconds"].values())/r["evaluations"]*1e6:.3f}',f'{r["correctedSeconds"]["schedule_retained"]/r["evaluations"]*1e6:.3f}',f'{r["correctedSeconds"]["schedule_context_fallback"]/r["evaluations"]*1e6:.3f}',str(full['rows'][r['group']+2]['operations'])) for r in data['rows'][2:]]))
|
||
report.append('各group完整分类数据(不只保留/回退)见comparison.json中main.rows[group+2],seconds与correctedSeconds除以evaluations即为单次均值。\n')
|
||
report.append('**低扰动粗粒度交叉核验**\n')
|
||
report.append('另构建coarse-worker:只有callback外层以及baseline/完整probe入口和出口的标记,数值调用直接进入原model_eval_local_internal,内部没有细分标记。3轮覆盖全部896次callback(非抽样)。以下原始均值不扣空标记,额外的每probe边界成本很小;它用于检查细分计时对每组总量的偏差,不用于强制缩放细分分类。\n')
|
||
report.append(table(['group','粗粒度完整probe µs','细分扣标记 µs','细分相对偏差'],[(g,f'{sum(coarse["rows"][g+2]["seconds"].values())/coarse["rows"][g+2]["evaluations"]*1e6:.3f}',f'{sum(data["rows"][g+2]["correctedSeconds"].values())/data["rows"][g+2]["evaluations"]*1e6:.3f}',f'{(sum(data["rows"][g+2]["correctedSeconds"].values())/data["rows"][g+2]["evaluations"])/(sum(coarse["rows"][g+2]["seconds"].values())/coarse["rows"][g+2]["evaluations"])-1:+.2%}') for g in range(27)]))
|
||
report.append(table(['粗粒度轮次','callback s','积分 s','group26 µs'],[(f'coarse-{i}',f'{read(f"coarse-{i}")["diagnostic"]["jacobianSeconds"]:.6f}',f'{read(f"coarse-{i}")["solveSeconds"]:.6f}',f'{sum(profile(f"coarse-{i}")["rows"][28]["seconds"].values())/896*1e6:.3f}') for i in range(3)]))
|
||
report.append('**group 26:schedule全跳过后的固定成本**\n')
|
||
g=data['rows'][28];n=g['evaluations'];ga=sum(g['correctedSeconds'].values())
|
||
cg=coarse['rows'][28];coarse_g26=sum(cg['seconds'].values())/cg['evaluations']*1e6
|
||
report.append(f'全量896次核验中,保留原操作=0、fallback原操作=0,与原audit逐操作计数相符。主测量均值:原始 **{sum(g["seconds"].values())/n*1e6:.3f} µs**,扣标记估计 **{ga/n*1e6:.3f} µs**;更低扰动的粗粒度完整probe均值 **{coarse_g26:.3f} µs**。这是本模型、本轨迹、group 26下的固定底座,不是所有group通用的固定常数,也不包含外层差分写回。\n')
|
||
report.append(table(['分类','原始均值 / µs','扣标记均值 / µs','估计占比'],[(LABELS[c],f'{g["seconds"][c]/n*1e6:.3f}',f'{v/n*1e6:.3f}',f'{v/ga:.2%}') for c,v in g['correctedSeconds'].items() if g['seconds'][c]]))
|
||
report.append('**采样密度与数值校验**\n')
|
||
density_rows=[]
|
||
for name,d in [('1/8',densities['8']),('1/16',data),('1/32',densities['32'])]:
|
||
factor=896/d['samples'];g=d['rows'][28]
|
||
density_rows.append((name,d['samples'],f'{sum(d["totals"]["correctedSeconds"].values())*factor:.6f}',f'{d["totals"]["correctedSeconds"]["schedule_retained"]*factor:.6f}',f'{d["totals"]["correctedSeconds"]["schedule_context_fallback"]*factor:.6f}',f'{sum(g["correctedSeconds"].values())/g["evaluations"]*1e6:.3f}'))
|
||
report.append(table(['密度','抽中callback','一轮扣标记估计 s','保留计算 s','fallback计算 s','group26 µs'],density_rows))
|
||
report.append(table(['只编入插桩、采样关闭','Jacobian s','积分 s','完整进程 s'],[(f'disabled-{i}',*[f'{metric(read(f"disabled-{i}"),k):.6f}' for k in ('jacobianSeconds','solveSeconds','processSeconds')]) for i in range(2)]))
|
||
report.append(f'共{len(checks)}次完整运行的states/outputs/event二进制、全部warning字段、最终状态、accepted/rejected steps、Newton iterations/failures、nfev/njev/nlu、context复制/比较字节数、各group保护命中/回退计数均与既有performance worker一致。全量计时副本另核对896个132×132矩阵,共15,611,904元素及各矩阵输入t/y,逐字节一致。内部互斥计时桶的闭合误差为0 TSC tick;加上外层边界差后,分类与QPC总量在浮点精度内闭合。\n')
|
||
report.append('全量插桩的每组“保守保留”和“context回退”操作数分别等于依赖计划应执行数、原audit实际执行数减去应执行数;group26两者均为0。整probe fallback未发生。生产native源文件hash、旧performance worker所有源文件hash以及原生成模型函数完整文本均验证未变。\n')
|
||
report.append(table(['求解器项目','所有本轮运行保持一致'],[(k,reference[k]) for k in ['acceptedSteps','rejectedSteps','stateTransitions','solverStarts','nfev','njev','nlu']]+[(k,reference['diagnostic'][k]) for k in ['newtonIterations','newtonConvergenceFailures']]))
|
||
report.append('**可以支持的诊断结论**\n')
|
||
report.append('1. schedule实际保留计算1,390,592次,context保护失败后的回退计算4,620,672次;139,776次区间context校验失败。细分估计回退原计算约0.61s,保守保留原计算约0.42s,1/8和1/32密度下排序相同。保护的主要时间影响体现在失败后的原计算,并非memcmp本身;不能据此推断去掉保护是安全的。\n')
|
||
report.append('2. 比较约0.032s,baseline快照/结果保存约0.053s,恢复约0.030s。三者不是零成本,但合计量级显著小于回退原计算。所有这些时间均与计算阶段互斥,baseline小计没有再次加入总和。\n')
|
||
report.append('3. 未裁剪的初始化、gas准备和schedule外方程/输出/诊断合计估计约0.58s;其中remaining outputs约0.24s、pipe diagnostics约0.19s,而gas准备约0.056s。remaining outputs包含各管道ff的fmin限幅,pipe diagnostics包含参数PH反算,不能把前者等同简单写内存、后者等同单一内核调用。此处未对某个具体函数做内部剖析,不宣称fmin就是已证实的单函数热点。\n')
|
||
report.append('4. group26的schedule保留/回退均为0,依然要执行未裁剪阶段和恢复操作。粗粒度三轮均值21.109–21.263µs;细分扣标记得到24.749µs,高约16.8%,提示小probe的细分扰动占比更高。其细分热点主要是remaining outputs、pipe diagnostics与finite check,但精确占比应保留上述测量误差。\n')
|
||
report.append('5. 随机分层采样减少了整轮测量干扰,不能消除被抽中callback自身的串行化/缓存/编译布局影响。细分校正总量仍有6.98%残差;本报告没有把残差摊进other或按比例缩放各分类来制造闭合。跨轮机器负载差异也会影响粗/细计时对比。本轮没有据此修改任何优化实现。\n')
|
||
report.append('**证据与复现**\n')
|
||
report.append('脚本:tests/manual/profile_local_probe.py、local_probe_profile.h/.c、analyze_local_probe_profile.py。prepare只在本目录生成计时worker;run --stride 1 --matrices做完整数值核验;batch做预热、5对主测量和密度对照;分析脚本生成本报告。各运行目录保留profile.json、measurement.json、probe.json、result.json和二进制结果;build.json保存原文件hash和阶段边界。\n')
|
||
(OUT/'report.md').write_text('\n'.join(report),encoding='utf-8')
|
||
print(json.dumps(dict(medians=medians,deltas=deltas,rawEstimated=sum(raw.values())*scale,correctedEstimated=total*scale,group26Us=ga/n*1e6,densityRows=density_rows,numericalRuns=len(checks)),ensure_ascii=False,indent=2))
|
||
|
||
if __name__=='__main__':main()
|