1. 什么是 GDS(GPUDirectStorage)
GDS 允许 RDMA 网卡直接访问 GPU 内存,有助于增加 GPU 应用读写文件的 IO 带宽,减少 IO 时延,并降低其 CPU 负载。
客户端在开启 GDS 特性后,文件将以 O_DIRECT
方式打开,客户端不会再缓存文件数据。应用层读写文件时,客户端通过 nvidia-fs.ko 将应用层的 GPU 内存地址转换成 DMA 地址,并将其发送到服务端,由服务端 RDMA 网卡负责对客户端的 DMA 地址读取或填充。
2. 使用要求
2.1 系统要求
Ubuntu 20.04,Ubuntu 22.04,Ubuntu 24.04,RHEL 8, RHEL 9
2.2 存储要求
在使用 GDS 时,需要应用层调用 cuFile API 才能正常工作。只有有限的存储系统实现了对 GDS 的支持:
- NVMe
- NVMeOF
- SCSI
- ScaleFlux CSD
- NVMesh
- DDN EXAScaler
- IBM Spectrum Scale
- NFS
- BeeGFS
- WekaFS
- …
这里有一份 2021 年底的支持列表可以参考: https://developer.nvidia.com/zh-cn/blog/accelerating-io-in-the-modern-data-center-magnum-io-storage-partnerships/
3. 安装 GDS
3.1 安装依赖项
1
2
3
4
5
| export distro=ubuntu2004
export arch=x86_64
wget https://developer.download.nvidia.com/compute/cuda/repos/$distro/$arch/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
apt-get update
|
1
2
3
| apt list --installed | grep nvidia-fs
apt-cache search nvidia-fs
apt-get install nvidia-fs-dkms nvidia-fs
|
1
2
3
| nvidia-smi | grep "Driver Version"
| NVIDIA-SMI 535.129.03 Driver Version: 535.129.03 CUDA Version: 12.2 |
|
安装之前需要检查一下是否已经安装,再去寻找与 Driver 版本匹配的版本。
1
2
3
| apt list --installed | grep libnvidia_nscq
apt-cache search libnvidia-nscq
apt-get install libnvidia-nscq-535
|
安装之前需要检查一下是否已经安装,再去寻找与 Driver 版本匹配的版本。
1
2
3
| apt list --installed | grep fabricmanager
apt-cache search fabricmanager
apt-get install nvidia-fabricmanager-535
|
3.2 安装 GDS
1
2
3
| apt list --installed | grep nvidia-gds
apt-cache search nvidia-gds
apt-get install nvidia-gds-12-2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
| /usr/local/cuda-12.2/gds/tools/gdscheck.py -p
GDS release version: 1.7.2.10
nvidia_fs version: 2.22 libcufile version: 2.12
Platform: x86_64
============
ENVIRONMENT:
============
=====================
DRIVER CONFIGURATION:
=====================
NVMe : Supported
NVMeOF : Unsupported
SCSI : Unsupported
ScaleFlux CSD : Unsupported
NVMesh : Unsupported
DDN EXAScaler : Unsupported
IBM Spectrum Scale : Unsupported
NFS : Unsupported
BeeGFS : Unsupported
WekaFS : Unsupported
Userspace RDMA : Unsupported
--Mellanox PeerDirect : Enabled
--rdma library : Not Loaded (libcufile_rdma.so)
--rdma devices : Not configured
--rdma_device_status : Up: 0 Down: 0
=====================
CUFILE CONFIGURATION:
=====================
properties.use_compat_mode : true
properties.force_compat_mode : false
properties.gds_rdma_write_support : true
properties.use_poll_mode : false
properties.poll_mode_max_size_kb : 4
properties.max_batch_io_size : 128
properties.max_batch_io_timeout_msecs : 5
properties.max_direct_io_size_kb : 16384
properties.max_device_cache_size_kb : 131072
properties.max_device_pinned_mem_size_kb : 33554432
properties.posix_pool_slab_size_kb : 4 1024 16384
properties.posix_pool_slab_count : 128 64 32
properties.rdma_peer_affinity_policy : RoundRobin
properties.rdma_dynamic_routing : 0
fs.generic.posix_unaligned_writes : false
fs.lustre.posix_gds_min_kb: 0
fs.beegfs.posix_gds_min_kb: 0
fs.weka.rdma_write_support: false
fs.gpfs.gds_write_support: false
profile.nvtx : false
profile.cufile_stats : 0
miscellaneous.api_check_aggressive : false
execution.max_io_threads : 4
execution.max_io_queue_depth : 128
execution.parallel_io : true
execution.min_io_threshold_size_kb : 8192
execution.max_request_parallelism : 4
properties.force_odirect_mode : false
properties.prefer_iouring : false
=========
GPU INFO:
=========
GPU index 0 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 1 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 2 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 3 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 4 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 5 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 6 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
GPU index 7 NVIDIA A800-SXM4-80GB bar:1 bar size (MiB):131072 supports GDS,IOMMU State: Disabled
==============
PLATFORM INFO:
==============
IOMMU: disabled
Platform verification succeeded
|
由于没有额外支持 GDS 的存储系统,仅 NVMe 设备处于支持 GDS 的状态。
4. 测试 GDS
4.1 创建一个 100G 的文件
1
| time dd if=/dev/zero of=/data/test/dd.txt bs=40M count=2500
|
4.2 不同传输模型下的测试
/usr/local/cuda-12.2/gds/tools/gdsio
提供了 8 个不同的测试模式,分别是:
GPU Direct Storage (GDS): 数据直接从存储传输到 GPU,绕过 CPU。这种模式减少了延迟并增加了吞吐量,特别适合需要 GPU 高速访问数据的场景。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 0
IoType: READ XferType: GPUD Threads: 4 DataSetSize: 10203136/10240000(KiB) IOSize: 1024(KiB) Throughput: 4.443489 GiB/sec,Avg_Latency: 878.805571 usecs ops: 9964 total_time 2.189826 secs
|
存储到 CPU 的传统传输: 数据首先从存储传输到 CPU。这是传统的处理方式,CPU 接收并处理数据,然后再传递给其他组件,比如 GPU。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 1
IoType: READ XferType: CPUONLY Threads: 4 DataSetSize: 10240000/10240000(KiB) IOSize: 1024(KiB) Throughput: 4.414133 GiB/sec,Avg_Latency: 868.366600 usecs ops: 10000 total_time 2.212354 secs
|
存储到 CPU 再到 GPU: 数据先从存储传输到 CPU,经过处理后再传输到 GPU。这是更常见的流程,适用于需要 CPU 进行数据预处理的场景。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 2
IoType: READ XferType: CPU_GPU Threads: 4 DataSetSize: 10142720/10240000(KiB) IOSize: 1024(KiB) Throughput: 4.312804 GiB/sec,Avg_Latency: 905.410136 usecs ops: 9905 total_time 2.242822 secs
|
- 3 - Storage->CPU->GPU_ASYNC
存储到 CPU 再到 GPU 的异步传输: 数据先从存储传输到 CPU,然后异步传输到 GPU。这种模式允许 CPU 在等待数据传输完成的同时执行其他任务,提高了效率。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 3
IoType: READ XferType: CPU_ASYNC_GPU Threads: 4 DataSetSize: 10167296/10240000(KiB) IOSize: 1024(KiB) Throughput: 3.318594 GiB/sec,Avg_Latency: 1176.616969 usecs ops: 9929 total_time 2.921806 secs
|
- 4 - Storage->PAGE_CACHE->CPU->GPU
存储->页缓存->CPU->GPU: 数据首先进入操作系统的页缓存,然后传输到 CPU,最后传输到 GPU。页缓存可以加快对常用数据的访问速度,但会增加一步缓存操作。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 4
IoType: READ XferType: CPU_CACHED_GPU Threads: 4 DataSetSize: 10011648/10240000(KiB) IOSize: 1024(KiB) Throughput: 1.770729 GiB/sec,Avg_Latency: 2206.536591 usecs ops: 9777 total_time 5.392046 secs
|
存储到 GPU 的异步传输: 数据直接从存储异步传输到 GPU,允许其他操作在传输过程中继续执行,减少等待时间,提高整体处理效率。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 5
IoType: READ XferType: ASYNC Threads: 4 DataSetSize: 10160128/10240000(KiB) IOSize: 1024(KiB) Throughput: 3.053654 GiB/sec,Avg_Latency: 1272.345376 usecs ops: 9922 total_time 3.173068 secs
|
存储到 GPU 的批处理传输: 数据从存储传输到 GPU,但采用批处理的方式进行。适用于需要一次性处理大量数据的情况。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 6
IoType: READ XferType: GPU_BATCH Threads: 1 IoDepth: 4 DataSetSize: 10240000/10240000(KiB) IOSize: 1024(KiB) Throughput: 4.422783 GiB/sec,Avg_Latency: 873.240876 usecs ops: 10001 total_time 2.208027 secs
|
- 7 - Storage->GPU_BATCH_STREAM
存储到 GPU 的流式批处理传输: 这是一种批处理和流式处理结合的模式,数据从存储传输到 GPU 时,采用流式处理进行批处理,进一步优化了处理速度和资源利用率。
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 4 -s 10G -i 1M -I 0 -x 7
IoType: READ XferType: GPU_BATCH_STREAM Threads: 1 IoDepth: 4 DataSetSize: 10240000/10240000(KiB) IOSize: 1024(KiB) Throughput: 2.437489 GiB/sec,Avg_Latency: 1600.979502 usecs ops: 10001 total_time 4.006429 secs
|
4.3 不同模式下的测试结果
模式 | 速度 (GiB/sec) |
---|
0 - Storage->GPU (GDS) | 4.443489 GiB/sec |
1 - Storage->CPU | 4.414133 GiB/sec |
2 - Storage->CPU->GPU | 4.312804 GiB/sec |
3 - Storage->CPU->GPU_ASYNC | 3.318594 GiB/sec |
4 - Storage->PAGE_CACHE->CPU->GPU | 1.770729 GiB/sec |
5 - Storage->GPU_ASYNC | 3.053654 GiB/sec |
6 - Storage->GPU_BATCH | 4.422783 GiB/sec |
7 - Storage->GPU_BATCH_STREAM | 2.437489 GiB/sec |
- Storage->GPU (GDS)\Storage->GPU_BATCH: 速度最高,因为数据直接从存储传输到 GPU,绕过了 CPU
- Storage->CPU->GPU_ASYNC 和 Storage->GPU_ASYNC: 异步模式下的速度稍低一些,因为异步传输增加了管理开销
- Storage->PAGE_CACHE->CPU->GPU: 数速度最低,因为数据经过了页缓存,增加了额外的步骤
4.3 验证 GDS 模式下对 CPU 的低使用率
主要对比模式 0 和 2
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 40 -s 100G -i 1M -I 0 -x 0
IoType: READ XferType: GPUD Threads: 40 DataSetSize: 101975040/102400000(KiB) IOSize: 1024(KiB) Throughput: 6.653494 GiB/sec,Avg_Latency: 5870.442542 usecs ops: 99585 total_time 14.616528 secs
|
1
2
| PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
43261 root 20 0 41.9g 753364 700692 D 18.8 0.1 0:04.69 gdsio
|
1
2
3
| /usr/local/cuda-12.2/gds/tools/gdsio -f /data/test/dd.txt -d 0 -w 40 -s 100G -i 1M -I 0 -x 2
IoType: READ XferType: CPU_GPU Threads: 40 DataSetSize: 101849088/102400000(KiB) IOSize: 1024(KiB) Throughput: 6.649129 GiB/sec,Avg_Latency: 5874.226678 usecs ops: 99462 total_time 14.608058 secs
|
1
2
| PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
47977 root 20 0 36.0g 153276 138644 S 63.7 0.0 0:03.27 gdsio
|
可以看到在 GDS 模式下,CPU 使用率只有经过 CPU 传输的 30%。
5. 参考