Files
GR-raytracing/gpu_psf_acceleration_plan.md
T
wyj e1ec480669 HIP: accelerate PSF accumulation and restore parallel producers
Cooperate across 32 lanes per PSF and use two completion-protected staging slots with complete batch timing. Restore coarse OpenMP event production while serializing shared GPU submissions and direct fallback boundaries.

Add bounded benchmarks, streaming and renderer regressions, and preserve validation evidence and ownership documentation.
2026-09-06 21:38:53 -04:00

205 lines
12 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 估算的整帧内存不是当前结构的实际成本。
## 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 资源的提交边界清晰。