# HIP PSF 有界真实事件回放与像素归约实验(2026-09-07) ## 结论与交付 **当前方向(2026-09-13):搁置旧串行 adaptive 的慢因追溯,在新版 worker 私有预分桶 adaptive 上优化生产管线。以下各日期记录保留历史结论;当前结果和下一步目标以 “2026-09-13 全天复测与下一步目标”一节为准。** 已实施原计划的有界捕获/回放、16×16 和 32×32 按像素归约原型、独立 CPU producer 诊断及正确性回归。**原型保留在测试程序中,未替换生产 HIP 路径。** 实现于 2026-09-11 提交为 `7f5ec1a`;以下日志和 hash 保留 2026-09-07 测量时的状态。 RX 9070 上,65,536 个真实银心视场事件的累积回放中位数从 104.107 ms 降至 69.823 ms(16×16,约 1.49×)。含公共 GPU 初始化为 137.111 → 102.323 ms(约 1.34×)。 但同等贡献的分散对照中,16×16 从 85.302 ms 退化至 104.389 ms;32×32 为 79.899 ms。 强放大样本的 32×32 结果波动区间与 atomic 重叠,不能确认稳定收益。因此尚不足以选择 一个通用生产默认算法;后续集成应先考虑分布选择及生产流式 producer 的端到端对照。 没有运行完整全天渲染,也没有推断新的全天加速比。 ## 2026-09-11 自适应选择后续实验 在提交 `11e703e33dffb1ff168ba11dd922e68b448116b9` 之上增加了仅用于回放的 `adaptive` 模式,production sink 仍未改变。选择器逐个 16,384-event chunk 扫描 32×32 中心 tile 占用;chunk 至少有 8,192 events、且平均每个占用中心 tile 至少 32 events 时选择 tile16,否则选择现有 atomic。该阈值是基于本页固定输入提出的实验 假设,不是跨场景或跨设备参数。 选择扫描不构建 support 引用,四个样本的中位成本为 0.037--0.455 ms。tile 路径使用 独立的有界 event device buffer,不复用 production 双 staging slot,因此同一 stream 内 可以按 chunk 混合 atomic/tile;mixed fixture 实际覆盖 2 个 tile chunk、1 个 atomic chunk 和中途 direct fallback。所有额外 scratch 仍在 replay sink 创建时一次分配,未进入 renderer。 同一新 binary(SHA256 `121b85ade12680929cf0f560e04485e2ad3d8a56ff9dcbba950a323f840c5151`)串行运行, 每项三次;表中为包含选择、分桶、上传、kernel、合并、下载和清理的 `replay_wall` 中位数: | 65,536-event 输入 | paired atomic | paired tile16 | adaptive | adaptive 选择 | | --- | ---: | ---: | ---: | ---: | | 银心密集 | 95.018 ms | 67.354 ms | 67.834 ms | 0.177 ms | | 同贡献分散 | 78.203 ms | 99.693 ms | 80.092 ms | 0.455 ms | 自适应路径在密集输入相对 paired atomic 快约 1.40×,距固定 tile16 中位数 0.7%;在分散 输入保留 atomic,距其 paired 中位数 2.4%。另外两个真实输入的自适应中位数为强放大 21.617 ms、普通区域 18.347 ms,分别选择 1/1 tile chunk。银心选择 4/4 tile chunks, 分散对照选择 4/4 atomic chunks。此结果支持继续研究 production 流式集成,但尚未包含 OpenMP producer 与 sink 锁竞争,也没有授权用本回放结果宣称完整全天加速。 全部 adaptive/mixed 检查通过原有 finite、double HDR 和 RGB/Y 通量阈值;最坏 `max_abs=5.96856e-11`、`max_rel=5.95958e-13`、RGB 通量相对差 `<=2.83233e-14`、Y `<=1.15036e-14`。`make -j1 test` 与 production HIP primitive 也通过。第一次在受限沙箱内运行明确失败为 `no ROCm-capable device is detected`,随后只在 获准的主机 GPU 环境执行;失败记录保留,没有删除或覆盖。 原始证据: - 构建:[adaptive_build_host.log](hip_psf_replay_2026-09-07/adaptive_build_host.log); - adaptive 三次:`adaptive_{center_65536,dispersed_65536,lensed_16384,ordinary_12765}_host_{0,1,2}.log`; - paired 基线:`paired_{center,dispersed}_{atomic,16}_{0,1,2}.log`; - mixed、CPU 与 HIP 回归:`adaptive_boundary_mixed_host_0.log`、 `adaptive_cpu_regression.log`、`adaptive_hip_primitive_host.log`; - 受限环境失败:`adaptive_center_65536_0.log`。 每份日志均保留完整命令、45/90 s timeout、Git hash、binary hash(适用时)、程序原始输出、 process wall 和 exit status。所有性能进程均由现有独占 runner 串行执行,未与其他 renderer 或 profiler 并发。 ## 2026-09-12 持续回放与 production 集成 在提交 `2d01c2c101ccea8193a64bb46ceafca3009f0ef5` 之上的未提交实现中,回放器增加了 1--512 轮有界重复模式,用同一真实事件流测试持续负载。重复模式不把累计 128/256 轮的 GPU HDR 与单轮 CPU reference 比较,因而输出明确标记 `validation=skipped-for-sustained-timing`; 单轮真实输入与 mixed boundary 仍执行原有 double HDR、RGB/Y 通量和 finite 检查。 原 replay tile16 在密集输入的 256 轮完整 wall 为 12.968 s,atomic 为 14.326 s,只有 1.10×--1.18× 的持续收益;tile accumulation 本身仍约快 1.4×,CPU 的整屏嵌套列表分桶 约占 1.8--1.9 s。不同运行顺序下的 128 轮 adaptive 为 6.372--6.880 s,对应 atomic 7.149--7.165 s,证明短回放的 1.40× 完整收益不能直接外推。 production sink 随后接入稀疏 touched-tile 分桶和可复用有界 scratch。默认保持 atomic; `HIP_PSF_ACCUMULATION=adaptive` 启用与 replay 相同的中心密度选择规则。32 MiB references、 2 MiB tasks 或 128 MiB partials 超限时按 chunk 回退 atomic,不改变 double RGB、四点 phase cache、圆形 support、wing clipping 或 direct fallback 顺序。 最终同 binary(SHA-256 `c560c193e1dc2104030ed804ea68e16ab7576592191dbf147b917a6e097a66b6`)连续回放 65,536 个真实银心事件 128 轮: | production sink | 完整 replay wall | GPU 阶段 | selector | CPU bin | upload | batches | | --- | ---: | ---: | ---: | ---: | ---: | ---: | | atomic | 7.164 s | 7.132 s | 0 | 0 | 0.023 s | 512 atomic | | adaptive | 4.631 s | 3.875 s | 0.018 s | 0.607 s | 0.091 s | 512 tile16 | 完整 replay 为 **1.55×**,记录的 GPU 阶段为 **1.84×**。同 binary 的 64 轮同贡献分散 输入中,adaptive 选择 256/256 atomic chunks,完整 wall 为 3.167 s,直接 atomic 为 3.169 s,差异在 0.1% 内。最终 dense 单轮检查的 `max_abs=2.71051e-19`、`max_rel=1.96115e-14`。最终 mixed boundary 覆盖 2 个 tile16、1 个 atomic chunk 和中途 direct fallback,最坏 `max_abs=5.96856e-11`、 `max_rel=5.95958e-13`,RGB/Y 通量阈值均通过。production primitive 在 adaptive 环境下也 通过,`max_abs=2.84217e-14`、`max_rel=7.53192e-16`。 三 tile、21,087-star renderer 配对使用同一 4K lens map 和同一 production binary (SHA-256 `f51cbccac135502440f005c5d61d95d6004be7d4ec5cd09bfe04bab53053143d`)。 atomic/adaptive 均产生 156,837 events;adaptive 选择 14 tile16 + 2 atomic batches,kernel 为 0.118894 s,对照 0.169212 s,splat wall 为 0.236/0.285 s。两张 PNG 的 SHA-256 都是 `99a971fac7f5e66f0a1aafd0921b61f16fcb933c9488320f95e423542d3b6a6d`。约 1.4 s 的完整 进程受 cache build 等固定成本波动支配,不能用 process wall 判断这项优化。 随后使用同一 4K lens map、598,264,924 events 和 36,530 batches 运行了完整全天 adaptive 渲染。它推翻了上述有界样本的外推: | 完整全天 | splat wall | kernel | CPU bin | selector | upload | process wall | | --- | ---: | ---: | ---: | ---: | ---: | ---: | | atomic | 480.500 s | 477.302449 s | 0 | 0 | 1.411367 s | 533.62 s | | adaptive | 586.763 s | 416.265471 s | 155.302 s | 2.212 s | 7.506981 s | 640.35 s | adaptive 的 GPU kernel 只减少 61.037 s(12.79%),而串行关键路径上的 CPU 分桶增加 155.302 s,splat wall 因而增加 106.263 s(22.12%),完整进程增加 106.73 s(20.00%)。 36,515/36,530 batches 被选为 tile16,说明中心 32px tile 密度无法预测完整 47px PSF support 扩张后的 references、tasks、列表长度和分桶成本。atomic 从有界回放的 13.93 ms/batch 到全天的 13.07 ms/batch 没有恶化;tile kernel 则从有界样本的 7.57 ms/batch 变为全天的 11.40 ms/batch,CPU 分桶另需 4.25 ms/batch。串行分桶是已确认的额外成本;GPU 阶段变慢的具体原因未定位, 不能仅凭这些时间排除时钟或其他系统因素。 正确性仍成立:atomic/adaptive PNG 的 SHA-256 都是 `c63df730c7f927fc6b6ae17df5ffbad1d2bb44631a5821557150d00d6269a3e4`。两个 HDR FITS 共有 24,883,200 个 float,113 个因累积顺序不同;`max_abs=2.38418579e-07`、 `max_rel=1.18905923e-07`。这项旧串行分桶 adaptive 实现是历史负结果,不能外推为新版并行预分桶的结论; 默认继续保持 atomic。当时提出的下一轮实验是直接度量 support-expanded 引用工作量,并在 重新跑完整全天前用真实流式 producer 验证并行预分桶或 GPU 分桶能否把成本移出串行关键路径。 完整 adaptive 原始输出保存在 `full_production_adaptive_user.log`(SHA-256 `ec7b41d56a76cb93383737c30c6c6055bdb53b9b0cff54034333d96a841b1f36`);该用户命令未嵌入 Git/binary hash,运行后工作区 binary 的 SHA-256 为 `f51cbccac135502440f005c5d61d95d6004be7d4ec5cd09bfe04bab53053143d`,不可仅凭事后 hash 证明执行期间 binary。atomic 数字来自同一任务先前保留的终端输出。 ### 2026-09-12 producer 私有并行预分桶原型 在上述完整全天负结果之后,将 adaptive 选择与 support-expanded CPU 分桶移到每个 OpenMP producer 私有的 `HipPsfPreparedChunk`,在获取 sink 共享锁前完成;单个 sink 仍独占 GPU HDR、stream、device scratch 和稳定的上传 staging。direct fallback 先准备本 worker 的待提交 chunk,再在同一锁内完成提交、HDR 下载、CPU splat、HDR 上传。原 `hip_psf_sink_submit` 仍用于 单线程回放兼容,正常生产默认 atomic 未变。新日志记录 tile references、tasks、merges 和 单 chunk 峰值,以便下一次评估完整 support 工作量。 同一 65,536-event 银心固定输入重复 128 轮,均为 512 个 tile16 batches。新 binary 的配对 回放结果如下(两者均通过 `128 × CPU double reference`,`max_rel=2.14616e-14`): | 生产 sink 回放 | replay wall | 累计 CPU bin | GPU 阶段 | process wall | | --- | ---: | ---: | ---: | ---: | | sink 内串行分桶 | 3.886 s | 0.549 s | 3.659 s | 5.778 s | | 16 worker 私有预分桶 | 3.958 s | 0.709 s(各 worker 求和) | 3.670 s | 5.873 s | 此输入上并行预分桶没有端到端收益,且累计 CPU 工作与 RSS 上升(约 716→770 MiB)。由于这 份输入已被全天结果证明低估真实分桶与 tile kernel 成本,此试验仍不能判断全天会否受益, 更不能宣称 61 s 的 kernel 收益已被回收。**不据此再跑完整全天。**需要先取得代表实际 36,530 chunks 的 support-expanded references/tasks 分布和并行分桶 wall,再决定是否继续此方向。 真实小型 4K lens-map renderer 中,16 workers 处理 156,837 events,13 tile +3 atomic batches;13 个 tile chunk 共 6,145,194 references、64,056 tasks、5,465 merges,单 chunk 最多 561,449 references。PNG SHA-256 与先前 atomic 输出同为 `99a971fac7f5e66f0a1aafd0921b61f16fcb933c9488320f95e423542d3b6a6d`。另一个 32,771-event mixed boundary 回放包含 2 tile +1 atomic chunk 和 direct fallback,通过 CPU double reference,`max_abs=5.96856e-11`、`max_rel=5.95958e-13`。HIP primitive 与 `make -j4 ENABLE_PNG=1 test` 均通过。 新原始日志:`parallel_prebin_{serial_128_validated,16workers_128_validated}.log`、 `parallel_prebin_renderer_workload.log`、`parallel_prebin_mixed_boundary.log`、 `parallel_prebin_hip_primitive.log`。先前 `parallel_prebin_16workers_128.log` 因 OpenMP `reduction(max:failed)` 的私有初值而没有提交事件;原始失败保留,修正为 `reduction(+:failed)` 后的 `*_v2.log` 才是首次有效回放,最终数字以上述带 scaled reference 校验的日志为准。 为获取不经 GPU 的真实全天 support 分布,dummy 后端增加显式 `DUMMY_PSF_SUPPORT_STATS=1` 诊断:每 worker 保存最多 16,384 个事件,在 chunk flush 时按 production 的 cache-limited 矩形 support 统计 16px references、touched tiles、按 256 references 切分的 tasks、最大单 tile 列表和第一遍计数耗时。它不生成 HDR、不 materialize references、不上传 GPU,不能把第一遍耗时等同于完整两遍分桶成本。21,087-star 小样通过, 原始记录为 `parallel_prebin_dummy_support_small.log`;该样的 chunk 边界受 OpenMP 动态调度 影响,不与 HIP renderer 的逐 chunk 列表配对。完整全天诊断结果见下文。 下一次完整全天诊断使用与已跑的 dummy 任务相同的参数,只额外设置环境变量;输出路径仅 满足 CLI,dummy 不写图像: ```sh OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE DUMMY_PSF_SUPPORT_STATS=1 \ ./build/Release/schwarzschild_sky_dummy --verbose \ --psf-relative-tail 1e-8 --psf-min-y 0 --max-cache-psf-flux 1e8 \ --all-sky-catalog assets/2mass/processed/all_sky --exposure 1e13 \ --psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 --catalog-load-workers 4 \ --lens-map-input output/lens/schwarzschild_galactic_center_R100_45deg_16_4_4k_.grlens \ --output /tmp/2mass_dummy_support_diagnostic.png ``` 用户随后运行了上述完整全天 dummy 诊断;原始终端输出为 [`full_dummy_support_user.log`](hip_psf_replay_2026-09-07/full_dummy_support_user.log), SHA-256 `992a3109de28a338c53af229b6a3b4083659a835f78929c36d36178358a6d5e0`。 日志未嵌入执行时 Git/binary hash;运行后本地 dummy binary 的 SHA-256 为 `2550fbdc7367ec4d56bdf87894e1322d7f4af5165e93a17af3e6a37806c0649a`。 同一 343,363,141 stars 产生 598,264,924 cached events,0 direct/wing/discard; 64,440 catalog tiles 全部加载,49.020 s;16 worker 分类/chunk wall 81.760 s。zsh `time` 给出总时间 2:11.91;zsh 对 pipeline 中的 `tee` 另列一行,不能把两个 2:11.91 相加。 该次动态调度产生 36,508 个满 chunk、16 个 partial;与 HIP 的 36,530 batches 不作逐批 配对,但总事件数一致。 | 全天满 chunk support 统计 | p50 | p90 | p99 | max | | --- | ---: | ---: | ---: | ---: | | 16px references | 746,748.5 | 802,816 | 802,816 | 802,816 | | touched 16px tiles | 49 | 168 | 1,036 | 1,521 | | tile tasks | 2,975 | 3,136 | 3,435.93 | 3,733 | | 最大 tile 列表 | 16,384 | 16,384 | 16,384 | 16,384 | | 第一遍计数 | 0.807 ms | 0.919 ms | 1.049 ms | 7.969 ms | 全部 chunk 合计 27,216,790,943 references、107,847,441 tasks,worker 第一遍计数时间之和 29.347 s。这是并行 worker 时间之和,**不是**额外 wall time,也不包括第二遍写 references、 任务构造、锁内 staging 或 GPU 上传。全天 HIP 串行完整分桶为 155.302 s,不能拿 29.347 s 直接替换它。第一遍显示每个事件平均覆盖约 45.5 个 16px tile;满 chunk 的 p90 已到 `16,384 × 49`,且最大列表从中位数起就是整批事件。 对旧真实 `center_65536.events` 逐 chunk 用相同 support 矩形计算,四批 references 为 745,430 / 725,200 / 753,474 / 749,671,接近全天 p50;但 touched tiles 为 96 / 162 / 203 / 222,最大列表仅 14,637 / 9,099 / 11,188 / 9,220。因此先前有界 样本只匹配了引用总量,没匹配热点集中度。为区分这两个量,`make_hotspot_fixture.py` 把 原事件平移到相同整数像素,或保留约 8×8px 位置散布;颜色、flux、support 原样保留, 亚像素余数仅受 double 舍入影响。这两份**明确是反事实 GPU workload,不是物理星像**。 固定热点每批恰好 802,816 references、49 tiles、3,136 tasks、最大列表 16,384; 输入 SHA-256 分别为 `de39e07d420f70aaa2f7309d209e58a1091d2bea4ca6d8332366e6944f19347b` 与 `87f90c2e43845962702e1643f9b7a635108b75b6e21a30080650442745cadcf6`。 | 128 轮、512 批回放 | atomic wall | tile 串行 wall | tile 并行 wall | atomic GPU 阶段 | tile GPU 阶段 | | --- | ---: | ---: | ---: | ---: | ---: | | 同一整数像素 | 7.711 s | 4.001 s | 4.071 s | 7.677 s | 3.760 s | | 8×8px 散布 | 6.482 s | 3.949 s | 4.046 s | 6.447 s | 3.714 s | 全部回放通过按轮数缩放的 CPU double reference,tile 的最大相对误差不超过 `3.30e-14`。此对照说明 refs/tile/list 聚合量不足以重现全天 tile GPU 阶段 `416.265/36,530 = 11.40 ms/batch`:即使强制匹配 p90 热点,回放仍约 `7.3 ms/batch`。另外在 `center_65536.events` 的同一回放进程内放入 15 个 CPU 忙等线程, atomic/tile GPU 阶段为 7.126/3.669 s(512 批),几乎仍是无忙等线程的 7.13/3.66 s;简单主机抢占也未重现全天差距。上述 workload 与争用实验均为诊断性 反事实,不能改变真实全天 adaptive 慢 20% 的结论。 原始配对日志:`hotspot_{atomic,adaptive_serial,adaptive_parallel}_128.log`、 `hotspot_jitter8_{atomic,adaptive_serial,adaptive_parallel}_128.log`、 `busy_center_{atomic,adaptive}_128.log`。全天 adaptive 原始进度每隔约 5 秒报告累计 HIP 阶段:首尾约 7–8 ms/batch,中间约 12–13 ms/batch 持续数万批。这提示当前固定 65,536 events 输入未覆盖真实流中的长期困难区段,但也不能排除其他随时间变化的系统因素; 原因仍未定位。当时提出从该区段捕获真实 events 和逐批 GPU/CPU 明细; 2026-09-13 已搁置这项旧版追溯,不再作为新版推进的前置条件。 其余原始证据为 `final_production_{atomic,adaptive}_128.log`、 `final_production_adaptive_dense.log`、 `final_production_dispersed_{atomic,adaptive}_64.log`、 `final_production_adaptive_mixed.log`、`final_hip_test_adaptive.log` 和 `final_renderer_{atomic,adaptive}.log`。每份日志包含完整命令、timeout、Git hash、binary hash 及原始输出。production 默认值没有改变。 实现入口: - [capture_psf.c](../tests/capture_psf.c):调用真实 producer 的测试专用 consumer,捕获或诊断,不生成 HDR。 - [replay_psf.hip](../tests/replay_psf.hip):CPU double reference、现有 atomic、两种 tile 原型。 - [make_psf_fixture.c](../tests/make_psf_fixture.c):单独标记的合成边界/热点/wing fixture。 - [test_psf_capture.py](../tests/test_psf_capture.py):边界限制、分类、串行/并行/索引摘要、拒绝覆盖验证。 - [全部原始证据与索引](hip_psf_replay_2026-09-07/README.md)。 ## 2026-09-13 全天复测与下一步目标 用户在重新构建 worker 私有预分桶版本后,再次完成同配置全天 adaptive 渲染;随后 `git stash` 回到 `2d01c2c`,重新构建并复测原 atomic,之后用 `git stash pop` 恢复修改。 该 HEAD 的 HIP 实现不读取 `HIP_PSF_ACCUMULATION`,所以 atomic 复测命令虽仍写着 `adaptive`,实际是 atomic;不能把输出文件名或环境变量当作算法证据。 | 全天实现 | splat wall | GPU event 阶段 | CPU bin | upload | process wall | | --- | ---: | ---: | ---: | ---: | ---: | | 历史 atomic | 480.500 s | 477.302449 s | 0 | 1.411367 s | 533.62 s | | 旧串行 adaptive | 586.763 s | 416.265471 s | 155.302 s,串行 | 7.506981 s | 640.35 s | | 新并行预分桶 adaptive | 282.944 s | 256.184375 s | 134.374 s,worker 累加 | 7.184765 s | 335.75 s | | 本次 atomic 复测 | 481.417 s | 478.336515 s | 0 | 1.432135 s | 534.37 s | 四次总事件数均为 598,264,924、batches 均为 36,530;两次 adaptive 都选择 36,515 tile16 和 15 atomic batches。新 adaptive 无 direct/wing/discard,references 为 27,216,530,468、 tasks 为 107,238,420、merges 为 2,802,462,峰值 references/chunk 为 802,816。 新 adaptive 和旧 adaptive 均已使用相同 payload 的黑体 LUT;catalog 加载分别为 49.334/50.104 s。新版 bin 时间是各 worker 的经过时间之和,可以与 GPU 重叠,不能加到 splat wall 上,也不能与旧版串行 bin 作等口径的关键路径比较。 atomic 的 splat/GPU 复测仅比历史值高约 0.2%。相对本次 atomic,新 adaptive 的 splat 快约 1.70×、GPU event 阶段快约 1.87×、完整进程快约 1.59×。这支持继续推进新版; 尚不是相同 binary 内的 atomic/adaptive 配对,也不证明新版全天 HDR 数值正确性。 新旧 adaptive 的 splat 差 303.819 s,其中 GPU event 阶段差 160.081 s;不能把全部收益 归因于分桶并行化。旧版 GPU 阶段为何更慢仍未知,保留历史证据,**停止专项追溯**;仅当 新版出现可重复退化或正确性问题且旧版信息有助定位时重新调查。 新 adaptive 完整原文见 [full_parallel_prebin_adaptive_user_2026-09-13.log](hip_psf_replay_2026-09-07/full_parallel_prebin_adaptive_user_2026-09-13.log); atomic 复测仅收到结尾摘录,原样保存为 [full_atomic_redo_user_2026-09-13_excerpt.log](hip_psf_replay_2026-09-07/full_atomic_redo_user_2026-09-13_excerpt.log)。 两者均未提供运行时 binary hash,摘录不能代替完整命令和完整运行日志;本次只更新文档, 没有重新运行 benchmark 或比较新生成的全天 HDR。 ### 新版优化目标与验证顺序(待实施) 目标是在相同 RX 9070、4K lens map、全天 catalog、PSF/曝光/黑体参数和 HDR/PNG 输出下, 将完整进程从 335.75 s 推进到 **240 s/张以内**。这是待验证目标,不是性能承诺;不能通过 降低精度、删减事件、改变 tail/min-Y、缩小输入或省略输出来达标。atomic 保留为参考和 显式可选路径,本次不修改默认算法。 用户全程观察新版的 btop:GPU 常在约 94%,会反复降至约 80%,并非偶发;整机 CPU 持续满载。用户另报告原 atomic 能吃满 GPU。旧串行 adaptive 当时没有观测,不能推断它 不存在 GPU 不满载现象。上述是人工观测,未保存同步遥测,不能据此量化净算力利用率。 新版 generation/submission 累计分别为 814.275/3712.364 s,后者包含分桶、锁等待和 提交/完成等待;atomic 复测的 GPU 阶段占 splat wall 约 99.36%,进程仍为 1461% CPU。 CPU 满载不等于有效 producer 工作,忙等是需测量的嫌疑,尚未定量确认。 新版非 splat 阶段约 52.806 s;即使消除 splat wall 与 GPU event 阶段之间的全部 26.760 s,总进程仍约 309 s。若其他阶段不变,240 s 目标要求 splat 不超过约 187.2 s, 比当前 GPU event 阶段还低约 27%。该 event 区间包围 prepare/accumulate/merge,可能含 提交间隙,不等同于三个 kernel 的净执行时间。因此同时调查管线空隙和 GPU 执行成本, 不能把 btop 达到 100% 当作验收标准。 1. 先比较已有新版 adaptive 与 atomic 全天 HDR:finite、逐像素误差、RGB/Y 总通量, 使用现有正确性阈值;记录输出 hash,不为这一步重跑全天。 2. 增加可关闭的有界诊断,拆分 CPU 分桶、锁等待、锁持有、GPU 完成等待、staging 和 提交时间,记录线程 CPU time;GPU 分别测 prepare、accumulate、merge,并保留原总区间。 在新版代表性真实流式小样上同步记录 GPU busy、时钟、功耗、温度,先验证测量开销。 固定事件回放用于隔离成本,不能单独替代生产 producer/sink 的端到端证据。 3. 若批间空隙显著,优先评估双缓冲 staging/上传,使下一批准备与当前批 GPU 执行重叠; 若共享锁争用显著,再对照专用提交线程加有界队列。这些是待验证候选,不是已选定实现。 明确缓冲 ownership、完成后复用和有界背压;单 sink 持有 GPU HDR,保留 direct fallback 的 finish/download/CPU/upload 顺序,不引入 per-event task 或无界排队。 4. 管线改善后重测剩余成本;若主要时间仍在 kernel,则优化占比最大的实际 kernel;若 catalog 加载成为主要限制,再单独评估输入阶段。保留密集、分散和 mixed/direct 回归。 有界配对采用相同 binary/输入、预热后至少三次交错顺序复测,报告 wall、CPU time、 GPU 分阶段及波动,不累加重叠 worker 时间。每次预设 timeout,串行独占执行,保留完整 命令、Git/diff/binary/input hash、原始日志与退出码;GPU 不可用直接失败。 5. 有界正确性与收益验证后再另行安排全天配对确认,同时报告完整进程和分阶段时间。 未达到 240 s 时记录剩余差距及实测瓶颈;不为解释旧版而额外运行全天。 ## 环境与测量纪律 Git 基线 `5eccc31c99db96de2a0597babf2fd4c2149e91e7`,测量时在此基础上有未提交修改。 没有覆盖用户已有的计划修改。生产 `src/hip_psf.hip` 未改;`src/frame.c` 的诊断钩子 仅在 standalone 测试编译时启用。每次直接执行的 binary SHA256 在相应日志中; [源码、binary、lens map hash](hip_psf_replay_2026-09-07/source_binary_manifest.json)、 [宿主环境](hip_psf_replay_2026-09-07/metadata.log)、 [构建命令](hip_psf_replay_2026-09-07/build_commands.txt)与 `build*.log` 保存完整配置。 Release / C `-O2 -march=native` / HIP `-O2 --offload-arch=gfx1201`,HIP 7.2,RX 9070。 回放 CPU reference 为串行;diagnostic 最多 16 workers;混合 renderer fixture 为 4 workers。 各进程重建相同 immutable cache:FWHM=2.7、beta=4.5、tail=1e-8,64 phase intervals、 47px cache radius。没有清除文件系统 page cache;输入是重复读取的固定小文件。 所有测试进程串行,回放超时 45 s、缩小 renderer 超时 60 s;未出现测试超时。 早期 `v3_*` 期间部分编译活动重叠,全部 `v3_*` 仅用作探索/正确性证据。 下表只用构建和回归结束后的 `final_*` 三次独立复测,不引用受构建干扰的时间。 `run.py` 记录命令、原始 stdout/stderr、退出码和进程 wall,失败立即停止,限时进程被 kill 后会 wait/reap;独占锁及启动前的进程检查防止本套工具重叠运行。 ## 固定输入、选择规则与实际覆盖 使用已有 3840×2160 Schwarzschild lens map,不重新 tracing/refine。只读取两个指定 catalog tile 的均匀 8,192 行子集,见 [输入 manifest](hip_psf_replay_2026-09-07/input_manifest.json) 和 [重建脚本](hip_psf_replay_2026-09-07/prepare_inputs.py)。没有遍历完整全天 catalog。 捕获器限制 CSV≤8 MiB、stars≤32,768、lens map≤64 MiB/单帧、triangle 范围≤131,072、 缓存事件≤65,536、分类总数≤131,072。按 triangle ID、原 catalog 顺序捕获,保留所有 7 个 event double,文本用 17 位有效数字 round-trip;header 保存实际数量与 PSF 参数。 triangle 范围 `[0,130882)`;按未截断的局部 magnification 再筛选: | 区域 | 原始 tile | magnification | 最大捕获实际数 | 占用 32px 中心 tiles | 最大中心密度 | | --- | --- | --- | ---: | ---: | ---: | | 普通区域 | RA252/Dec048(Dec −42°) | [0,1.2) | 12,765 | 8 | 4,691 | | 银心视场密集区域 | RA262/Dec060(Dec −30°) | [0,2) | 65,536(到上限) | 30 | 7,778 | | 强放大区域 | 同上 | [2,1e6) | 16,454 | 367 | 176 | 普通、强放大子集用完后没有复制事件凑足 65,536。事件文件名后缀表示请求上限,实际数量 以 header 和 manifest 为准。实际 bbox、flux/support 范围、中心 tile 分布及事件 hash 见 [events_manifest.json](hip_psf_replay_2026-09-07/events_manifest.json)。三种真实输入的 support 均为 45.84777786185942px;变化 support/wing/边缘另由合成 fixture 覆盖。 分散对照只平移完整处于画面内部的事件中心,保留 fractional phase(浮点平移舍入以内)、 flux 和 support;本来裁切的事件不移动。每次都重新计算并断言实际 event–pixel 贡献数 完全不变:真实和分散的 65,536 事件均为 **432,818,979** 个贡献。没有以裁切减少工作量。 ## 原型与 ownership 每 chunk≤16,384 events。CPU 按 cache 遍历 support 的完整包围矩形建立所有相交 tile 引用,PSF wings 可以进入多个 tile;GPU 用原来的圆形行范围再筛选,继续四点 phase cache 插值和 double RGB。每个像素由一个线程累计,不使用全局 double atomic。 第一次朴素实现反复计算 phase、sqrt/行范围,4,096 普通事件的回放约 25–27 ms,慢于 atomic。第二版为每个 chunk 在 GPU 预计算 phase、颜色×flux 和行范围,然后供像素线程复用。 分散对照随后触发 128 MiB 部分和限制,进程已停止。最终版让≤256 引用的单列表 tile 直接写回独占 HDR 像素;只有长列表分段才写部分和,第二阶段按固定 task 次序相加。 这种修正保持内存上限,避免为整屏稀疏 tiles 分配一幅额外 double HDR。 设备上固定复用:references 32 MiB、tasks 2 MiB、starts 128 KiB、partials 128 MiB, 以及最多 16,384 事件的 Prepared/行范围约 12.875 MiB;合计额外预留 **175 MiB**。 超出引用/任务/部分和容量立即报错,无隐式切换。全部缓冲由单个实验 sink 持有,单 stream 顺序消费、同步后复用;每个 partial 元素都被覆盖写入,不需要 memset。最终样本实际 scratch 使用峰值约 37.26 MiB,整个 CPU-reference+GPU 进程 RSS 最大 717,172 KiB。 预留量和实际用量不同,RSS 包含 CPU HDR/reference/cache,不能当作生产额外 RAM。 ## 独立最终回放结果 下表是 `replay_wall` 中位数(ms,三次):包含 scratch 分配、分桶、上传、预计算、累积、 合并、下载、清理,排除公共 sink/cache 初始化和 CPU reference。日志另报 `complete_replay` (加公共 GPU sink 创建)、`CPU_reference`、cache build、完整 `PROCESS_WALL`,避免混淆。 | 输入 | 实际 events | atomic | tile16 | tile32 | | --- | ---: | ---: | ---: | ---: | | 普通 | 12,765 | 26.423 | 18.511 | 19.286 | | 银心视场 | 16,384 | 31.803 | 22.621 | 23.247 | | 强放大 | 16,384 | 26.536 | 23.814 | 25.388 | | 银心视场 | 65,536 | 104.107 | 69.823 | 73.093 | | 同等贡献分散对照 | 65,536 | 85.302 | 104.389 | 79.899 | 含公共 GPU 创建的 65,536 密集回放为 137.111 / 102.323 / 105.949 ms。 强放大 tile32 回放范围 22.801–29.410 ms,atomic 25.932–27.395 ms;三次样本不足以 证明这里的稳定提升。完整数值、范围和全部重复见 [summary.log](hip_psf_replay_2026-09-07/summary.log) 与 `final_*.log`,由 [final_cases.py](hip_psf_replay_2026-09-07/final_cases.py) 串行生成。 分阶段日志同时记录实际贡献吞吐量。atomic 上传/kernel/download 使用 HIP event; 候选分桶为 CPU wall,prepare/accumulation/merge 为包含 launch+stream sync 的 host wall。 它们不能拿来做精确的纯 kernel 周期归因,完整回放 wall 才是算法比较依据。 分散 tile16 的分桶本身约数十 ms,足以抵消其累积优势。 [编译器资源记录](hip_psf_replay_2026-09-07/device_resources.log) 显示 atomic kernel 62 VGPR,prepare 37,tile accumulation 21,merge 18,private segment 均为 0。 生成的 atomic 代码仍有三个 `global_atomic_cmpswap_b64` 循环;候选不需要它们。 这不是运行时 cache/occupancy/FP64 counter 测量,不能据此分摊 atomic contention 的比例。 没有使用降低 HDR 精度、近似黑体颜色或改变 min-Y/tail 的方法。 ## CPU producer 独立测量 诊断 consumer 在正常查询、inverse mapping、频移、黑体积分与 prepare/classification 之后,仅计数与计算摘要。输出明确标记 `DIAGNOSTIC ONLY, no HDR`。 parallel 模式每 worker 计数/摘要独占;汇总 checksum 与事件顺序无关,串行捕获仍保留顺序。 indexed 模式从同一有界 CSV 预构建原生一度 tile 索引,worker 查询前已完全只读,不执行 I/O。 为了比较完整相同工作而不受事件上限/调度停止次序影响,银心诊断 triangle 范围缩为 `[0,40151)`,其他仍 `[0,130882)`。所有以下运行均未触顶,四种模式逐项核对 cached/wing/direct/discarded/events 和 checksum 完全一致。各三次中位数: | 输入 | events | memory/1 worker | memory/16 | indexed/1 | indexed/16 | | --- | ---: | ---: | ---: | ---: | ---: | | 普通 | 12,765 | 2.8123 s | 0.3502 s | 0.0729 s | 0.0125 s | | 银心视场 | 16,895 | 1.1472 s | 0.1383 s | 0.0535 s | 0.00986 s | | 强放大 | 16,454 | 1.3845 s | 0.1493 s | 0.6836 s | 0.0751 s | CSV 全扫描明显夸大查询成本;生产判断应使用 indexed 列。强放大子集遍历大量分散 triangle, 其独立 producer 时间在这一小输入上高于 GPU 回放,说明进一步加速 GPU 未必改善同等比例的 端到端时间。这不是全天 CPU 下限,也不能与另一事件数量的回放直接相减。 未修改黑体积分;没有把 `summed generation / workers` 当作独立计时。 ## 正确性与失败记录 - 全部真实回放、分散对照和最终 45 次独立复测通过 finite/double HDR 检验。 - [边界 fixture](hip_psf_replay_2026-09-07/fixture_generate.log):32,771 events,33 wing-clipped, exact/intermediate phases、屏幕内外、热点、三 chunk/缓冲复用。atomic、tile16、tile32 均覆盖中途 finish/download → CPU direct → upload → 继续累积。 - 全部最终+边界最大 `max_abs=5.96856e-11`、`max_rel=5.98529e-13`;最坏 RGB 总通量 相对差≤2.83419e-14,Y≤1.15193e-14。沿用旧 replay 的 abs/rel<1e-10,另增加总 RGB/Y 相对误差≤1e-10 的检查,没有为结果放宽门槛;现有生产 primitive 的 rel≤1e-12 也通过。 - [捕获/索引诊断回归](hip_psf_replay_2026-09-07/capture_indexed_regression.log)通过:真实 mixed classification cached=2/direct=1,min-Y 场 discarded=3;串行/并行/索引摘要一致;验证 event cap、非法范围、拒绝覆盖已有文件。未用提高 min-Y 代替 producer 测量。 - [HIP primitive](hip_psf_replay_2026-09-07/hip_primitive.log)、 [Minkowski mixed/min-Y integration](hip_psf_replay_2026-09-07/minkowski_integration.log)通过。 - [Schwarzschild CPU](hip_psf_replay_2026-09-07/schwarzschild_cpu.log) / [HIP](hip_psf_replay_2026-09-07/schwarzschild_hip.log)同一 8,192 星子集分类一致; [24,883,200 个 FITS float32 样本完全一致](hip_psf_replay_2026-09-07/schwarzschild_hdr.log)。 此处测试的是保留的生产路径;tile 原型的 double 正确性由回放验证,不冒称已接入 renderer。 - [`make -j1 test`](hip_psf_replay_2026-09-07/cpu_regression.log)通过(33.44 s)。 保留三类早期非零退出:沙箱未暴露 GPU、v2 分散输入的 scratch 超限、读取器误拒绝合法 wing-clipped support。后者的修复保留 event 的物理 support,仅在实际遍历时限制 cache 范围。 未删失败日志,未在任何失败后不加分析自动扩大测试规模。 ## 最小复现 从仓库根目录先按 [build_commands.txt](hip_psf_replay_2026-09-07/build_commands.txt) 构建。 固定输入已随报告保留;原大 catalog/lens map hash 在 manifest。已有日志拒绝覆盖,重复 运行请使用新标签和新的事件输出路径: ```sh python3 benchmarks/hip_psf_replay_2026-09-07/run.py repeat_capture 60 \ build/Release/capture_psf \ output/lens/schwarzschild_galactic_center_R100_45deg_16_4_4k_.grlens \ benchmarks/hip_psf_replay_2026-09-07/center.csv \ 0 130882 65536 /tmp/gr-psf-repeat.events 1e13 1e8 0 0 2 python3 benchmarks/hip_psf_replay_2026-09-07/run.py repeat_atomic 45 \ build/Release/replay_psf /tmp/gr-psf-repeat.events 65536 atomic python3 benchmarks/hip_psf_replay_2026-09-07/run.py repeat_tile16 45 \ build/Release/replay_psf /tmp/gr-psf-repeat.events 65536 16 python3 benchmarks/hip_psf_replay_2026-09-07/run.py repeat_tile32 45 \ build/Release/replay_psf /tmp/gr-psf-repeat.events 65536 32 ``` 以上是重跑示例,`repeat_*` 标签本次未执行;实际执行命令逐条保存在各原始日志。