性能基准测试
本项目不会将任何单一基准测试表视为普遍真理。WebGPU 性能在很大程度上取决于浏览器版本、驱动质量、GPU 架构、数组大小,以及你是否能在多次运行之间复用缓冲区。
如何评估性能
使用交互式 Demo在你自己的机器上测试当前构建。比较以下指标:
- GPU 时间 - 仅计算工作
- 总时间 - 上传、计算和回读合计
- CPU 时间 -
TypedArray.sort()作为本地基准
通常最重要的因素
输入大小
小数组通常更倾向于 CPU,因为缓冲区传输开销占主导地位。更大的数组才是 GPU 排序发挥作用的场景。
复用
当你复用同一个 GPUContext 并在多次运行之间保持缓冲区存活时,重复排序的性能会更好。
算法选择
| 使用场景 | 更好的起点 | 原因 |
|---|---|---|
| 通用参考实现 | BitonicSorter | 结构可预测,推理更简单 |
大型 Uint32Array 工作负载 | RadixSorter | 对整数密集型数据的浪费比较更少 |
| 小型或一次性数组 | CPU 排序 | 设置成本更低 |
基准测试工作流
- 从小数组开始并确认正确性。
- 增加数组大小,直到传输开销不再占主导地位。
- 比较 GPU 专用时间与总时间;两者都很重要。
- 重复相同的运行数次,以平滑着色器编译和预热效果。
解读结果
- GPU 时间更快,总时间更慢 通常意味着着色器工作没问题,但传输/设置开销占主导地位。
- GPU 时间和总时间都更快 表明浏览器/GPU 非常适合该工作负载。
- Radix 比 Bitonic 慢 可能发生在较小的数组上,额外的趟次无法很好地摊销。
实用技巧
复用同一个上下文
ts
const gpu = new GPUContext();
await gpu.initialize();
const sorter = new BitonicSorter(gpu);
await sorter.sort(batchA);
await sorter.sort(batchB);当大小可预测时预分配
ts
const sorter = new RadixSorter(gpu);
sorter.preallocate(1_000_000);同时衡量正确性和吞吐量
在开发时启用验证,当你只需要原始吞吐量测量时再禁用它。
运行你自己的基准测试
仓库附带了一个专门为此目的维护的浏览器测试场。打开交互式 Demo,选择你的工作负载大小,并在目标机器上比较 Bitonic、Radix 和 CPU 的耗时。