Files
GR-raytracing/gpu_psf_acceleration_plan.md
T
wyj 2fc2b43e8d Doc: Record production PSF chunk geometry
Preserve the protected full-catalog dummy run, its initial harness failure, input and output hashes, distribution quantiles, and the resulting sparse-tile scheduling conclusions.
2026-09-11 23:28:02 -04:00

316 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GPU PSF 累积计划
## 2026-09-07 更新
有界实测后,production HIP 已改为 32-thread/event 协作 kernel,并恢复 OpenMP
catalog/inverse-map/颜色计算。每个 worker 拥有一个 16,384-event 私有块,共享的
GPU sink 只在批量提交和完整 CPU direct-fallback 边界加锁,保留单份 cache/HDR。
两个 pinned host/device slot 通过 kernel completion event 控制复用;所有 batch
均计时,长任务会周期报告已提交与已回收的完成事件数。详细结果、限制、重现命令及
原始输出见 [有界排查记录](benchmarks/hip_psf_2026-09-07.md)。
三种受控事件分布支持协作 kernel 的收益;真实三 tile 子集也改善了端到端耗时。
没有据此把全部 kernel 时间归因为 atomic contention,未引入 tile-local reduction、
float HDR 或黑体近似。下面第 7 节的 2026-09-05 状态是历史基线,单线程 producer
和前 64 批计时限制已被此次实现取代。实际 `PsfCachedEvent` 为 56 B,16,384 项为
896 KiB;早期按 24–32 B 估算的整帧内存不是当前结构的实际成本。
## 后续实施结果(2026-09-07)
已实施有界真实事件捕获、CPU/当前 HIP/16×16/32×32 回放、按像素归约原型与
独立 producer 诊断;原型包含 phase/行边界复用,以及稀疏 tile 直接写回、密集列表
部分和合并。固定输入、manifest、完整原始日志与结论见
[HIP 回放实验](benchmarks/hip_psf_replay_2026-09-07.md)。
production HIP 尚未替换为 tile 算法;收益与事件分布有关,不能由局部回放推算
全天加速比。未运行完整全天 catalog。测试工具与原型已于 2026-09-11 提交为
`7f5ec1a`;以下保留原执行计划作为验收依据。
同日后续实验在 replay 中增加了按 chunk 的中心 tile 密度选择器。当前 RX 9070 配对数据中,
65,536-event 银心输入的 adaptive/atomic/tile16 中位数为 67.834/95.018/67.354 ms,
同贡献分散输入为 80.092/78.203/99.693 ms;选择扫描中位成本不超过 0.455 ms。
mixed fixture 已覆盖同一 stream 内 atomic、tile 与 direct fallback 的组合。结果支持下一步
做 production 流式集成原型,但选择器和 tile sink 目前仍只在测试程序中,未改变生产默认。
随后用只计数的 `PSF_BACKEND=dummy` 跑过用户给定的 45 度 Schwarzschild 银心全天命令,
没有启动 HIP,也没有写 HDR/PNG。598,264,924 个 cache event 中有 36,508 个满
16,384-event chunk;满 chunk 的 event-producing triangle 数 p50/p75/p90/p99 为
2/3/10/31,occupied 32px center tile 数为 1/2/5/30,全部满足当前 adaptive tile16
阈值。这把“dense replay”提升成了真实 production producer 顺序的证据,支持把 adaptive
tile16 接入 production sink 作为下一步候选。限制是 16-worker dynamic schedule 会有运行间
波动,而且 p99 chunk 含相距约 3.7K px 的稀疏簇;实现必须保留稀疏 tile 列表和 atomic
fallback,不能假定单一连续小矩形。详见
[dummy chunk 全量记录](benchmarks/dummy_psf_chunks_2026-09-11/README.md)。
## 下一步执行计划(2026-09-07,原计划;有界实验已实施)
### 依据与目标
当前实现基线为 `e1ec480669b0d24a0266ee135edf8a64a0d80ec9`。用户完成的
[全天 CPU/HIP 记录](benchmarks/2mass_galactic_center_cpu_hip_2026-09-07.md)
中,HIP 总耗时 533.06 s,splat 阶段 481.2 s,其中 kernel 476.906037 s、
event upload 1.504570 s。下一步优先降低 GPU PSF 累积成本,暂不优先优化
geodesic、增加 CPU workers 或改造传输流水线。
用户随后提供的同一 lens map 导入 CPU 运行总耗时 1402.02 s,splat 阶段
1350.3 s;与 HIP 对应的时间比分别为约 2.63 和 2.81。这组后续数据来自本次
会话,尚未在上述 benchmark 中归档完整原始日志。单星重新生成几何的 67.35 s
包含固定开销,也支持几何不是当前主要成本;它不是独立的纯 tracing 计时。
kernel 占比高不能单独证明 atomic contention 主导。以下分桶原型用于检验这个
假设,不预先承诺加速倍数,也不直接替换 production 路径。
### 1. 建立有界真实事件回放
- 从小型 catalog 子集和已有 lens map 的选定 triangles 捕获正常准备后的
`PsfCachedEvent`,覆盖普通区域、银心密集区域和强透镜区域。保留位置、颜色、
flux、support、事件顺序及相匹配的 PSF cache 参数;不收集完整六亿事件。
- 捕获器必须限制输入子集、triangle 范围和输出事件数,不能只限制输出文件大小、
却仍遍历整个全天 catalog。记录输入与事件文件 hash、选择规则和实际覆盖分布。
- 首轮按 4,096、16,384、65,536 events 递增;单次回放上限 45 s,小型 renderer
上限 60 s。超时后先分析,不自动扩大规模。空间分散的合成对照单独标记,保持
事件数、flux 和 support 分布可比,避免把屏幕裁切减少的工作量当作收益。
- 对同一回放比较 CPU double reference、当前 32-thread/event kernel 与候选算法。
除 events/s 外,统计实际 event–pixel 贡献数和贡献吞吐量;拆分上传、分桶、
累积、合并、下载时间,并测量整个回放 wall time 与内存峰值。
交付物:有界捕获/回放工具、固定输入与 manifest、完整命令及原始日志。
先获得可重复的当前基线,再进入候选算法对照。
### 2. 原型验证按像素归约
- 分别试验 16×16 和 32×32 screen tiles。根据事件完整 support 构建每个 tile
的事件列表;一个事件可引用到多个 tile,不能只按中心归属,否则会丢失 PSF wings。
- 让线程拥有输出像素,在寄存器中用 double 累积 RGB,再写回 HDR。继续使用现有
四点 phase cache 插值、圆形 support 和裁切判定。目标是消除每个贡献的全局
double atomic,而不是改用低精度或减少物理贡献。
- 密集 tile 的长列表可拆成独立的部分和,再用第二阶段归约,避免一个热点 tile
限制并行度。明确部分和的 ownership、写回顺序和 scratch 生命周期。
- 保持有界 chunk;限制 tile 引用列表及部分和内存,检查索引溢出并明确超限处理。
不依赖整帧事件常驻内存。分桶、空像素遍历、合并和 buffer 清理都计入成本。
- 原型与现有 kernel 并存。若减少 atomics 后仍无收益,结合回放和设备分析检查
cache 权重读取、FP64 算术、寄存器压力与负载分布;不把失败解释为必须降低精度。
进入生产集成的条件:正确性通过,且包含分桶/合并的完整回放在代表性样本上有
可重复收益。只有 kernel 单项变快而整体变慢时,不替换当前实现。第 4、7 节原有的
tile-local 门槛在此区分为“允许有界实验检验假设”和“有收益证据才保留生产实现”。
### 3. 测量 CPU producer 独立吞吐
提供诊断 sink:保留正常 catalog 查询、inverse mapping、频移、黑体颜色、
cache/direct/min-Y 判定和事件准备,仅将累积消费替换为计数与校验摘要。
明确标记诊断输出,不能把未累积的 HDR 当作正常渲染结果。
先在同一有界输入运行该模式,测量 producer wall time,必要时细分查询、映射与颜色
计算。不要用提高 min-Y 的方式替代它:那会提前改变执行路径。现有 summed worker
generation 的 `3302.459 / 16 ≈ 206 s` 仅是粗略线索,受等待和调度影响,不能作为
独立 CPU 下限。GPU 加速后若 producer 成为限制,再据测量选择优化对象;黑体近似
或查表不在本轮默认范围内。
### 4. 正确性、集成与测试纪律
- 保持 double HDR、亚像素 phase、support、wing clip、min-Y 与 direct fallback
语义;包含跨 tile、屏幕边缘、不同 phase、大 support、热点、多 chunk、buffer
复用和混合 direct fallback 的用例。fallback 前须完成待处理 GPU 工作,保持
下载、CPU 累积、上传的完整顺序。
- 验证 finite 值、事件及分类计数、double linear HDR 的绝对/相对误差和总 RGB/Y
通量差;近零值不单用相对误差。沿用现有测试门槛作为起点,若需调整必须解释
数值原因并记录误差证据,不为通过测试任意放宽。
- 归约顺序会变化,不能承诺 PNG 比特级一致。PNG 比较是补充,不能代替 double
HDR 检验。先通过 PSF 单元回放,再做小型 Minkowski、Schwarzschild 集成回归。
- 所有测试进程严格串行;启动前确认没有前一测试仍在运行,超时后确认退出再继续。
不同时运行 CPU/HIP 对照,也不让 profiler 与另一测试竞争设备。
- 本计划不授权重跑完整全天渲染。先完成有界验证和性能证据,再决定是否需要完整
验证;没有完整运行就不宣称整帧加速比。保存 Git/binary hash、构建命令、设备与
runtime、线程、输入/cache、所有阶段计时和原始终端输出。
- 实施后同步设计文档第 22.3 节及 benchmark。原计划写入时尚未实现或执行测试;当前进展见上方实施结果,
后续提交仍须由用户明确授权。
## 1. 目的与边界
本文件规划的是**最终点源 PSF 到 HDR framebuffer 的累积**加速,而不是 GPU
geodesic tracing,也不是改变 catalog、lens map 或物理模型。
当前单帧数据流保持为:
```text
image-plane mesh -> backward ray tracing -> final lens map
-> catalog query / inverse mapping -> (x, y, linear RGB, PSF parameters)
-> PSF splat -> HDR framebuffer
```
GPU 后端只替换最后的 `PSF splat -> HDR framebuffer`。CPU 仍负责 catalog 读取、
source-triangle 查询、inverse mapping、magnification、frequency shift、黑体颜色和
`--psf-min-y` 判定。它们已经在 PSF 累积之前完成;被 `--psf-min-y` 丢弃的事件不得
上传到 GPU。
这使得光追和 PSF 是按阶段顺序执行的任务。数值时空的 time slabs 在完成 lens map 后
已经可以释放,不能把它们同 GPU PSF framebuffer、cache 或事件块当成同时占用的显存。
CPU 实现始终是正确性基线和所有机器的 fallback。GPU 是可选的 `optics/psf` 后端,不得
改变亚像素位置、Moffat 参数、`--psf-relative-tail`、`--psf-min-y`、亮星 cache/direct
fallback 语义或 HDR 输出定义。
## 2. 目标机器
| 机器 | CPU / GPU | 计划角色 |
| --- | --- | --- |
| 工作站 | i7-12700K 的 8P/16T 配置;RX 9070 系列、16 GB | GPU 原型与高吞吐生产渲染机 |
| ITX | i5-10500 ES、6C/12T;Intel 核显 | CPU-only 基线;核显只在实际基准证明有益后启用 |
| Optiplex | i7-7700、4C/8T;Radeon Pro WX 4100、4 GB | 低端离散 GPU 兼容性和加速收益测试机 |
## 3. 后端接口与事件流
默认路径不构建“全帧所有星像”的事件数组,而是流式提交有限大小的事件块。数亿事件即使
每项仅 24--32 B,也会使 host-device 流量达到十余 GiB;在内存较小的机器上,整帧数组也会
造成不必要的主存峰值。
ATRI 工作站有 128 GB RAM,因此可以提供一个明确的、可选的整帧收集模式。以约 4.92 亿
事件为例,24 B/event 约为 11.0 GiB,32 B/event 约为 14.7 GiB;即使加上索引、分桶工作区、
CPU HDR 与 catalog,仍有可用空间。其可能收益不是减少需要传给 GPU 的总事件数,而是:
- 先按屏幕 tile 或 Morton order 重排事件,使 GPU 输入有更好的空间局部性;
- 一次得到准确的各 tile 负载,用于安排多个 kernel launch / workgroup;
- 为 tile-local reduction 预先构造连续的 event ranges,避免 GPU 端动态分桶;
- 将 PCIe 传输与多个 GPU 批次的执行安排得更稳定。
这是一条 ATRI 专用的空间换时间路线,必须以端到端实测证明收益后才保留。它不应成为 ITX、
Optiplex 或通用 CPU fallback 的前提;在这些机器上仍使用流式块。
当前 CPU 已在 `optics` 层建立 cache-eligible 的事件边界:
```c
typedef struct {
double x, y;
LinearRgb color;
double flux, support_radius;
} PsfCachedEvent;
```
`psf_prepare_cached_event()` 保留既有的 cache/direct/min-Y 判定,状态 0 或 2 产出该
事件;direct fallback 在 CPU 立即处理,min-Y 在上传前丢弃。`PsfEventSink` 由每个 OpenMP
worker 初始化一次、贯穿其线程生命周期,固定容量为 16,384 个事件;填满或线程结束时由现有
CPU cache evaluator 消费。此实现是 GPU producer 的正确性基线,并已通过固定 HDR reference
和完整 2MASS 前后性能记录验证。
GPU sink 将消费同一 `PsfCachedEvent` 与现有不可变 `PsfKernelCache::weights`,不得重新以
float 解析采样替代 cache 语义。首版使用有限大小的上传块并复用 device buffer;块大小从
1--16 MiB 试起,由实测决定。GPU 后端仍必须统计:cache splat、wing clip、direct fallback
和 min-Y discarded;这些计数在块完成后汇总,而不是在热循环中同步。
为降低局部热点,CPU 侧应把来自不同 image-plane triangle / worker 的事件块交错提交。
三角形内部的星像中心必定落在各自不重叠的像平面三角形内;不同三角形的 PSF wings 仍可
重叠,故这只是改善 GPU work distribution 的低成本手段,不是互斥性假设。
## 4. GPU 累积的两级方案
### A. direct global atomic 原型
一个 GPU thread 或 thread group 处理一个 PSF event,遍历其圆形支持域,并对 HDR pixel
做浮点 atomic add。这是最小的实现,适合先测:PCIe 上传、cache 读取、PSF 算术和热点
atomic contention 各自占比。
`atomic add` 的含义是“读、加、写”不可被另一线程插入;它保证多个 thread 同时向同一
pixel 加光通量时不丢更新。它不减少物理贡献次数,也不保证浮点加法顺序,因此 GPU 输出
应以容差同 CPU reference 比较,而非要求 bitwise 相等。
### B. tile-local reduction
若 direct atomic 在银河中心等密集区域成为瓶颈,则按屏幕 tile(例如 16x16 或 32x32
pixels)分桶事件。一个 GPU block 是一组共同被调度的 threads;block 内可使用 shared
memory,即该 block 专用、片上、速度快的小型临时数组。threads 先把本 tile 的许多 PSF
贡献累积在 shared memory,最后每个 HDR pixel 只写回全局 framebuffer 一次或少数几次。
这没有少算任何光,而是把大量对同一全局 HDR pixel 的竞争写入,转换为 block 内的局部
累积。代价是分桶、边界 PSF、跨 tile wings 和负载不均衡的实现复杂度。只有 direct 原型
证明 atomic 是主要瓶颈时才进入这一步。
## 5. API 选择
### HIP / ROCm
- 适合工作站 RX 9070 的最快原型;宿主端和 kernel 都接近 C/C++ 工作流。
- 用它验证算法与性能,尤其是 direct atomic 和 tile reduction。
- Gentoo 能否稳定运行由本机实际 driver/runtime、功能探测、正确性测试和长跑决定;不得用
厂商“受支持发行版”名单作为可用与否的判断标准。
- WX 4100 / Polaris 不应被假定能运行当前 ROCm 栈。因此 HIP 是高性能候选,不是三机共同
的部署承诺。
### Vulkan compute
- 是跨 Intel 核显、WX 4100 和 RX 9070 最有价值的正式可选后端;使用现有图形驱动的 Vulkan
compute path,宿主端保持 C。
- shader 编译为 SPIR-V;启动时枚举设备、显存、workgroup 限制和所需 feature。
- 浮点 `atomicAdd` 不是 Vulkan core。direct-atomic 路径必须检查
`VK_EXT_shader_atomic_float` 的对应 feature;没有则不能悄悄降级为错误结果。
- 不支持 float atomic 的设备可走 tile-local reduction,或明确回退 CPU。后者是首版可接受
行为。
### OpenCL
- 可作为单机实验或能力探测选项,但不作为主线接口。
- 各 Gentoo 主机上具体 OpenCL ICD、Mesa/Rusticl 或 AMD runtime 的设备暴露和 feature 组合
需实际检查,不能从 API 名称推断。
- 若未来 Vulkan 覆盖不足,再基于真实测得的设备矩阵决定是否值得维护 OpenCL 后端。
## 6. 精度与验收
GPU 后端必须先在小、固定 catalog snapshot 上同 CPU 的 `--psf-direct` 或 cache reference
对比。比较 linear HDR RGB/Y,而不是仅比较 tone-mapped PNG。
验收项:
1. 相同输入、固定输出尺寸、固定 PSF 参数与固定 catalog tile set。
2. 记录每通道绝对/相对误差、最大像素误差、总 RGB/Y 通量差和事件统计。
3. 单星(不同 phase、亮/暗、边缘和大 support)、稀疏场、密集重叠场各有测试。
4. 验证 `--psf-relative-tail`、`--psf-min-y`、cache/direct fallback 的统计及图像语义一致。
5. 当用户显式选择 GPU 后端时,GPU 不可用、feature 不足、初始化失败或运行错误必须明确报错
并终止该次渲染;不得回退 CPU 或默默输出部分帧。未选择 GPU 时,CPU 路径仍是独立基线。
6. 以端到端 wall time 为准,同时记录 CPU 线程数、GPU、driver/runtime、块大小、分辨率、
catalog snapshot、Git hash 和参数。
浮点原子加法的规约顺序随调度变化,GPU 与 CPU double HDR 不会 bitwise 相同。这是可量化的
数值差异;容差要由上述固定输入对照决定,而不是预先假设。
## 7. 实施顺序
### 当前状态(2026-09-05)
已完成 CPU event 路径:`PsfCachedEvent`、`psf_prepare_cached_event()` 与 per-worker
`PsfEventSink` 已进入 `frame_splat_catalog()`。固定 HDR reference 与 unit tests 验证该路径
不改变输出;在 2MASS 全天 1080p 的前后比较中,完整 event 实现相对无 event 路径版本增加
0.99% user CPU work。该记录含完整命令和原始输出,见
`benchmarks/2mass_all_sky_psf_event_sink_2026-09-05.md`。
曾有一个 float、解析中心采样的 HIP atomic spike,用于确认 HIP runtime、上传与 float atomic
可执行;它没有 cache 权重、双精度 HDR 或 production integration。其 `test-hip` target 和测试
已移除,不能作为 renderer GPU backend 的验证或运行入口。
HIP direct-atomic 的当前实现状态:
1. 已定义 production HIP sink 的 C ABI,上传 double event 与 immutable cache 权重,并复用
device/HDR buffer。正式构建选项为 `PSF_BACKEND=cpu|hip`;HIP 选择会把该层链接到 renderer,
而 CPU 选择不要求 HIP 工具链或 runtime。
在 RX 9070(gfx1201)上,`make -B PSF_BACKEND=hip SPACETIME=minkowski hip-psf-test`
的三事件重叠 cache 对照给出 `max_abs=3.4694469519536142e-18`、
`max_rel=2.7555746842446215e-16`。
2. 已接入 `frame` 的流式 sink。`PSF_BACKEND=hip` 使用单一 GPU double HDR framebuffer;
cache 事件按 16,384 项块提交,仍使用既有 bilinear phase cache、圆形支持和 wing clip 规则。
direct fallback 会完成前序 GPU 工作、在 CPU 计算、再上传 HDR 后继续,因而保持提交顺序。
3. RX 9070 上的 640×360 固定 Minkowski catalog HDR 对照逐样本一致;含 2 个 cache 事件与
1 个 direct fallback 的 `tests/data/hip_psf_mixed_catalog.csv` 场同样逐样本一致。GPU failure
会打印阶段与 HIP 错误并令该帧返回失败,不会切换到 CPU backend。
4. 已在 RX 9070 上记录一个受控的高密度 endpoint:54,160 星的 1920×1920、0.6 deg
2MASS tile 产生 26,172 个 cache event、零 direct fallback。HIP 的 2 个 batch 中 H2D
为 0.073 ms、kernel 为 2.950 s、D2H 为 11.256 ms;CPU/HIP PNG 字节一致。完整命令、
原始输出、Git 基线、线程、设备、分辨率和 PSF 参数见
`benchmarks/hip_psf_direct_atomic_dense_tile_2026-09-05.md`。
5. 该 endpoint 说明当前时间主要位于 device kernel,而非 PCIe;它**不能单独证明** kernel
时间主要来自热点 atomic contention(仍混有每 event 的 PSF 遍历与 cache 读取)。因此暂不
实现 tile-local reduction。下一步应在资源隔离条件下,以不同屏幕密度和 PSF 支持域分离竞争
效应;只有该证据显示竞争为主导且 tile-local 的整帧端到端测量获益时,才保留分桶/重排实现。
ATRI 的整帧收集/重排同样必须以端到端收益证明。
6. HIP 路径稳定后再评估 Vulkan 的可移植后端及其他机器的实际设备矩阵。
每一步独立提交,并保持 CPU reference、GPU runtime 层和 shader 资源的提交边界清晰。