1. GDS cuFile API 参考#

NVIDIA® GPUDirect® Storage cuFile API 参考指南提供了关于 cuFile API 参考的信息,该参考用于应用程序和框架中以利用 GDS 技术,并描述了这些 API 的意图、上下文和操作,这些 API 是 GDS 技术的一部分。

2. 简介#

NVIDIA® Magnum IO GPUDirect® Storage (GDS) 是 GPUDirect 系列的一部分。GDS 实现了 GPU 内存和存储之间直接内存访问 (DMA) 传输的直接数据路径,从而避免了通过 CPU 的反弹缓冲区。这种直接路径提高了系统带宽,并降低了 CPU 的延迟和利用率负载。

本文档提供了关于 cuFile API 的信息,这些 API 用于应用程序和框架中以利用 GDS 技术,并描述了这些 API 的意图、上下文和操作,这些 API 是 GDS 技术的一部分。

注意

API 和描述如有更改,恕不另行通知。

3. 用法#

本节介绍了 cuFile API 的操作。

由于该功能是 CUDA Driver C API 的一部分,因此 API 使用 cuFile 前缀和 CUDA Driver 的驼峰命名法。

  • 所有 API 都是线程安全的。

  • 在库初始化后不应使用 fork 系统调用。在子进程中 fork 系统调用后的 API 行为是未定义的。

  • 带有 GPU 缓冲区的 API 应在有效的 CUDA 上下文和流(如果适用)中调用。

  • 所有 API 都是从 CPU 而不是 GPU 发出的。

注意

从 CUDA 工具包 12.2(GDS 版本 1.7.x)版本开始,cuFile API 支持在 GPU 设备以及主机内存上分配的内存。使用 GPUDirect 的对等传输在受支持的文件系统和硬件配置上支持设备内存之间的传输。除非 API 专门应用于特定类型的内存,否则 API 将此内存地址称为缓冲区指针。

3.1. 动态交互#

以下描述了 cuFile API 之间的动态交互。

某些 cuFile API 是可选的。如果未主动调用它们,则它们的动作将反应性地发生

如果在驱动程序、文件或缓冲区上调用 cuFile{DriverOpen, HandleRegister, BufRegister} `` ,而该驱动程序、文件或缓冲区已被先前的 ``cuFile* API 调用打开或注册,则会导致错误。如果在从未被先前的 cuFile* API 调用打开或注册的缓冲区、文件或驱动程序上调用 cuFile{BufDeregister, HandleDeregister, DriverClose},则会导致错误。对于这些错误,API 的输出参数将处于未定义状态,并且没有其他副作用。

  • cuFileDriverOpen 显式地导致驱动程序初始化。

    它的使用是可选的。如果未使用它,则驱动程序初始化将在首次使用 cuFile{HandleRegister, Read, Write, BufRegister} API 时隐式发生。

  • (强制性)cuFileHandleRegister 将特定于操作系统的文件描述符转换为 CUfileHandle_t,并基于挂载点和文件打开方式对 GDS 支持性进行检查。

  • cuFileBufRegister 显式地注册内存缓冲区。

    如果未调用此 API,则在首次使用缓冲区时(例如,在 cuFile{Read, Write} 中),如果需要,将使用内部注册内存。

  • cuFile{BufDeregister, HandleDeregister} 分别显式释放缓冲区和文件资源。

    如果未调用此 API,则在使用 cuFileDriverClose 关闭驱动程序时,缓冲区和资源将被隐式释放。

  • cuFileDriverClose 显式释放驱动程序资源。

    如果未调用此 API,则在对库句柄执行 dlclose() 或进程终止时,驱动程序资源将被隐式释放。

3.2. 驱动程序、文件和缓冲区管理#

本节介绍了管理驱动程序、文件和缓冲区的整体工作流程

  1. 调用 cuFileDriverOpen() 以初始化关键性能路径的状态。

  2. 使用 cudaMalloc、cudaMallocManagedcuMem* API 分配 GPU 内存,或使用 cudaMallocHostmallocmmap 分配主机内存。

  3. 要注册缓冲区,请调用 cuFileBufRegister 以初始化关键性能路径的缓冲区状态。

  4. 完成以下 IO 工作流程

    1. 对于 Linux,使用 POSIX open 打开文件。

    2. 调用 cuFileHandleRegister 以将现有的文件描述符包装在与操作系统无关的 CUfileHandle_t 中。此步骤评估文件状态和文件挂载对于 GDS 的适用性,并初始化关键性能路径的文件状态。

    3. 在现有的 cuFile 句柄和现有缓冲区上调用 IO API,例如 cuFileRead/cuFileWrite

      • 如果之前未在缓冲区指针上调用 cuFileBufRegister,则 cuFileRead/cuFileWrite 将在需要时使用内部注册缓冲区。

      • 不使用 cuFileBufRegister 可能不利于小 IO 大小的性能。

      • 有关更多信息,请参阅 GPUDirect 最佳实践指南

    4. 除非返回错误条件,否则 IO 将成功执行。

  5. 调用 cuFileBufDeregister 以释放特定于缓冲区的 cuFile 状态。

  6. 调用 cuFileHandleDeregister 以释放特定于文件的 cuFile 状态。

  7. 调用 cuFileDriverClose 以释放 cuFile 状态。

注意

不使用 cuFileDeregistercuFileDriverClose API(步骤 5、6 和 7)可能会不必要地消耗资源,如 valgrind 等工具所示。最佳实践始终是在应用程序清理路径中调用这些 API。

3.3. cuFile 兼容模式#

用例

cuFile API 可用于不同的场景

  • 开发人员使用 cuFile API 构建 GPUDirect Storage 应用程序,但没有受支持的硬件配置。

  • 开发人员构建在 CUDA 计算能力 > 6 的 GPU 卡上运行的应用程序,但没有暴露 BAR 空间。

  • 部署中未加载或无法加载 nvidia-fs.ko

  • Linux 发行版不支持 GPUDirect Storage 的部署。

  • 文件系统可能不支持 GPUDirect Storage 的部署。

  • 网络链接未启用 RDMA 支持的部署。

  • 配置对于 GPUDirect Storage 不是最优的部署。

行为

cuFile 库提供了一种机制,允许 cuFile 读取和写入使用兼容模式,分别使用 POSIX preadpwriteaio_submit API 到主机内存,并在适用时复制到 GPU 内存。cuFile API 兼容模式的行为由以下配置参数确定。

配置选项(默认)

cuFile IO 行为

“allow_compat_mode”: true

如果为 true,则当库检测到打开的缓冲区文件描述符无法使用 GPUDirect Storage 时,将回退到使用兼容模式。

“force_compat_mode”: false

如果为 true,则可以使用此选项强制所有 IO 使用兼容模式。或者,管理员可以卸载 nvidia_fs.ko 或不在 docker 容器环境中暴露字符设备。

“gds_rdma_write_support”: true

如果为 false,即使底层文件系统能够执行 GPUDirect Storage 写入,也强制兼容模式用于写入。 注意: 如果选项为“false”,则此选项将覆盖并禁用任何文件系统特定的选项以启用 RDMA 写入。

“posix_unaligned_writes” : false

如果为 true,则强制兼容模式用于写入,其中文件偏移量和/或 IO 大小未与页面边界(4KB)对齐。

“lustre:posix_gds_min_kb” : 0

对于 lustre 文件系统,如果大于 0,则兼容模式用于 [1 - posix_gds_min_kb] kB 范围内的 IO 大小。

注意: 即使 allow_compat_mode 设置为 false,此选项也将强制 posix 模式。

“weka:rdma_write_support” : false

如果此选项为 false,则所有写入 WekaFS 的操作都将使用兼容模式。

注意: 如果该选项设置为 false,即使 allow_compat_mode 选项为 truefalse,cuFile 库也将使用 posix 路径。

“gpfs:gds_write_support” : false

如果此选项为 false,则所有写入 IBM Spectrum Scale 的操作都将使用兼容模式。

注意: 如果该选项设置为 false,即使 allow_compat_mode 选项为 true 或 false,cuFile 库也将使用 posix 路径。

“rdma_dynamic_routing”: false,

“rdma_dynamic_routing_order”: [ “ “SYS_MEM” ]

如果 rdma_dynamic_routing 设置为 truerdma_dynamic_routing_order 设置为 [SYS_MEM],则 DFS 的所有 IO 都将使用兼容模式。

除了上述配置选项外,兼容模式将用作以下用例的后备选项。

用例

cuFile IO 行为

GPU 中没有 BAR1 内存。

使用兼容模式。

对于 wekaFS 或 IBM Spectrum Scale 挂载:如果没有指定 rdma_dev_addr_list,或者注册 MR 到 ib 设备失败。

使用兼容模式。

无法在 GPU 内存中分配反弹缓冲区。

使用兼容模式。

对于 WekaFS 和 IBM Spectrum Scale:如果内核为 GPUDirect Storage 读取/写入返回 -ENOTSUP

在内部使用兼容模式重试 IO 操作。

IBM Spectrum Scale 或 WekaFS 上的 cuFile Stream 和 cuFile Batch API

所有异步和批处理操作都将在内部使用兼容模式 IO。

nvidia_fs.ko 驱动程序未加载。

所有 IO 操作都将使用兼容模式。

局限性

  • 在 GPU 的 CUDA 计算能力低于 6 的情况下,兼容模式不起作用。

  • GDS 兼容模式已在启用 GDS 的文件系统和环境中进行测试并可正常工作。尚未测试它在所有其他文件系统上的工作情况。

4. cuFile API 规范#

本节提供了有关从 CPU 使用的 cuFile API 的信息,以启用应用程序和框架。

4.1. 数据类型#

4.1.1. 声明和定义#

以下是相关的 cuFile 枚举及其描述。

typedef struct CUfileError {
        CUfileOpError err; // cufile error
        enum CUresult cu_err; // for CUDA-specific errors
} CUfileError_t;

/**
 * error macros to inspect error status of type CUfileOpError
 */

#define IS_CUFILE_ERR(err) \
        (abs((err)) > CUFILEOP_BASE_ERR)

#define CUFILE_ERRSTR(err) \
        cufileop_status_error(static_cast<CUfileOpError>(abs((err))))

#define IS_CUDA_ERR(status) \
        ((status).err == CU_FILE_CUDA_DRIVER_ERROR)

#define CU_FILE_CUDA_ERR(status) ((status).cu_

以下枚举和两个结构支持更广泛的跨操作系统支持

enum CUfileFileHandleType {
    CU_FILE_HANDLE_TYPE_OPAQUE_FD = 1, /* linux based fd    */
    CU_FILE_HANDLE_TYPE_OPAQUE_WIN32 = 2, /* windows based handle */
    CU_FILE_HANDLE_TYPE_USERSPACE_FS  = 3, /* userspace based FS */
};

typedef struct CUfileDescr_t {
    CUfileFileHandleType type; /* type of file being registered */
    union {
        int fd;             /* Linux   */
        void *handle;       /* Windows */
    } handle;
    const CUfileFSOps_t *fs_ops;     /* file system operation table */
} CUfileDescr_t;

/* cuFile handle type */
typedef void*  CUfileHandle_t;

typedef struct cufileRDMAInfo
{
    int version;
    int desc_len;
    const char *desc_str;
} cufileRDMAInfo_t;

typedef struct CUfileFSOps {
      /* NULL means discover using fstat */
      const char* (*fs_type) (void *handle);

      /* list of host addresses to use,  NULL means no restriction */
      int (*getRDMADeviceList)(void *handle, sockaddr_t **hostaddrs);

      /* -1 no pref */
      int (*getRDMADevicePriority)(void *handle, char*, size_t,
                                loff_t, sockaddr_t* hostaddr);

      /* NULL means try VFS */
      ssize_t (*read) (void *handle, char*, size_t, loff_t, cufileRDMAInfo_t*);
      ssize_t (*write) (void *handle, const char *, size_t, loff_t , cufileRDMAInfo_t*);
} CUfileFSOps_t;

typedef enum CUfileDriverStatusFlags {
        CU_FILE_LUSTRE_SUPPORTED = 0,        /*!< Support for DDN LUSTRE */
        CU_FILE_WEKAFS_SUPPORTED = 1,        /*!< Support for WEKAFS */
        CU_FILE_NFS_SUPPORTED = 2,           /*!< Support for NFS */
        CU_FILE_GPFS_SUPPORTED = 3,          /*! < Support for GPFS */
        CU_FILE_NVME_SUPPORTED = 4,          /*!< Support for NVMe */
        CU_FILE_NVMEOF_SUPPORTED = 5,        /*!< Support for NVMeOF */
        CU_FILE_SCSI_SUPPORTED = 6,          /*!< Support for SCSI */
        CU_FILE_SCALEFLUX_CSD_SUPPORTED = 7, /*!< Support for Scaleflux CSD*/
        CU_FILE_NVMESH_SUPPORTED = 8,        /*!< Support for NVMesh Block Dev*/
        CU_FILE_BEEGFS_SUPPORTED = 9,        /*!< Support for BeeGFS */
} CUfileDriverStatusFlags_t;


enum CUfileDriverControlFlags {
      CU_FILE_USE_POLL_MODE = 0, /*!< use POLL mode. properties.use_poll_mode*/
      CU_FILE_ALLOW_COMPAT_MODE = 1 /*!< allow COMPATIBILITY mode. properties.allow_compat_mode*/
};

typedef enum CUfileFeatureFlags {
    CU_FILE_DYN_ROUTING_SUPPORTED =0,
    CU_FILE_BATCH_IO_SUPPORTED = 1,
    CU_FILE_STREAMS_SUPPORTED = 2
} CUfileFeatureFlags_t;;

/* cuFileDriverGetProperties describes this structure's members */
typedef struct CUfileDrvProps {
   struct {
     unsigned int major_version;
     unsigned int minor_version;
     size_t poll_thresh_size;
     size_t max_direct_io_size;
     unsigned int dstatusflags;
     unsigned int dcontrolflags;
   } nvfs;
   CUfileFeatureFlags_t fflags;
   unsigned int max_device_cache_size;
   unsigned int per_buffer_cache_size;
   unsigned int max_pinned_memory_size;
   unsigned int max_batch_io_timeout_msecs;
} CUfileDrvProps_t;

/* Parameter block for async cuFile IO */
/* Batch APIs use an array of these    */
/* Status must be CU_FILE_WAITING when submitted, and is
   updated when enqueued and when complete, so this user-allocated
   structure is live until the operation completes.    */
typedef enum CUFILEStatus_enum {
        CUFILE_WAITING = 0x000001,  /* required value prior to submission */
        CUFILE_PENDING = 0x000002,  /* once enqueued */
        CUFILE_INVALID = 0x000004,  /* request was ill-formed or could not be enqueued */
        CUFILE_CANCELED = 0x000008, /* request successfully canceled */
        CUFILE_COMPLETE = 0x0000010, /* request successfully completed */
        CUFILE_TIMEOUT = 0x0000020,  /* request timed out */
        CUFILE_FAILED  = 0x0000040  /* unable to complete */
}CUfileStatus_t;

typedef enum cufileBatchMode {
        CUFILE_BATCH = 1,
} CUfileBatchMode_t;

typedef struct CUfileIOParams {
        CUfileBatchMode_t mode; // Must be the very first field.
        union {
                struct  {
                        void *devPtr_base;
                        off_t file_offset;
                        off_t devPtr_offset;
                        size_t size;
                }batch;
        }u;
        CUfileHandle_t fh;
        CUfileOpcode_t opcode;
        void *cookie;
} CUfileIOParams_t;

typedef struct CUfileIOEvents {
        void *cookie;
        CUfileStatus_t   status;      /* status of the operation */
        size_t ret;       /* -ve error or amount of I/O done. */
} CUfileIOEvents_t;

4.1.2. 类型定义#

cuFile 类型定义

typedef struct CUfileDescr CUfileDesr_t
typedef struct CUfileError CUfileError_t
typedef struct CUfileDrvProps CUfileDrvProps_t
typedef enum CUfileFeatureFlags CUfileFeatureFlags_t
typedef enum CUfileDriverStatusFlags_enum CUfileDriverStatusFlags_t
typedef enum CUfileDriverControlFlags_enum CUfileDriverControlFlags_t
typedef struct CUfileIOParams CUfileIOParams_t
typedef enum CUfileBatchOpcode CUfileBatchOpcode_t

4.1.3. 枚举#

cuFile 枚举

  • enum CUfileOpcode_enum

    这是批处理模式的 cuFile 操作码。

操作码

描述

CU_FILE_READ

0

批量读取

CU_FILE_WRITE

1

批量写入

/* cuFile Batch IO operation kind */
enum CUfileOpcode {
     CU_FILE_READ,
     CU_FILE_WRITE,
};
  • enum CUfileStatus

    批处理模式的 cuFile 状态代码。

状态

描述

CUFILE_WAITING

0x01

初始值。

CUFILE_PENDING

0x02

一旦入队到驱动程序中就设置。

CUFILE_INVALID

0x04

无效参数。

CUFILE_CANCELED

0x08

请求已成功取消。

CUFILE_COMPLETE

0x10

成功完成。

CUFILE_TIMEOUT

0x20

操作已超时。

CUFILE_FAILED

0x40

IO 失败。

  • enum CUfileOpError

    • cuFile 操作错误类型。

    • 所有错误代码值,除了 CU_FILE_SUCCESS 之外,都被认为是可能使 API 的输出和输入参数值处于未定义状态的故障。

      这些值不能对文件系统、应用程序进程和更大的系统产生任何副作用。

      注意

      cuFile 特定的错误将大于 CUFILEOP_BASE_ERR,以便用户能够区分 POSIX 错误和 cuFile 错误。

      #define CUFILEOP_BASE_ERR 5000
      

错误代码

描述

CU_FILE_SUCCESS

0

cufile 成功。

CU_FILE_DRIVER_NOT_INITIALIZED

5001

未加载 nvidia-fs 驱动程序。

CU_FILE_DRIVER_INVALID_PROPS

5002

无效属性。

CU_FILE_DRIVER_UNSUPPORTED_LIMIT

5003

属性范围错误。

CU_FILE_DRIVER_VERSION_MISMATCH

5004

nvidia-fs 驱动程序版本不匹配。

CU_FILE_DRIVER_VERSION_READ_ERROR

5005

nvidia-fs 驱动程序版本读取错误。

CU_FILE_DRIVER_CLOSING

5006

驱动程序正在关闭。

CU_FILE_PLATFORM_NOT_SUPPORTED

500

当前平台不支持 GDS。

CU_FILE_IO_NOT_SUPPORTED

5008

当前文件不支持 GDS。

CU_FILE_DEVICE_NOT_SUPPORTED

5009

当前 GPU 不支持 GDS。

CU_FILE_NVFS_DRIVER_ERROR

5010

nvidia-fs 驱动程序 ioctl 错误。

CU_FILE_CUDA_DRIVER_ERROR

5011

CUDA Driver API 错误。

此错误指示 CUDA 驱动程序 API 错误。如果设置了此错误,则在 cuFileError 的 cu_err 字段中设置了 CUDA 特定的错误代码。

CU_FILE_CUDA_POINTER_INVALID

5012

无效的设备指针。

CU_FILE_CUDA_MEMORY_TYPE_INVALID

5013

无效的指针内存类型。

CU_FILE_CUDA_POINTER_RANGE_ERROR

5014

指针范围超出分配的地址范围。

CU_FILE_CUDA_CONTEXT_MISMATCH

5015

CUDA 上下文不匹配。

CU_FILE_INVALID_MAPPING_SIZE

5016

访问超出最大固定内存大小。

CU_FILE_INVALID_MAPPING_RANGE

5017

访问超出映射大小。

CU_FILE_INVALID_FILE_TYPE

5018

不支持的文件类型。

CU_FILE_INVALID_FILE_OPEN_FLAG

5019

不支持的文件打开标志。

CU_FILE_DIO_NOT_SET

5020

未设置 fd direct IO。

CU_FILE_INVALID_VALUE

5022

无效的 API 参数。

CU_FILE_MEMORY_ALREADY_REGISTERED

5023

设备指针已注册。

CU_FILE_MEMORY_NOT_REGISTERED

5024

发生设备指针查找失败。

CU_FILE_PERMISSION_DENIED

5025

驱动程序或文件访问错误。

CU_FILE_DRIVER_ALREADY_OPEN

5026

驱动程序已打开。

CU_FILE_HANDLE_NOT_REGISTERED

5027

文件描述符未注册。

CU_FILE_HANDLE_ALREADY_REGISTERED

5028

文件描述符已注册。

CU_FILE_DEVICE_NOT_FOUND

5029

找不到 GPU 设备。

CU_FILE_INTERNAL_ERROR

5030

发生了内部错误。有关更多详细信息,请参阅 cufile.log

CU_FILE_GETNEWFD_FAILED

5031

获取新的文件描述符失败。

CU_FILE_NVFS_SETUP_ERROR

5033

发生了 NVFS 驱动程序初始化错误。

CU_FILE_IO_DISABLED

5034

当前文件上的配置禁用了 GDS。

CU_FILE_BATCH_SUBMIT_FAILED

5035

提交批处理操作失败。

CU_FILE_GPU_MEMORY_PINNING_FAILED

5036

分配固定 GPU 内存失败。

CU_FILE_BATCH_FULL

5037

批处理操作队列已满。

CU_FILE_ASYNC_NOT_SUPPORTED

5038

不支持 cuFile 流操作。

注意

数据路径错误通过使用 errno 的标准错误代码捕获。API 在出错时将返回 -1。

4.2. cuFile Driver API#

以下 cuFile API 用于初始化、最终化、查询和调整 cuFile 系统的设置。

/* Initialize the cuFile infrastructure */
CUfileError_t cuFileDriverOpen();

/* Finalize the cuFile system */
CUfileError_t cuFileDriverClose();

/* Query capabilities based on current versions, installed functionality */
CUfileError_t cuFileGetDriverProperties(CUfileDrvProps_t *props);

/*API to set whether the Read/Write APIs use polling to do IO operations */
CUfileError_t cuFileDriverSetPollMode(bool poll, size_t poll_threshold_size);

/*API to set max IO size(KB) used by the library to talk to nvidia-fs driver */
CUfileError_t cuFileDriverSetMaxDirectIOSize(size_t max_direct_io_size);

/* API to set maximum GPU memory reserved per device by the library for internal buffering */
CUfileError_t cuFileDriverSetMaxCacheSize(size_t max_cache_size);

/* Sets maximum buffer space that is pinned in KB for use by  cuFileBufRegister
CUfileError_t cuFileDriverSetMaxPinnedMemSize(size_t
   max_pinned_memory_size);

/* Retrieves the cuFile library version. */
CUfileError_t cuFileGetVersion(int *version);

注意

有关用法,请参阅 sample_007

4.3. cuFile 同步 IO API#

cuFile IO API 的核心是读取和写入函数。

ssize_t cuFileRead(CUFileHandle_t fh, void *bufPtr_base, size_t size, off_t file_offset, off_t devPtr_offset);
ssize_t cuFileWrite(CUFileHandle_t fh, const void *bufPtr_base, size_t size, off_t file_offset, off_t devPtr_offset);

设备或主机上缓冲区的起始偏移量由基址 (bufPtr_base) 和偏移量 (bufPtr_offset) 确定。此偏移量与文件中的偏移量不同。

注意

要使用注册缓冲区,bufPtr_base 必须是在 cuFileBufRegister 期间用于注册的缓冲区指针。否则,cuFileReadcuFileWrite API 可能会使用内部内存缓冲区进行 GPUDirect Storage 对等操作。

注意

对于不支持 GDS 的所有路径,默认行为是当 properties.allow_compat_mode 设置为 true 时,cuFile IO API 尝试使用文件系统支持的 posix 模式 API 进行 IO。为了禁用 cuFile API 回退到不受支持的 GDS 路径的 posix API,应将 /etc/cufile.json 文件中的 properties.allow_compat_mode 设置为 false。

注意

有关用法,请参阅示例 sample_003

4.4. cuFile 文件句柄 API#

以下是关于 cuFile 句柄 API 的一些信息。

cuFileHandleRegister API 通过使用与操作系统无关的接口,使文件描述符或句柄为 cuFile 子系统所知。该 API 返回一个由 cuFile 子系统拥有的不透明句柄。

为了节省内存,cuFileHandleDeregister API 用于释放 cuFile 相关的内存对象。仅使用 POSIX close 将不会清理 cuFile 使用的资源。此外,与在 cuFile 上下文中操作的文件关联的 cuFile 对象的清理将在 cuFileDriverClose 时发生。

CUfileError_t cuFileHandleRegister(CUFileHandle_t *fh, CUFileDescr_t *descr);
void cuFileHandleDeregister(CUFileHandle_t fh);

注意

有关用法,请参阅 sample_003

4.5. cuFile 缓冲区 API#

cuFileBufRegister API 会产生显著的性能成本,因此应尽可能分摊注册成本。开发人员必须确保预先注册缓冲区,并使其脱离关键路径。

cuFileBufRegister API 是可选的。如果未使用此 API,则会使用 cuFile 管理和内部固定的缓冲区,而不是固定用户的内存。

cuFileBufDeregister API 用于最佳地清理 cuFile 相关的内存对象,但 CUDA 当前没有类似于 cuFileBufDeregister 的 API。与在 cuFile 上下文中操作的缓冲区关联的对象的清理在 cuFileDriverClose 时发生。如果使用显式 API,则会立即报告产生的错误,但如果隐式执行这些显式 API 的操作,则错误报告和处理不太明确。

CUfileError_t cuFileBufRegister(const void *devPtr_base, size_t size, int flags);
CUfileError_t cuFileBufDeregister(const void *devPtr_base);

注意

有关用法,请参阅 sample_005

4.6. cuFile 流 API#

使用 cuFile 流 API 排队的 operations 与流上的其他工作以 FIFO 顺序排序,并且必须在继续流中的下一个操作之前完成。

CUfileError_t cuFileReadAsync(CUFileHandle_t fh, void *bufPtr_base,
                  size_t *size_p, off_t *file_offset_p, off_t *bufPtr_offset_p,
                  ssize_t *bytes_read_p, CUStream stream);
CUfileError_t cuFileWriteAsync(CUFileHandle_t fh, void *bufPtr_base,
                  size_t *size_p, off_t *file_offset_p, off_t *bufPtr_offse_pt,
                  ssize_t *bytes_written_p, CUstream stream);

注意

有关用法,请参阅示例 sample_031sample_032sample_033sample_034

4.7. cuFile 批处理 API#

批处理 API 是同步提交的,但相对于主机线程异步执行。

这些操作可以在不同的文件、同一文件中不同的位置或混合位置提交。可以使用同一主机线程或不同线程中的状态 API 异步检查 IO 的完成情况。cuFileBatchIOGetStatus API 接受一个 CUfileIOEvents_t 数组和要轮询的最小元素数,该数组描述了每个实例的 IO 操作、状态、错误和事务字节数。仅当状态指示成功完成时,事务字节数字段才有效。

注意

有关用法,请参阅示例 sample_019sample_020sample_021sample_022

5. cuFile API 功能规范#

本节提供了有关 cuFile API 功能规范的信息。

有关函数集及其相互关系的高级分析,请参阅 GPUDirect Storage 概述指南。我们预计会为其中一些函数添加额外的返回代码。

所有 cuFile API 都是从主机代码调用的。

5.1. cuFileDriver API 功能规范#

本节提供了有关 cuFileDriver API 功能规范的信息。

5.1.1. cuFileDriverOpen#

CUfileError_t cuFileDriverOpen();

打开驱动程序会话以支持 GDS IO 操作。

参数

返回值

  • 成功打开时,或驱动程序已打开时,返回 CU_FILE_SUCCESS

  • 打开驱动程序失败时,返回 CU_FILE_DRIVER_NOT_INITIALIZED

  • 打开失败时,返回 CU_FILE_PERMISSION_DENIED

    当字符设备 (/dev/nvidia_fs[0-15]) 被管理员(例如,admin)限制为特定用户时,可能会发生这种情况,其中 /dev 未在容器中以读取权限公开。

  • 当 cuFile 库与其内核驱动程序之间存在不匹配时,返回 CU_FILE_DRIVER_VERSION_MISMATCH

  • 如果 CUDA 驱动程序初始化失败,则返回 CU_FILE_CUDA_DRIVER_ERROR。如果当前平台不受 GDS 支持,则返回 CU_FILE_PLATFORM_NOT_SUPPORTED

  • 对于 cuFile 特定的内部错误,返回 CU_FILE_NVFS_SETUP_ERROR

有关更多信息,请参阅 cufile.log 文件。

描述

  • 此 API 打开与 NVFS 内核驱动程序的会话,以实现从用户空间到内核空间的通信,并调用 GDS 驱动程序来设置支持 GDS IO 操作所需的资源。

  • 该 API 检查当前平台是否支持 GDS 并初始化 cuFile 库。

  • 此 API 从 /etc/cufile.JSON 中的 JSON 配置文件加载 cuFile 设置。

    如果 JSON 配置文件不存在,则 API 加载默认库设置。要修改此默认配置文件,需要管理权限。管理员可以修改它以授予 cuFile 对指定设备和挂载路径的访问权限,并根据工作负载类型调整 IO 参数(以 KB 为单位,4K 对齐)。有关更多信息,请参阅 默认配置文件 (/etc/cufile.json)。

5.1.2. cuFileDriverClose#

CUfileError_t cuFileDriverClose();
  • 关闭驱动程序会话并释放 GDS 的任何关联资源。

  • 这在进程退出时隐式发生。

  • 驱动程序一旦关闭就可以重新打开。

参数

返回值

  • 成功关闭时,返回 CU_FILE_SUCCESS

  • 失败时,返回 CU_FILE_DRIVER_NOT_INITIALIZED

描述

  • 关闭 GDS 会话和任何关联的内存资源。如果存在使用 cuFileBufRegister 注册但未注销的缓冲区,则 cuFileDriverClose 会隐式注销这些缓冲区。当 cuFileDriverClose 正在进行时,任何正在进行的 IO 都将收到错误。

5.1.3. cuFileDriverGetProperties#

可以使用 cuFileDriverGetProperties 查询 cuFileDrvProps_t 结构,并使用 cuFileDriverSetProperties 选择性地修改。该结构是自描述的,并且其字段与主要和次要 API 版本参数一致。

CUfileError_t cuFileDriverGetProperties(cuFileDrvProps_t *props);
  • 获取 GDS 功能的驱动程序会话属性。

参数

props

指向 cuFile 驱动程序属性的指针。

返回值

  • 成功完成时,返回 CU_FILE_SUCCESS

  • 失败时,返回 CU_FILE_DRIVER_NOT_INITIALIZED

  • 驱动程序版本不匹配时,返回 CU_FILE_DRIVER_VERSION_MISMATCH

  • 如果输入无效,则返回 CU_FILE_INVALID_VALUE

描述

此 API 用于获取当前的 GDS 属性和 nvidia-fs 驱动程序属性和功能,例如对 SCSI、NVMe 和 NVMe-OF 的支持。

此 API 用于获取当前的 nvidia-fs 驱动程序特定属性,例如以下属性

  • major_version:cuFile 主版本

  • minor_version:cuFile 次版本

  • props.nvfs.dstatusflags,这些是位标志,指示对以下驱动程序功能的支持

    • CU_FILE_EXASCALER_SUPPORTED,一个位,用于检查 DDN EXAScaler 并行文件系统解决方案(基于 Lustre 文件系统)客户端是否支持 GDS。

    • CU_FILE_WEKAFS_SUPPORTED,一个位,用于检查 WekaFS 是否支持 GDS。

  • Props.nvfs.dcontrolflags,这些是位标志,指示驱动程序功能的当前激活状态

    • CU_FILE_USE_POLL_MODE,当位设置时,IO 使用轮询模式。

    • CU_FILE_ALLOW_COMPAT_MODE,如果值为 1,则设置兼容模式。

    否则,禁用兼容模式。

  • Props.fflags,这些是位标志,指示是否支持以下库功能

    • CU_FILE_STREAMS_SUPPORTED,一个属性,用于检查是否支持 CUDA 流。

    • CU_FILE_DYN_ROUTING_SUPPORTED,一个属性,用于检查是否支持动态路由功能。

  • Props.nvfs.poll_thresh_size,最大 IO 大小,以 KB 为单位,并且必须是 4K 对齐的,用于轮询模式。

  • Props.nvfs.max_direct_io_size,nvidia-fs 驱动程序向底层文件系统请求的最大 GDS IO 大小,以 KB 为单位,并且必须是 4K 对齐的。

  • Props.max_device_cache_size,每个设备的最大 GPU 缓冲区空间,以 KB 为单位,并且必须是 4K 对齐的。在内部使用,例如,用于处理未对齐的 IO 和最佳 IO 路径路由。此值可能会向下舍入到最接近的 GPU 页面大小。

  • Props.max_device_pinned_mem_size,最大缓冲区空间,单位为 KB,并且必须是 4K 对齐的,该空间被锁定并映射到 GPU BAR 空间。 这可能会向下舍入到最接近的 GPU 页面大小。

  • Props.per_buffer_cache_size,GPU 弹跳缓冲区大小,单位为 KB,用于内部池。

附加信息

有关更多信息,请参阅以下内容

5.1.4. cuFileDriverSetPollMode(bool poll, size_t poll_threshold_size)#

cuFileDriverSetPollMode(bool poll, size_t poll_threshold_size) API

CUfileError_t cuFileDriverSetPollMode(bool poll,
                                      size_t poll_threshold_size);
  • 设置 Read/Write API 是否使用轮询来完成 IO 操作。 如果启用轮询模式,则小于或等于阈值的 IO 大小将用于轮询。

  • poll_threshold_size 必须是 4K 对齐的。

参数

poll

布尔值,指示是否使用轮询模式。

poll_threshold_size

用于轮询模式的 IO 大小,单位为 KB。 默认值为 4KB。

返回值

  • 成功完成时,返回 CU_FILE_SUCCESS

  • CU_FILE_DRIVER_NOT_INITIALIZED,如果加载驱动程序失败。

  • CU_FILE_DRIVER_UNSUPPORTED_LIMIT,如果使用有效阈值大小设置失败。

描述

此 API 与 cuFileGetDriverProperties 结合使用。 此 API 用于设置库是否应使用轮询以及小于或等于该值(将进行轮询)的最大 IO 阈值大小。

此 API 覆盖可能通过 JSON 配置文件使用配置键 properties.poll_modeproperties.poll_max_size_kb 为当前进程设置的默认值。

有关更多信息,请参阅以下内容

cuFileDriverGetProperties

5.1.5. cuFileDriverSetMaxDirectIOSize(size_t max_direct_io_size)#

CUfileError_t cuFileDriverSetMaxDirectIOSize(size_t max_direct_io_size);
  • 设置最大 IO 大小,单位为 KB。

    nvidia-fs 驱动程序使用此参数作为最大 IO 块大小,在该大小中,IO 被发送到底层文件系统。 在兼容模式下,这是库用于发出 POSIX 读取/写入的最大 IO 块大小。

  • 最大直接 IO 大小必须是 4K 对齐的。

参数

max_direct_io_size

允许的最大直接 IO 大小,单位为 KB。 默认值为 16384KB。 这是因为通常并行文件系统在批量读取/写入时性能更好。

返回值

  • CU_FILE_SUCCESS,如果成功完成。

  • CU_FILE_DRIVER_NOT_INITIALIZED,如果加载驱动程序失败。

  • CU_FILE_DRIVER_UNSUPPORTED_LIMIT,如果使用有效大小设置失败。

描述

此 API 与 cuFileGetDriverProperties 一起使用,用于设置库使用的最大直接 IO 大小,以指定 nvidia-fs 内核驱动程序,后者可以向底层文件系统发出 IO 的最大块大小。 在兼容模式下,这是库用于发出 POSIX 读取/写入的最大 IO 块大小。 此参数取决于底层 GPU 硬件和系统内存。

此 API 覆盖可能通过 JSON 配置文件使用 properties.max_direct_io_size_kb 配置键为当前进程设置的默认值。

有关更多信息,请参阅以下内容

5.1.6. (size_t max_cache_size)#

CUfileError_t cuFileDriverSetMaxCacheSize(size_t max_cache_size);
  • 设置每个设备的最大 GPU 缓冲区空间,单位为 KB,用于内部用途,例如,处理未对齐的 IO 和最佳 IO 路径路由。 此值可能会向下舍入到最接近的 GPU 页面大小。

  • 最大缓存大小必须是 4K 对齐的。

  • 此 API 覆盖可能通过 JSON 配置文件使用 properties.max_device_cache_size_kb 配置键为当前进程设置的默认值。

参数

max_cache_size

每个设备的最大 GPU 缓冲区空间,单位为 KB,用于内部用途,例如,处理未对齐的 IO 和最佳 IO 路径路由。 此值可能会向下舍入到最接近的 GPU 页面大小。

默认值为 131072KB。

返回值

  • CU_FILE_SUCCESS,如果成功完成。

  • CU_FILE_DRIVER_NOT_INITIALIZED,如果加载驱动程序失败。

  • CU_FILE_DRIVER_UNSUPPORTED_LIMIT,如果使用有效 IO 大小设置失败

描述

此 API 与 cuFileGetDriverProperties 一起使用,用于设置库内部使用的每个设备的缓存大小上限。

有关更多信息,请参阅 cuFileDriverGetProperties

5.1.7. cuFileDriverSetMaxPinnedMemSize(size_t max_pinned_memory_size)#

CUfileError_t cuFileDriverSetMaxPinnedMemSize(size_t max_pinned_mem_size);
  • 设置最大 GPU 缓冲区空间,单位为 KB,该空间被锁定和映射。 此值可能会向下舍入到最接近的 GPU 页面大小。

  • 最大锁定大小必须是 4K 对齐的。

  • 默认值对应于最大 PinnedMemory 或设备的物理内存大小。

  • 此 API 覆盖可能由当前进程的 properties.max_device_pinned_mem_size_kb JSON 配置键设置的默认值。

参数

max_pinned_memory_size

最大缓冲区空间,单位为 KB,该空间被锁定并映射到 GPU BAR 空间。 此值可能会向下舍入到最接近的 GPU 页面大小。 最大限制可以设置为 UINT64_MAX,这等效于没有强制限制。 它可以设置为小于 GPU 物理内存大小的值。

返回值

  • CU_FILE_SUCCESS,如果成功完成。

  • CU_FILE_DRIVER_NOT_INITIALIZED,如果加载驱动程序失败。

  • CU_FILE_DRIVER_UNSUPPORTED_LIMIT,如果使用有效大小设置失败。

描述

此 API 与 cuFileGetDriverProperties 一起使用,用于设置可以锁定和映射的最大 GPU 内存大小的上限,并且取决于底层 GPU 硬件和系统内存。 此 API 与 cuFileBufRegister 相关,后者用于注册 GPU 设备内存。 有关更多信息,请参阅 cuFileDriverGetProperties

5.1.8. cuFileGetVersion(int *version)#

CUfileError_t cuFileGetVersion(int *version);
  • 检索 cuFile 库版本。

  • 版本以 (1000 * major + 10 * minor) 的形式返回。

  • 例如,cuFile 1.7.0 将表示为 1070。

参数

version

输出参数,成功完成后,它将包含上述格式的版本号。

返回值

  • CU_FILE_SUCCESS,如果成功完成。

  • CU_FILE_INVALID_VALUE,如果 version 参数为空。

  • CU_FILE_DRIVER_VERSION_READ_ERROR,如果版本不可用。

描述

此 API 用于获取 cuFile 库的当前版本。 有时应用程序可能需要根据版本来判断是否存在任何特定的 GDS 功能。

5.2. cuFile IO API 功能规范#

本节提供有关 cuFile IO API 功能规范的信息。

这些 API 中引用的设备指针地址与调用者的当前上下文有关。

与非异步版本的 cuMemcpy 不同,cuFileHandleRegistercuFileHandleDeregistercuFileReadcuFileWrite API 不具有相对于空流中其他工作的排序语义。

5.2.1. cuFileHandleRegister#

CUfileError_t cuFileHandleRegister(CUFileHandle_t *fh, CUfileDescr_t *descr);
  • 注册打开的文件。

  • cuFileHandleRegister 是必需的,并且执行额外的检查,这些检查会被记忆以提高后续 cuFile 操作的性能。

  • 此 API 与操作系统无关。

注意

CUDA 工具包 12.2(GDS 版本 1.7.x)支持非 O_DIRECT 打开标志以及 O_DIRECT。 允许应用程序在兼容模式下以及在安装 nvidia-fs.ko 的情况下以非 O_DIRECT 模式打开文件。 在后一种情况下,如果存在 GPU 和存储之间的 O_DIRECT 路径,则将使用该路径。

参数

fh

指向 OS 中性 cuFile 句柄结构的有效指针,该结构由用户提供,但由 cuFile 运行时填充和维护。

desc

指向 OS 中性文件描述符的有效指针,该描述符由用户提供,其中包含有关要打开的文件的详细信息,例如基于 Linux 的文件的 fd

返回值

  • CU_FILE_SUCCESS,如果成功完成。

  • CU_FILE_DRIVER_NOT_INITIALIZED,如果加载驱动程序失败。

  • CU_FILE_IO_NOT_SUPPORTED,如果不支持文件系统。

  • CU_FILE_INVALID_VALUE,如果存在空值或错误的 API 参数。

  • CU_FILE_INVALID_FILE_OPEN_FLAG,如果文件以不支持的模式打开,例如没有 O_APPEND

    O_NOCTTYO_NONBLOCKO_DIRECTORYO_NOFOLLOWO_NOATIMEO_TMPFILE

  • CU_FILE_INVALID_FILE_TYPE,如果文件路径无效、不是常规文件、不是符号链接或不是设备文件。

  • CU_FILE_HANDLE_ALREADY_REGISTERED,如果文件已使用相同的文件描述符注册。

描述

  • 给定文件描述符将填充并返回使用 cuFile API 发出 IO 所需的 CUfileHandle_t

  • 任何非 CU_FILE_SUCCESS 的返回值都会使 fh 处于未定义状态,但没有其他副作用。

  • 默认情况下,此 API 接受文件描述符是以 O_DIRECT 模式还是非 O_DIRECT 模式打开。

有关更多信息,请参阅以下内容

5.2.2. cuFileHandleDeregister#

CUfileError_t cuFileHandleDeregister(CUFileHandle_t *fh);

参数

fh

cuFileHandleRegister 获取的文件句柄。

返回值

注意

此 API 仅在 cufile.log 文件中为有效输入记录 ERROR 级别消息。

描述

  • 该 API 用于释放 cuFileHandleRegister 声明的资源。

    仅当应用程序确保句柄没有未完成的 IO 操作时,才应调用此 API。 如果在文件上的 IO 正在进行时调用 cuFileHandleDeregister,可能会导致未定义的行为。

  • 用户仍然需要在调用此 API 后使用 close 系统调用在 cuFile 子系统外部关闭文件描述符。

    在不调用 cuFileHandleDeregister 的情况下关闭文件句柄不会释放 cuFile 库中持有的资源。 如果未调用此 API,则 cuFile 子系统会延迟释放资源或在应用程序退出时释放资源。

有关更多信息,请参阅以下内容

5.2.3. cuFileRead#

ssize_t cuFileRead(CUfileHandle_tfh, void *bufPtr_base, size_t size, off_t file_offset, off_t bufPtr_offset);
  • 将指定字节从文件描述符读取到设备内存或主机内存。

参数

fh

文件的文件描述符。

bufPtr_base

设备内存或主机内存中缓冲区的基地址。 对于注册的缓冲区,bufPtr_base 必须保持设置为 cuFileBufRegister 调用中使用的基地址。

size

要读取的字节大小。

file_offset

要从中读取的文件偏移量。

bufPtr_offset

相对于 bufPtr_base 指针的偏移量,要读取到该偏移量。 此参数应仅与注册的缓冲区一起使用。

返回值

  • 成功读取的字节大小。

  • -1 表示错误,因此 errno 设置为指示文件系统错误。

  • 所有其他错误都返回 CUfileOpError 枚举值的负整数值。

描述

此 API 通过使用 GDS 功能将数据从指定文件句柄在指定偏移量和大小字节处读取到 GPU 内存中,或者根据内存指针的类型读取到主机内存中。 该 API 对于未对齐的偏移量和任何数据大小都能正确工作,尽管性能可能与对齐读取的性能不匹配。 这是一个同步调用,会阻塞直到 IO 完成。

注意

对于 bufPtr_offset,如果数据将从使用 cuFileBufRegister 注册的 bufPtr_base 完全开始读取,则应将 bufPtr_offset 设置为 0。 要从注册缓冲区范围内的偏移量开始读取,相对偏移量应在 bufPtr_offset 中指定,并且 bufPtr_base 必须保持设置为 cuFileBufRegister 调用中使用的基地址。

有关更多信息,请参阅以下内容

5.2.4. cuFileWrite#

ssize_t cuFileWrite(CUfileHandle_t fh, const void *bufPtr_base, size_t size, off_t file_offset, off_t bufPtr_offset);
  • 使用 GDS 将指定字节从设备内存写入文件描述符。

参数

fh

文件的文件描述符

bufPtr_base

设备内存或主机内存中缓冲区的基地址。 对于注册的缓冲区,bufPtr_base 必须保持设置为 cuFileBufRegister 调用中使用的基地址。

size

要写入的字节大小。

file_offset

要写入的文件偏移量。

bufPtr_offset

相对于 bufPtr_base 指针的偏移量,从中写入。 此参数应仅与注册的缓冲区一起使用。

返回值

  • 成功写入的字节大小。

  • -1 表示错误,因此 errno 设置为指示文件系统错误。

  • 所有其他错误都返回 CUfileOpError 枚举值的负整数值。

描述

此 API 通过使用 GDS 功能,将数据从 GPU 内存或主机内存写入到由文件句柄在指定偏移量和大小字节处指定的文件。 该 API 对于未对齐的偏移量和数据大小都能正确工作,尽管性能与对齐写入的性能不相上下。这是一个同步调用,会阻塞直到 IO 完成。

注意

GDS 功能修改了 SysMem 中的标准文件系统元数据。 但是,GDS 功能不承担将该元数据写回永久存储的任何特殊责任。 除非应用程序使用显式的 fsync(2) 调用,否则不能保证系统崩溃后数据仍然存在。 如果文件以 O_SYNC 标志打开,则元数据将在调用完成之前写入磁盘。

有关 bufPtr_offset: 的更多信息,请参阅 cuFileRead 中的注释。

有关更多信息,请参阅以下内容

5.3. cuFile 内存管理功能规范#

本节中的 API 中提到的设备指针地址与调用者的当前上下文有关。 cuFile 依赖用户在使用 cuFileBufRegister API 之前完成自己的分配,并在使用 cuFileBufDeregister API 之后释放。

5.3.1. cuFileBufRegister#

CUfileError_t cuFileBufRegister(const void *bufPtr_base,
                                size_t size, int flags);
  • 根据内存类型,此 API 注册现有的 cuMemAlloc'd(锁定的)内存以用于 GDS IO 操作,或注册主机内存以用于 IO 操作。

参数

bufPtr_base

设备指针的地址。 cuFileReadcuFileWrite **必须**使用此 bufPtr_base 作为基地址。

size

从内存开始映射的字节大小。

flags

为将来使用保留; 必须为 0。

返回值

  • CU_FILE_SUCCESS,如果注册成功。

  • CU_FILE_NVFS_DRIVER_ERROR,如果 nvidia-fs 驱动程序无法处理请求。

  • CU_FILE_INVALID_VALUE,如果失败。

  • CU_FILE_CUDA_DRIVER_ERROR,如果发生 CUDA 特定的错误。 可以使用 CU_FILE_CUDA_ERR (err) 获取 CUresult 代码。

  • CU_FILE_MEMORY_ALREADY_REGISTERED,如果内存已注册。

  • CU_FILE_INTERNAL_ERROR,特定于库的内部错误。

  • CU_FILE_CUDA_MEMORY_TYPE_INVALID,对于不是通过 cudaMalloccuMemAlloc 分配的设备内存。

  • CU_FILE_CUDA_POINTER_RANGE_ERROR,如果大小超出已分配内存的范围。

  • CU_FILE_INVALID_MAPPING_SIZE,如果大小超出 GPU 资源限制。

  • CU_FILE_GPU_MEMORY_PINNING_FAILED,如果没有足够的锁定内存可用。

描述

根据内存类型,此 API 要么注册指定的 GPU 地址,要么注册主机内存地址和大小,以用于 cuFileReadcuFileWrite 操作。 如果需要,用户必须调用 cuFileBufDeregister 以释放 GPU 内存的锁定内存映射。

有关更多信息,请参阅以下内容

5.3.2. cuFileBufDeregister#

CUfileError_t cuFileBufDeregister(const void *bufPtr_base);
  • 根据内存类型,此 API 要么注销 CUDA 内存,要么注销使用 cuFileBufRegister API 注册的主机内存。

参数

bufPtr_base

设备指针的地址,用于释放提供给 cuFileBufRegister 的映射

返回值

  • CU_FILE_SUCCESS,如果注销成功。

  • CU_FILE_MEMORY_NOT_REGISTERED,如果未注册 bufPtr_base

  • CU_FILE_ERROR_INVALID_VALUE,如果无法找到指定内存的注册。

  • CU_FILE_INTERNAL_ERROR,特定于库的内部错误。

描述

此 API 注销由 cuFileBufRegister 注册的内存映射。 有关更多信息,请参阅 cuFileBufRegister

5.4. cuFile Stream API 功能规范#

本节提供有关 cuFile 流 API 功能规范的信息。

流 API 类似于 Read 和 Write,但它们采用流参数来支持异步操作并在 CUDA 流顺序中执行。

5.4.1. cuFileStreamRegister#

CUfileError_t cuFileStreamRegister(CUStream_t stream, unsigned flags);
  • 定义流 I/O API 的输入行为。

参数

stream

要在其中排队操作的 CUDA 流。 如果为 NULL,则在默认 CUDA 流中进行此操作。

flags

以下是有效值

描述

0x0

所有 I/O 参数仅在执行时有效。

0x1

缓冲区偏移值在提交时有效。

0x2

文件偏移值在提交时有效。

0x4

大小在提交时有效。

0x8

所有输入,即缓冲区偏移量、文件偏移量和大小都是 4K 对齐的。

0xf

所有输入都已对齐并在提交时已知。

注意

使用标志 0XF 将获得最佳性能,因为可以在提交时优化工作流程。

描述

此可选 API 向 cuFile 子系统注册流。

此 API 将分配资源以处理 cuFile 的流操作。

API 将在分配资源之前同步流。

流指针应为有效指针。

返回值

  • CU_FILE_SUCCESS,如果提交成功。

  • CU_FILE_ERROR_INVALID_VALUE,如果流规范无效。

  • CU_FILE_DRIVER_ERROR,如果 NVIDIA-fs 驱动程序无法处理请求。

  • CU_FILE_PLATFORM_NOT_SUPPORTED,在不支持的平台上。

5.4.2. cuFileStreamDeregister#

CUfileError_t cuFileStreamDeregister(CUStream_t stream);

参数

stream

要在其中排队操作的 CUDA 流。 如果为 NULL,则在默认 CUDA 流中进行此操作。

flags

为将来使用保留。

描述

此可选 API 向 cuFile 子系统注销流。

此 API 将释放与流关联的已分配 cuFile 资源。

API 将在释放资源之前同步流。

流指针应为有效指针。

流将在 cuFileDriverClose 中自动注销。

返回值

  • CU_FILE_SUCCESS,如果提交成功。

  • CU_FILE_ERROR_INVALID_VALUE,如果流规范无效。

  • CU_FILE_PLATFORM_NOT_SUPPORTED,在不支持的平台上。

5.4.3. cuFileReadAsync#

CUfileError_t cuFileReadAsync(CUFileHandle_t fh,
                        void *bufPtr_base,
                        size_t *size_p,
                        off_t *file_offset_p,
                        off_t *bufPtr_offset_p,
                        int *bytes_read_p,
                        CUstream stream);
  • 通过使用 GDS 功能,或者根据内存指针的类型,将指定字节的读取操作排队到设备内存或主机内存中的 cuFile 句柄。

  • 如果为非 NULL,则操作在流中排序。

  • 假定调用者的当前上下文。

参数

fh

文件的 cuFile 句柄。

bufPtr_base

  • 内存中要读取到的缓冲区的基地址。

  • 可以使用 cudaMemorycudaMallocHostmallocmmap 分配缓冲区。

  • 对于注册的缓冲区,bufPtr_base 必须保持设置为 cuFileBufRegister 调用中使用的基地址。

size_p

指向要读取的字节大小的指针。 如果在 I/O 提交时不知道确切的大小,则应将其设置为该流 I/O 的最大可能 I/O 大小。

file_offset_p

指向要从中读取的文件偏移量的指针。 除非另有使用 cuFileStreamRegister API 设置,否则此值在执行时才会进行评估。

bufPtr_offset_p

指向相对于 bufPtr_base 指针的偏移量的指针,从中写入。 除非另有使用 cuFileStreamRegister API 设置,否则此值在执行时才会进行评估。

bytes_read_p

指向从指定文件句柄读取的字节数的指针。 此指针应为非 NULL 值,并且 *bytes_read_p 设置为 0。 在流中成功执行操作后,值 *bytes_read_p 将包含以下内容之一

  • 成功读取的字节数。

  • -1 表示 IO 错误。

  • 所有其他错误都返回 CUfileOpError 枚举值的负整数值。

stream

  • 要在其中排队操作的 CUDA 流。

  • 如果为 NULL,则使此操作同步。

返回值

  • CU_FILE_SUCCESS,如果提交成功。

  • CU_FILE_DRIVER_ERROR,如果 nvidia-fs 驱动程序无法处理请求。

  • CU_FILE_ERROR_INVALID_VALUE,如果输入失败。

  • CU_FILE_CUDA_ERROR,如果发生 CUDA 特定的错误。

    可以使用 CU_FILE_CUDA_ERR(err) 获取 CUresult 代码。

描述

  • 此 API 通过使用 GDS 功能,将数据从指定文件句柄在指定偏移量和大小字节处读取到 GPU 内存中。

    这是一个异步调用,将操作排队到指定的 CUDA 流中,并且不会阻塞主机线程以等待 IO 完成。 可以使用 cuStreamSynchronize(stream) 等待操作完成。

  • bytes_read_p 内存应使用 cuMemHostAlloc/malloc/mmap 分配,或使用 cuMemHostRegister 注册。

    可以使用 cuMemHostGetDevicePointer 获取从设备访问该内存的指针。

  • 使用 cuFile Stream API 排队的操作相对于流上的其他工作以 FIFO 顺序排序,并且必须在继续流中的下一个操作之前完成。

  • 除非通过 cuFileStreamRegister API 另行指定,否则文件偏移量、缓冲区偏移量或大小参数在执行时才会进行评估。 在这些情况下,大小参数应在提交时设置为最大可能的 I/O 大小,并且可以在流 I/O 执行之前设置为实际大小。

有关更多信息,请参阅以下内容

5.4.4. cuFileWriteAsync#

CUfileError_t cuFileWriteAsync(CUFileHandle_t fh,
                        void *bufPtr_base,
                        size_t *size_p,
                        off_t file_offset_p,
                        off_t bufPtr_offset_p,
                        int *bytes_written_p,
                        CUstream_t stream);
  • 通过使用 GDS,将指定字节的写入操作从设备内存排队到 cuFile 句柄。

参数

fh

文件的 cuFile 句柄。

bufPtr_base

内存中要从中写入的缓冲区的基地址。 可以使用 cudaMemory/cudaMallocHost/malloc/mmap 分配缓冲区。 对于注册的缓冲区,bufPtr_base 必须保持设置为 cuFileBufRegister 调用中使用的基地址。

size_p

指向要写入的字节大小的指针。 如果在 I/O 提交时不知道确切的大小,则应将其设置为该流 I/O 的最大可能 I/O 大小。

file_offset_p

指向要从中写入的文件偏移量的指针。 除非另有使用 cuFileStreamRegister API 设置,否则此值在执行时才会进行评估。

bufPtr_offset_p

指向相对于 bufPtr_base 指针的偏移量的指针,从中写入。 除非另有使用 cuFileStreamRegister API 设置,否则此值在执行时才会进行评估。

bytes_written_p

指向写入到指定文件句柄的字节数的指针。此指针应为非 NULL 值,并且 *bytes_written_p 设置为 0。 在流中成功执行操作后,值 *bytes_written_p 将包含以下内容之一

  • 成功写入的字节数。

  • -1 表示 IO 错误。

  • 所有其他错误都将返回 CUfileOpError 枚举值的负整数值。

stream

要将操作排队的 CUDA 流。

返回值

  • CU_FILE_SUCCESS,如果提交成功。

  • CU_FILE_DRIVER_ERROR,如果 nvidia-fs 驱动程序无法处理请求。

  • CU_FILE_ERROR_INVALID_VALUE,如果输入失败。

  • CU_FILE_CUDA_ERROR,如果发生 CUDA 特定的错误。

    可以使用 CU_FILE_CUDA_ERR(err) 获取 CUresult 代码。

描述

  • 此 API 通过使用 GDS 功能,将数据从 GPU 内存写入到由文件句柄在指定偏移量和大小字节处指定的文件。 这是一个异步调用,将操作排队到指定的 CUDA 流中,并且不会阻塞主机线程以等待 IO 完成。 可以使用 cuStreamSynchronize(stream) 等待操作完成。

  • bytes_written 指针应使用 cuMemHostAlloc 分配或使用 cuMemHostRegister 注册,并且可以使用 cuMemHostGetDevicePointer 获取从设备访问该内存的指针。

  • 使用 cuFile Stream API 排队的操作相对于流上的其他工作以 FIFO 顺序排序,并且必须在继续流中的下一个操作之前完成。

  • 除非通过 cuFileStreamRegister API 另行指定,否则文件偏移量、缓冲区偏移量或大小参数在执行时才会进行评估。 在这些情况下,大小参数应在提交时设置为最大可能的 I/O 大小,并且可以在流 I/O 执行之前设置为实际大小。

有关更多信息,请参阅以下内容

5.5. cuFile 批处理 API 功能规范#

5.5.1. cuFileBatchIOSetUp#

CUfileError_t
cuFileBatchIOSetUp(CUfileBatchHandle_t *batch_idp, int max_nr);

参数

max_nr

(输入)此批处理将容纳的最大事件数。

注意

该数字应介于 1 - properties.io_batch_size 之间

batch_idp

(输出)将在后续批处理 IO 调用中使用。

返回值

  • CU_FILE_SUCCESS,如果成功。

  • CU_FILE_INTERNAL_ERROR,如果发生任何故障。

描述

此接口应是批处理 I/O 操作序列中的第一个调用。 这需要调用者打算使用的最大批处理条目数,并返回一个 CUFileBatchHandle_t,调用者应在后续批处理 I/O 调用中使用该句柄。

有关更多信息,请参阅以下内容

5.5.2. cuFileBatchIOSubmit#

CUfileError_t cuFileBatchIOSubmit(CUfileBatchHandle_t batch_idp,
                                 unsigned nr,
                                 CUfileIOParams_t *iocbp,
                                 unsigned int flags)

参数

batch_idp

新创建的批处理 ID 的输出参数地址,该 ID 从 cuFileBatchSetup 调用中获得。

nr

  • 批处理请求的请求数。

  • 该值必须大于 0 且小于或等于 cuFileBatchIOSetup 中指定的 max_nr

iocbp

该指针包含长度为 nr 数组的 CUfileIOParams_t 数组结构。

flags

为将来使用保留。 应设置为 0。

返回值

  • CU_FILE_SUCCESS,如果成功。

  • CU_FILE_INTERNAL_ERROR,如果发生任何故障。

描述

  • 此 API 将需要用于对其各自的文件句柄、偏移量和大小字节的 GPU/CPU 数据指针数组提交读取/写入操作。

    根据内存指针的类型,数据通过使用 GDS 传输到/从 GPU 内存,或者数据传输到/从 CPU 内存。

    • 这是一个异步调用,并将操作加入到 cuFileIOSetup API 提供的 batch_id 队列中。当使用此 batch_id 时,可以通过 cuFileBatchIOGetStatus 监控操作状态。

    • 可以通过调用 cuFileBatchIOCancel 取消操作,或通过 cuFileBatchIODestroy 销毁操作。

  • CUfileIOParams_t 数组中的条目描述了单个 IO 操作。

    只有当状态指示完成时,“已传输字节数”字段才有效。

  • 使用 cuFile Batch API 排队的操作相对于流上的其他工作是 FIFO 顺序的,并且必须在继续流中的下一个操作之前完成。每个批次中的操作可能会彼此重新排序。

  • 在整个批次完成之前,通过 CUfileIOParams_t 条目的各个 IO 操作的状态字段将具有未定义的值。此定义可能会更改。

有关更多信息,请参阅以下内容

5.5.3. cuFileBatchIOGetStatus#

CUfileError_t cuFileBatchIOGetStatus(CUfileBatchHandle_t batch_idp,
                                     unsigned min_nr,
                                     unsigned *nr,
                                     CUfileIOEvents_t *iocbp,
                                     struct timespec* timeout));

参数

batch_idp

在设置期间获得。

min_nr

请求状态的最小 IO 条目数。min_nr 应大于或等于零,且小于或等于 *nr

nr

这是指向要轮询完成状态的最大请求 IO 条目数的指针,用作输入/输出参数。作为输入,必须设置 *nr 以传递要轮询的最大 IO 请求数。作为输出,*nr 返回已完成的 I/O 数量。

iocbp

包含该批次中已完成 I/O 状态的 CUFileIOEvents_t 数组。

timeout

此参数用于指定在此 API 中等待的时间量,即使最小请求数尚未完成。如果超时,则返回的 IO 数量可能少于 min_nr

返回值

  • CU_FILE_SUCCESS,如果成功。

    此处的成功是指 API 的完成。可以通过检查数组 iocbp 中返回的状态和错误来获得各个 IO 的状态和错误。

  • 对于无效的批次 ID,返回 CU_FILE_ERROR_INVALID_VALUE

描述

  • 这是一个批处理 API,用于通过使用 cuFileBatchIOSubmit 返回的 batch_id 来监控批处理 IO 操作的状态。如果调用 cuFileBatchIOCancel,操作将自动取消,并且所有取消的 IO 操作的状态将反映 CU_FILE_CANCELED

  • 查询批次中每个成员的状态,这对于单个 CUEvent 来说是不可能的。在整个批次完成之前,通过 CUfileIOParams_t 条目的各个 IO 操作的状态字段将具有未定义的值。此定义可能会更改。

有关更多信息,请参阅以下内容

5.5.4. cuFileBatchIOCancel#

CUfileError_t cuFileBatchIOCancel(CUfileBatchHandle_t batch_idp)

参数

batch_idp

要取消的批次 ID。

返回值

  • CU_FILE_SUCCESS,如果成功。

  • 任何失败都返回 CU_FILE_ERROR_INVALID_VALUE

描述

  • 这是一个批处理 API,用于通过使用 cuFileBatchIOSubmit 返回的 batch_id 来取消正在进行的 IO 批处理操作。此 API 尝试取消批次中的单个 IO 操作(如果可能),但不保证取消正在进行的操作。

有关更多信息,请参阅以下内容

5.5.5. cuFileBatchIODestroy#

void cuFileBatchIODestroy(CUfileBatchHandle_t batch_idp)

参数

batch_idp

要销毁的批次句柄。

返回值

void

描述

这是一个批处理 API,用于销毁批处理上下文以及使用 cuFileBatchIOSetup 分配的资源。

有关更多信息,请参阅以下内容

6. cuFile API 示例程序#

以下示例程序使用 cuFile API

// To compile this sample code:
//
// nvcc gds_helloworld.cxx -o gds_helloworld -lcufile
//
// Set the environment variable TESTFILE
// to specify the name of the file on a GDS enabled filesystem
//
// Ex:   TESTFILE=/mnt/gds/gds_test ./gds_helloworld
//
//
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <cuda_runtime.h>
#include "cufile.h"

//#include "cufile_sample_utils.h"
using namespace std;

int main(void) {
        int fd;
        ssize_t ret;
        void *devPtr_base;
        off_t file_offset = 0x2000;
        off_t devPtr_offset = 0x1000;
        ssize_t IO_size = 1UL << 24;
        size_t buff_size = IO_size + 0x1000;
        CUfileError_t status;
        // CUResult cuda_result;
        int cuda_result;
        CUfileDescr_t cf_descr;
        CUfileHandle_t cf_handle;
        char *testfn;

        testfn=getenv("TESTFILE");
        if (testfn==NULL) {
            std::cerr << "No testfile defined via TESTFILE.  Exiting." << std::endl;
            return -1;
        }

        cout << std::endl;
        cout << "Opening File " << testfn << std::endl;

        fd = open(testfn, O_CREAT|O_WRONLY|O_DIRECT, 0644);
        if(fd < 0) {
                std::cerr << "file open " << testfn << "errno " << errno << std::endl;
                return -1;
        }

        // the above fd could also have been opened without O_DIRECT starting CUDA toolkit 12.2
        // (gds 1.7.x version) as follows
        // fd = open(testfn, O_CREAT|O_WRONLY, 0644);

        cout << "Opening cuFileDriver." << std::endl;
        status = cuFileDriverOpen();
        if (status.err != CU_FILE_SUCCESS) {
                std::cerr << " cuFile driver failed to open " << std::endl;
                close(fd);
                return -1;
        }

        cout << "Registering cuFile handle to " << testfn << "." << std::endl;

        memset((void *)&cf_descr, 0, sizeof(CUfileDescr_t));
        cf_descr.handle.fd = fd;
        cf_descr.type = CU_FILE_HANDLE_TYPE_OPAQUE_FD;
        status = cuFileHandleRegister(&cf_handle, &cf_descr);
        if (status.err != CU_FILE_SUCCESS) {
                std::cerr << "cuFileHandleRegister fd " << fd << " status " << status.err << std::endl;
                close(fd);
                return -1;
        }

        cout << "Allocating CUDA buffer of " << buff_size << " bytes." << std::endl;

        cuda_result = cudaMalloc(&devPtr_base, buff_size);
        if (cuda_result != CUDA_SUCCESS) {
                std::cerr << "buffer allocation failed " << cuda_result << std::endl;
                cuFileHandleDeregister(cf_handle);
                close(fd);
                return -1;
        }

        cout << "Registering Buffer of " << buff_size << " bytes." << std::endl;
        status = cuFileBufRegister(devPtr_base, buff_size, 0);
        if (status.err != CU_FILE_SUCCESS) {
                std::cerr << "buffer registration failed " << status.err << std::endl;
                cuFileHandleDeregister(cf_handle);
                close(fd);
                cudaFree(devPtr_base);
                return -1;
        }

        // fill a pattern
        cout << "Filling memory." << std::endl;

        cudaMemset((void *) devPtr_base, 0xab, buff_size);
        cuStreamSynchronize(0);

        // perform write operation directly from GPU mem to file
        cout << "Writing buffer to file." << std::endl;
        ret = cuFileWrite(cf_handle, devPtr_base, IO_size, file_offset, devPtr_offset);

        if (ret < 0 || ret != IO_size) {
                std::cerr << "cuFileWrite failed " << ret << std::endl;
        }

        // release the GPU memory pinning
        cout << "Releasing cuFile buffer." << std::endl;
        status = cuFileBufDeregister(devPtr_base);
        if (status.err != CU_FILE_SUCCESS) {
                std::cerr << "buffer deregister failed" << std::endl;
                cudaFree(devPtr_base);
                cuFileHandleDeregister(cf_handle);
                close(fd);
                return -1;
        }

        cout << "Freeing CUDA buffer." << std::endl;
        cudaFree(devPtr_base);
        // deregister the handle from cuFile
        cout << "Releasing file handle. " << std::endl;
        (void) cuFileHandleDeregister(cf_handle);
        close(fd);

        // release all cuFile resources
        cout << "Closing File Driver." << std::endl;
        (void) cuFileDriverClose();

        cout << std::endl;

        return 0;
}

7. cuFile Batch API 的已知限制#

本节提供有关此 GDS 版本中 cuFile Batch API 的已知限制的信息。

  • 批处理 I/O 主要由托管在 NVMe 或 NVMeOF 设备上的本地文件系统或支持 Linux AIO 的本机文件系统支持。下表概述了 cuFile 批处理 API 对不同文件系统的支持。

    下表概述了 cuFile 批处理 API 对分布式文件系统的支持

文件系统

GDS 批处理模式

注释

Ext4/XFS

读/写支持

DDN EXAScaler

读/写支持

NFS

读/写支持

IBM Spectrum Scale

不可用

将在兼容模式下工作

Weka

不可用

将在兼容模式下工作

BeeGFS

不可用

将在兼容模式下工作

8. 声明#

本文档仅供参考,不应被视为对产品特定功能、条件或质量的保证。NVIDIA Corporation(“NVIDIA”)不对本文档中包含信息的准确性或完整性作任何明示或暗示的陈述或保证,并且对本文档中包含的任何错误不承担任何责任。NVIDIA 对因使用此类信息或因使用此类信息而可能导致的侵犯第三方专利或其他权利的后果或使用不承担任何责任。本文档不承诺开发、发布或交付任何材料(如下定义)、代码或功能。

NVIDIA 保留随时对此文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。

客户在下订单前应获取最新的相关信息,并应验证此类信息是否为最新且完整。

NVIDIA 产品的销售受订单确认时提供的 NVIDIA 标准销售条款和条件的约束,除非 NVIDIA 和客户的授权代表签署的个别销售协议(“销售条款”)另有约定。NVIDIA 在此明确反对将任何客户通用条款和条件应用于购买本文档中引用的 NVIDIA 产品。本文档不直接或间接地形成任何合同义务。

NVIDIA 产品并非设计、授权或保证适用于医疗、军事、航空、航天或生命支持设备,也不适用于 NVIDIA 产品的故障或故障可合理预期会导致人身伤害、死亡或财产或环境损害的应用。NVIDIA 对在此类设备或应用中包含和/或使用 NVIDIA 产品不承担任何责任,因此,此类包含和/或使用由客户自行承担风险。

NVIDIA 不保证或声明基于本文档的产品将适用于任何特定用途。NVIDIA 不一定对每种产品的所有参数进行测试。客户全权负责评估和确定本文档中包含的任何信息的适用性,确保产品适合客户计划的应用,并为该应用执行必要的测试,以避免应用或产品的默认设置。客户产品设计中的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的附加或不同条件和/或要求。对于因以下原因引起或可归因于以下原因的任何默认设置、损坏、成本或问题,NVIDIA 不承担任何责任:(i) 以任何违反本文档的方式使用 NVIDIA 产品,或 (ii) 客户产品设计。

本文档未授予 NVIDIA 专利权、版权或本文档项下的其他 NVIDIA 知识产权的任何明示或暗示的许可。NVIDIA 发布的有关第三方产品或服务的信息不构成 NVIDIA 授予使用此类产品或服务的许可,也不构成对其的保证或认可。使用此类信息可能需要获得第三方在其专利或其他知识产权下的许可,或获得 NVIDIA 在 NVIDIA 专利或其他知识产权下的许可。

只有在事先获得 NVIDIA 书面批准的情况下,才允许复制本文档中的信息,复制时不得进行修改,且必须完全遵守所有适用的出口法律和法规,并附带所有相关的条件、限制和声明。

本文档和所有 NVIDIA 设计规范、参考板、文件、图纸、诊断程序、列表和其他文档(统称为“材料”)均按“原样”提供。NVIDIA 不对材料作任何明示、暗示、法定或其他方面的保证,并明确否认所有关于不侵权、适销性和特定用途适用性的暗示保证。在法律未禁止的范围内,在任何情况下,NVIDIA 均不对因使用本文档而引起的任何损害(包括但不限于任何直接、间接、特殊、偶然、惩罚性或后果性损害,无论因何种原因引起,也无论责任理论如何)承担责任,即使 NVIDIA 已被告知可能发生此类损害。尽管客户可能因任何原因而遭受任何损害,但 NVIDIA 对本文所述产品的对客户的累计总责任应根据产品的销售条款进行限制。

9. OpenCL#

OpenCL 是 Apple Inc. 的商标,经 Khronos Group Inc. 许可使用。

10. 商标#

NVIDIA、NVIDIA 徽标、CUDA、DGX、DGX-1、DGX-2、DGX-A100、Tesla 和 Quadro 是 NVIDIA Corporation 在美国和其他国家/地区的商标和/或注册商标。其他公司和产品名称可能是与其关联的各自公司的商标。