トレンドコラム

技術解説

NVIDIA GPUDirect Storage (GDS) 設定パラメータの解説

2024.10.08

NTTPC GPUエンジニア

GPUエンジニア
大野 泰弘

NVIDIA GPUDirect Storage (GDS) 設定パラメータの解説

LLMの学習等でストレージアクセスのパフォーマンスを上げたいって人が多い気がしますが、NVIDIA GPUDirect Storage (GDS) 設定パラメータの解説記事がNVIDIAのマニュアルしか見かけなかったので補足資料として記事を作成します。

cufile.json設定ファイルは、NVIDIA GPUDirect Storage (GDS)におけるI/O操作の詳細な構成を管理するためのものです。以下に、各セクションの詳細な解説を示します。
※cufile.jsonファイルは/etc/cufile.jsonに配置します。
基本的にはデフォルト値のままで良い場合が多いです。

1. logging

  • dir: ログファイルの保存ディレクトリ。指定しない場合、カレントディレクトリにログが生成されます。
  • level: (default = ERROR)ログの出力レベルを制御。ERRORはエラーメッセージのみ記録します。他のオプションには NOTICE、WARN、INFO、DEBUG などがあります(エラーレベルが高い順に)。

2. profile

  • nvtx: (default = false)NVIDIA Tools Extension (NVTX)のプロファイリングを有効/無効化。falseで無効。
  • cufile_stats: (default = 0)GDS操作に関する統計情報の詳細レベルを設定。0 から 3 までで、数値が高いほど詳細な情報が得られます。
  • io_batchsize: (default = 128)許可されるGDSの最大バッチサイズ。1~256の範囲で設定可能。

3. execution

  • max_io_queue_depth: (default = 128)I/Oキューに保持できる最大作業項目数。デフォルト値推奨。
  • max_io_threads: (default = 4)GPU当たりのI/O処理を行うホストスレッドの最大数。デフォルト値推奨。
  • parallel_io: (default = true)並列I/Oをサポートするかどうかを制御。
  • min_io_threshold_size_kb: (default = 8192)I/Oの分割を行う最小サイズ(KB単位)。デフォルト値推奨。
  • max_request_parallelism: (default = 4)1つのリクエストに対する最大並列数。デフォルト値推奨。

4. properties

  • max_direct_io_size_kb: (default = 16384)1リクエストあたりの最大ダイレクトI/Oサイズ(64K単位の倍数)。デフォルト値推奨。
  • max_device_cache_size_kb: (default = 131072)GPU用のバウンスバッファに予約するデバイスメモリサイズ。デフォルト値推奨。
  • max_device_pinned_mem_size_kb: (default = 33554432)1プロセスが固定できるデバイスメモリの最大サイズ。デフォルト値推奨。
  • use_poll_mode: (default = false)nvidia-fsドライバへの非同期I/O送信(ポーリングモード)を有効にするかを制御。ただし、全体のI/Oは同期的に実行される。ファイルサイズが小さい場合にレイテンシを短縮する効果。
  • poll_mode_max_size_kb: (default = 4)ポーリングモードでI/O完了を待つ際の最大リクエストサイズ。4の倍数に設定する必要有り。デフォルト値推奨。
  • allow_compat_mode: (default = true)POSIXベースのread/writeを許可する互換モードを有効にするかどうか。互換モードを無効化した方がパフォーマンスは向上する。Lustreの場合は非同期でファイルサイズが小さい場合に互換モードで通信した方がレイテンシが短いそうなので、無効化しない方がいいかもしれない。
  • gds_rdma_write_support: (default = true)RDMAベースのストレージに対するGDS書き込みサポートを有効にするかを制御。
  • io_batchsize: (default = 128)GDSのバッチサイズ。1~256の範囲で設定可能。
  • io_priority: (default = default)計算ストリームに対するI/Oの優先度 (default, low, med, high) を設定。ファイル操作以外にGPUのリソースが割かれている場合に効果あり。
  • rdma_dev_addr_list: (default = null)RDMAで使用できるクライアントサイドのNICを制限する場合にIPアドレスを指定。
  • rdma_load_balancing_policy: (default = RoundRobin)RDMAのロードバランシングポリシー。RoundRobinまたはRoundRobinMaxMinが選べます。
  • rdma_dynamic_routing: (default = false)RDMAによる動的ルーティングを有効にするかどうか。falseは無効。複数NICが搭載されている場合は有効である方がパフォーマンス向上する。
  • rdma_dynamic_routing_order: 動的ルーティングのポリシー順序。GPU_MEM_NVLINKS、GPU_MEM、SYS_MEM、P2Pの順で試行されます。

5. fs (ファイルシステム設定)

  • 各ファイルシステム(generic, beegfs, lustre, nfs, gpfs, weka)に関するI/O設定。
  • rdma_write_support: ファイルシステムごとのRDMA書き込みサポートの有効化/無効化。
  • gds_write_support: ファイルシステムごとのGDS書き込みサポートの有効化/無効化。
  • posix_unaligned_writes: POSIX書き込みで非同期な書き込みを許可するかどうか。
  • posix_gds_min_kb: 非同期且つ、この数値以下のファイルサイズはPOSIX書き込みを行う。4の倍数で設定する。Lustreの場合にレイテンシが改善する場合がある。

6. denylist

  • NVIDIA ファイルシステム(nvidia-fs)でのI/Oを制限するドライバやデバイス、ファイルシステム、マウントポイントをリストアップ。

7. miscellaneous

  • api_check_aggressive: デバッグのためにAPIレベルでの厳密なチェックを有効にするオプション。

rdma_load_balancing_policy

使用するNICの種類でパラメータを変更します。

  • RoundRobinはCPUに接続されたNICを利用する場合に設定します。(デフォルト値)
  • RoundRobinMaxMinはPCIeスイッチ等によりGPUと接続されたNICを利用する場合に設定します。

rdma_dynamic_routing および rdma_dynamic_routing_order

これらのパラメータは、RDMA通信における動的ルーティングを制御します。特に、複数のルートやNICが存在するシステムで、通信経路を動的に選択し、負荷分散や帯域幅の効率化を図る場合に有効です。

  • rdma_dynamic_routingがtrueになっている場合、クロスルートポート間の転送でルート選択が行われます。
  • rdma_dynamic_routing_orderは、動的ルーティングで優先されるメモリ間通信方法の順序を指定します。GPU_MEM_NVLINKSが最優先で、NVLinkが利用できない場合は次にGPUメモリ(GPU_MEM)、その後CPUメモリ(SYS_MEM)、最後にP2P(PCIeスイッチ等で接続された構成)が選択されます。

【参考】Dell PowerScale and NVIDIA GPUDirect Performance Report

ベンチマーク実行時に下記の設定をデフォルトから変更しています。

  • allow_compat_mode: false (default = true)
  • rdma_dynamic_routing: true (default = false)

【参考】NFS over RDMA 推奨マウントパラメータ

vers=3,rsize=1048576,wsize=1048576,hard,async,nconnect=8,timeo=600,retrans=2,proto=rdma,port=20049

  • vers=3: NFSv3のみNFS over RDMAでnconnectを利用可能です。NFSv3はシンプルでパフォーマンス重視の環境でよく使われます。
  • rsize=1048576: ネットワークREADリクエストごとにNFSクライアントが受信できるデータの最大バイト数を設定します。パフォーマンスが低下しないように、可能な限り大きいサイズ (最大 1048576) を使用することをお勧めします。
  • wsize=1048576: ネットワークWRITEリクエストごとにNFSクライアントが送信できるデータの最大バイト数を設定します。パフォーマンスが低下しないように、可能な限り大きいサイズ (最大 1048576) を使用することをお勧めします。
  • hard: NFSリクエストがタイムアウトした後のNFSクライアントの復旧動作を設定し、サーバーが応答するまでNFSリクエストを無期限に再試行します。データの整合性を確保できるように、ハードマウントオプション (hard) を使用することをお勧めします。
  • async: 非同期モードで NFS クライアントが書き込みリクエストを処理することを指定します。これにより、書き込み要求をサーバーに即座に送信せず、バッファに貯めて後から送信します。書き込みパフォーマンスを向上させますが、突然のシステム障害が発生した場合、データの一部が失われるリスクがあります。
  • nconnect=8: サーバーとの接続数を指定します。複数の接続を活用することで、パフォーマンスを向上させることができます。複数のコアを利用する環境で特に有効です。
  • timeo=600: NFSクライアントがNFSリクエストを再試行する前にレスポンスを待機するために使用するタイムアウト値を 600 デシ秒 (60 秒) に設定します。
  • retrans=2: NFSクライアントが追加の復旧アクションを試みる前にリクエストを再試行する回数を 2 に設定します。
  • proto=rdma: NFS over RDMAを有効にします。
  • port=20049: 使用するポート番号を指定します。多くの環境でNFS over RDMAは20049がデフォルトで使用されています。

【参考資料】NVIDIA GPUDirect Storage Benchmarking and Configuration Guide

【参考資料】GPUDirect Storage Benchmarking on Network Attached Storage

【参考】GDS on NFS over RDMA用の設定案(CPU側NIC利用想定)

遅延のある環境を考慮して非同期処理の有効化とバッチサイズを最大に設定。
POSIXを無効化してGDSを強制し、RDMAによる動的ルーティングを有効にすることでパフォーマンスを最大化する。
cat /etc/cufile.json

{
    "profile": {
        "io_batchsize": 256
    },
    "properties": {
        "use_poll_mode" : true,
        "allow_compat_mode": false,
        "io_batchsize": 256,
        "rdma_dynamic_routing": true
    }
}

【参考】GDS on Lustre用の設定案(GPU側NIC利用想定)

RDMAによる動的ルーティングを有効にすることでパフォーマンスを最大化。
4KB未満のファイルサイズで非同期処理が行われた場合はPOSIXで書き込みを行う。
また、GPU側のNICを利用する場合はRoundRobinMaxMinを選択する。
cat /etc/cufile.json

{
    "properties": {
        "rdma_load_balancing_policy": "RoundRobinMaxMin",
        "rdma_dynamic_routing": true
    },
    "fs": {
        "generic": {
            "posix_unaligned_writes" : true
        },
        "lustre": {
            "posix_gds_min_kb" : 4
        }
    }
}

【参考】デフォルトの設定

cat /usr/local/cuda-xx.xx/gds/cufile.json

{
    // NOTE : Application can override custom configuration via export CUFILE_ENV_PATH_JSON=
    // e.g : export CUFILE_ENV_PATH_JSON="/home//cufile.json"

        "logging": {
            // log directory, if not enabled will create log file under current working directory
            //"dir": "/home/",

            // NOTICE|ERROR|WARN|INFO|DEBUG|TRACE (in decreasing order of severity)
            "level": "ERROR"
        },
        "profile": {
            // nvtx profiling on/off
            "nvtx": false,
            // cufile stats level(0-3)
            "cufile_stats": 0
        },

        "execution" : {
            // max number of workitems in the queue;
            "max_io_queue_depth": 128,
            // max number of host threads per gpu to spawn for parallel IO
            "max_io_threads" : 4,
            // enable support for parallel IO
            "parallel_io" : true,
            // minimum IO threshold before splitting the IO
            "min_io_threshold_size_kb" : 8192,
            // maximum parallelism for a single request
            "max_request_parallelism" : 4
        },

        "properties": {
            // max IO chunk size (parameter should be multiples of 64K) used by cuFileRead/Write internally per IO request
            "max_direct_io_size_kb" : 16384,
            // device memory size (parameter should be 4K aligned) for reserving bounce buffers for the entire GPU
            "max_device_cache_size_kb" : 131072,
            // limit on maximum device memory size (parameter should be 4K aligned) that can be pinned for a given process
            "max_device_pinned_mem_size_kb" : 33554432,
            // true or false (true will enable asynchronous io submission to nvidia-fs driver)
            // Note : currently the overall IO will still be synchronous
            "use_poll_mode" : false,
            // maximum IO request size (parameter should be 4K aligned) within or equal to which library will use polling for IO completion
            "poll_mode_max_size_kb": 4,
            // allow compat mode, this will enable use of cuFile posix read/writes
            "allow_compat_mode": true,
            // enable GDS write support for RDMA based storage
            "gds_rdma_write_support": true,
            // GDS batch size
            "io_batchsize": 128,
            // enable io priority w.r.t compute streams
            // valid options are "default", "low", "med", "high"
            "io_priority": "default",
            // client-side rdma addr list for user-space file-systems(e.g ["10.0.1.0", "10.0.2.0"])
            "rdma_dev_addr_list": [ ],
            // load balancing policy for RDMA memory registration(MR), (RoundRobin, RoundRobinMaxMin)
            // In RoundRobin, MRs will be distributed uniformly across NICS closest to a GPU
            // In RoundRobinMaxMin, MRs will be distributed across NICS closest to a GPU
            // with minimal sharing of NICS acros GPUS
            "rdma_load_balancing_policy": "RoundRobin",
            //32-bit dc key value in hex
            //"rdma_dc_key": "0xffeeddcc",
            //To enable/disable different rdma OPs use the below bit map
            //Bit 0 - If set enables Local RDMA WRITE
            //Bit 1 - If set enables Remote RDMA WRITE
            //Bit 2 - If set enables Remote RDMA READ
            //Bit 3 - If set enables REMOTE RDMA Atomics
            //Bit 4 - If set enables Relaxed ordering.
            //"rdma_access_mask": "0x1f",

            // In platforms where IO transfer to a GPU will cause cross RootPort PCie transfers, enabling this feature
            // might help improve overall BW provided there exists a GPU(s) with Root Port common to that of the storage NIC(s).
            // If this feature is enabled, please provide the ip addresses used by the mount either in file-system specific
            // section for mount_table or in the rdma_dev_addr_list property in properties section
            "rdma_dynamic_routing": false,
            // The order describes the sequence in which a policy is selected for dynamic routing for cross Root Port transfers
            // If the first policy is not applicable, it will fallback to the next and so on.
            // policy GPU_MEM_NVLINKS: use GPU memory with NVLink to transfer data between GPUs
            // policy GPU_MEM: use GPU memory with PCIe to transfer data between GPUs
            // policy SYS_MEM: use system memory with PCIe to transfer data to GPU
            // policy P2P: use P2P PCIe to transfer across between NIC and GPU
            "rdma_dynamic_routing_order": [ "GPU_MEM_NVLINKS", "GPU_MEM", "SYS_MEM", "P2P" ]
        },

        "fs": {
            "generic": {

                // for unaligned writes, setting it to true will, cuFileWrite use posix write internally instead of regular GDS write
                "posix_unaligned_writes" : false
            },

            "beegfs" : {
                // IO threshold for read/write (param should be 4K aligned)) equal to or below which cuFile will use posix read/write
                "posix_gds_min_kb" : 0

                // To restrict the IO to selected IP list, when dynamic routing is enabled
                // if using a single BeeGFS mount, provide the ip addresses here
                //"rdma_dev_addr_list" : []

                // if using multiple lustre mounts, provide ip addresses used by respective mount here
                //"mount_table" : {
                //                    "/beegfs/client1" : {
                //                                    "rdma_dev_addr_list" : ["172.172.1.40", "172.172.1.42"]
                //                    },

                //                    "/beegfs/client2" : {
                //                                    "rdma_dev_addr_list" : ["172.172.2.40", "172.172.2.42"]
                //                    }
                //}

            },

            "lustre": {

                // IO threshold for read/write (param should be 4K aligned)) equal to or below which cuFile will use posix read/write
                "posix_gds_min_kb" : 0

                // To restrict the IO to selected IP list, when dynamic routing is enabled
                // if using a single lustre mount, provide the ip addresses here (use : sudo lnetctl net show)
                //"rdma_dev_addr_list" : []

                // if using multiple lustre mounts, provide ip addresses used by respective mount here
                //"mount_table" : {
                //                    "/lustre/ai200_01/client" : {
                //                                    "rdma_dev_addr_list" : ["172.172.1.40", "172.172.1.42"]
                //                    },

                //                    "/lustre/ai200_02/client" : {
                //                                    "rdma_dev_addr_list" : ["172.172.2.40", "172.172.2.42"]
                //                    }
                //}
            },

            "nfs": {

                // To restrict the IO to selected IP list, when dynamic routing is enabled
                //"rdma_dev_addr_list" : []

                //"mount_table" : {
                //                     "/mnt/nfsrdma_01/" : {
                //                                     "rdma_dev_addr_list" : []
                //                     },

                //                     "/mnt/nfsrdma_02/" : {
                //                                     "rdma_dev_addr_list" : []
                //                     }
                //}
            },

            "gpfs": {
                //allow GDS writes with GPFS
                "gds_write_support": false

                //"rdma_dev_addr_list" : []

                //"mount_table" : {
                //                     "/mnt/gpfs_01" : {
                //                                     "rdma_dev_addr_list" : []
                //                     },

                //                     "/mnt/gpfs_02/" : {
                //                                     "rdma_dev_addr_list" : []
                //                     }
                //}
            },

            "weka": {

                // enable/disable RDMA write
                "rdma_write_support" : false
            }
        },

        "denylist": {
            // specify list of vendor driver modules to deny for nvidia-fs (e.g. ["nvme" , "nvme_rdma"])
            "drivers":  [ ],

            // specify list of block devices to prevent IO using cuFile (e.g. [ "/dev/nvme0n1" ])
            "devices": [ ],

            // specify list of mount points to prevent IO using cuFile (e.g. ["/mnt/test"])
            "mounts": [ ],

            // specify list of file-systems to prevent IO using cuFile (e.g ["lustre", "wekafs"])
            "filesystems": [ ]
        },

        "miscellaneous": {
            // enable only for enforcing strict checks at API level for debugging
            "api_check_aggressive": false
        }
}