Files
GR-raytracing/benchmarks/hip_psf_replay_2026-09-07.md
T
wyj 776f9b7247 Test: Add adaptive HIP tile replay selection
Add a bounded per-chunk center-tile selector to the real-event replay prototype and retain the paired timing, mixed-boundary, CPU, HIP, and sandbox-failure evidence.
2026-09-11 23:27:24 -04:00

16 KiB
Raw Blame History

HIP PSF 有界真实事件回放与像素归约实验(2026-09-07)

结论与交付

已实施原计划的有界捕获/回放、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;
  • 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 并发。

实现入口:

环境与测量纪律

Git 基线 5eccc31c99db96de2a0597babf2fd4c2149e91e7,测量时在此基础上有未提交修改。 没有覆盖用户已有的计划修改。生产 src/hip_psf.hip 未改;src/frame.c 的诊断钩子 仅在 standalone 测试编译时启用。每次直接执行的 binary SHA256 在相应日志中; 源码、binary、lens map hash、 宿主环境、 构建命令与 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 和 重建脚本。没有遍历完整全天 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。三种真实输入的 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 与 final_*.log,由 final_cases.py 串行生成。

分阶段日志同时记录实际贡献吞吐量。atomic 上传/kernel/download 使用 HIP event; 候选分桶为 CPU wall,prepare/accumulation/merge 为包含 launch+stream sync 的 host wall。 它们不能拿来做精确的纯 kernel 周期归因,完整回放 wall 才是算法比较依据。 分散 tile16 的分桶本身约数十 ms,足以抵消其累积优势。

编译器资源记录 显示 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: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 也通过。
  • 捕获/索引诊断回归通过:真实 mixed classification cached=2/direct=1,min-Y 场 discarded=3;串行/并行/索引摘要一致;验证 event cap、非法范围、拒绝覆盖已有文件。未用提高 min-Y 代替 producer 测量。
  • HIP primitive、 Minkowski mixed/min-Y integration通过。
  • Schwarzschild CPU / HIP同一 8,192 星子集分类一致; 24,883,200 个 FITS float32 样本完全一致。 此处测试的是保留的生产路径;tile 原型的 double 正确性由回放验证,不冒称已接入 renderer。
  • make -j1 test通过(33.44 s)。

保留三类早期非零退出:沙箱未暴露 GPU、v2 分散输入的 scratch 超限、读取器误拒绝合法 wing-clipped support。后者的修复保留 event 的物理 support,仅在实际遍历时限制 cache 范围。 未删失败日志,未在任何失败后不加分析自动扩大测试规模。

最小复现

从仓库根目录先按 build_commands.txt 构建。 固定输入已随报告保留;原大 catalog/lens map hash 在 manifest。已有日志拒绝覆盖,重复 运行请使用新标签和新的事件输出路径:

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_* 标签本次未执行;实际执行命令逐条保存在各原始日志。