libcudf 中的单元基准测试是使用 NVBench 编写的。虽然许多现有基准测试是使用 Google Benchmark 编写的,但新的基准测试应使用 NVBench。
NVBench 库类似于 Google Benchmark,但在进行 GPU 基准测试时提供了一些质量改进,例如显示达到峰值内存带宽的比例以及 GPU 硬件的详细信息。
NVBench 和 Google Benchmark 都提供了许多选项,用于指定要进行基准测试的参数范围,以及控制报告的时间单位等。请参阅 cpp/benchmarks
中的现有基准测试以了解这些选项。
单元基准测试目录和源文件的命名应与被测功能保持一致。例如,copying.hpp
中 API 的基准测试应放在 cpp/benchmarks/copying
目录下。每个功能(或一组相关功能)应有其自己的基准测试源文件,命名为 <feature>.cu/cpp
。例如,cpp/src/copying/scatter.cu
的基准测试位于 cpp/benchmarks/copying/scatter.cu
中。
为了提高编译时间,只要可能,测试源文件应使用 .cpp
文件,因为 nvcc
在编译主机代码时比 gcc
慢。请注意,thrust::device_vector
包含设备代码,因此只能在 .cu
文件中使用。rmm::device_uvector
、rmm::device_buffer
以及 测试 中描述的各种 column_wrapper
类型可以在 .cpp
文件中使用,因此在测试代码中优先于 thrust::device_vector
。
CUDA 计算和诸如复制等操作通常相对于主机代码是异步的,因此仔细同步非常重要,以确保基准测试计时不会在被测功能完成之前停止。cpp/benchmarks/synchronization/synchronization.hpp
中提供了一个 RAII 辅助类 cuda_event_timer
来帮助实现此目的。该类还可以选择清除 GPU L2 缓存,以确保缓存命中不会在重复迭代中人为地夸大性能。
为了生成基准测试输入数据,辅助函数可在 cpp/benchmarks/common/generate_input.hpp 中找到。输入数据生成发生在设备端,这与 column_wrapper
中数据生成发生在主机端不同。
create_sequence_table
可以生成序列列,第一行从值 0 开始,后续行递增 1。create_random_column
可以生成填充随机数据的列。随机数据参数是可配置的。create_random_table
可以生成填充随机数据的列组成的表。随机数据参数是可配置的。一般来说,我们应该在各种数据大小和类型范围内对所有功能进行基准测试,以便能够发现 libcudf 更改导致的性能回归。然而,运行大量基准测试成本很高,因此理想情况下,我们应该以一种在不进行穷举测试的情况下获得良好覆盖率的方式来采样参数空间。
经验法则是,我们应该使用足够的数据进行基准测试,以便算法达到其饱和瓶颈点,无论该瓶颈是带宽还是计算。使用大于此点的数据集通常没有帮助,除非在特定情况下,这样做可以锻炼不同的代码,从而揭示较小基准测试无法发现的性能回归(这种情况应该很少见)。