欢迎使用 KvikIO 的 C++ 文档!

欢迎使用 KvikIO 的 C++ 文档!KvikIO 是一个用于高性能文件 IO 的 Python 和 C++ 库。它提供了 cuFile 的 C++ 和 Python 绑定,从而实现了 GPUDirect Storage (GDS)。KvikIO 在 GDS 不可用时也能高效工作,并且可以无缝读写主机和设备数据。

KvikIO C++ 是 RAPIDS 开源软件库套件的一部分,用于 GPU 加速数据科学。


注意:这是 C++ 库的文档。有关 Python 文档,请参阅 kvikio


特性

  • 面向对象的 API。
  • 异常处理。
  • 使用内部线程池进行并发读写。
  • 非阻塞 API。
  • 无缝处理主机和设备 IO。

安装

为了方便起见,我们发布了 Conda 包,可以轻松地将 KvikIO 包含到您的 CMake 项目中。

Conda/Mamba

我们强烈建议使用 mamba 替代 conda,我们在整个文档中都将这样做。

rapidsai 通道安装稳定版本,如下所示

# 在现有环境中安装
mamba install -c rapidsai -c conda-forge libkvikio
# 创建新环境 (CUDA 12)
mamba create -n libkvikio-env -c rapidsai -c conda-forge cuda-version=12.8 libkvikio
# 创建新环境 (CUDA 11)
mamba create -n libkvikio-env -c rapidsai -c conda-forge cuda-version=11.8 libkvikio

rapidsai-nightly 通道安装夜间版本,如下所示

# 在现有环境中安装
mamba install -c rapidsai-nightly -c conda-forge libkvikio
# 创建新环境 (CUDA 12)
mamba create -n libkvikio-env -c rapidsai-nightly -c conda-forge python=3.12 cuda-version=12.8 libkvikio
# 创建新环境 (CUDA 11)
mamba create -n libkvikio-env -c rapidsai-nightly -c conda-forge python=3.12 cuda-version=11.8 libkvikio

注意:如果夜间版本安装不起作用,请在您的 .condarc 中设置 channel_priority: flexible


在 CMake 项目中包含 KvikIO

可以在此处找到如何在现有 CMake 项目中包含 KvikIO 的示例:https://github.com/rapidsai/kvikio/blob/HEAD/cpp/examples/downstream/

从源代码构建

要构建 C++ 示例,请运行

./build.sh libkvikio

然后运行示例

./examples/basic_io

运行时设置

兼容模式 (KVIKIO_COMPAT_MODE)

当 KvikIO 在兼容模式下运行时,它不加载 libcufile.so。而是使用 POSIX 进行读写。请注意,这与 cuFile 中的兼容模式不同。KvikIO 可能会在使用 cuFile 库的非兼容模式下执行 I/O,但 cuFile 库本身可能配置为在其自己的兼容模式下运行。更多详情,请参阅 cuFile 兼容模式cuFile 环境变量

环境变量 KVIKIO_COMPAT_MODE 有三个选项(不区分大小写)

  • ON (别名:TRUE, YES, 1):启用兼容模式。
  • OFF (别名:FALSE, NO, 0):禁用兼容模式,并强制使用 cuFile I/O。如果满足 cuFile 的系统要求并正确配置了 cuFile,则会激活 GDS。但是,如果系统不适合 cuFile,OFF 选项下的 I/O 操作可能会出错。
  • AUTO:首先尝试 cuFile I/O,如果系统不满足 cuFile 的要求,则回退到 POSIX I/O。

AUTO 模式下,KvikIO 会回退到兼容模式

  • 当找不到 libcufile.so 时。
  • 在 Windows Subsystem for Linux (WSL) 中运行时。
  • /run/udev 不可读时,这种情况通常发生在未通过 --volume /run/udev:/run/udev:ro 参数启动的 docker 镜像中运行。

此设置也可以通过 defaults::set_compat_mode()defaults::compat_mode_reset() 进行编程控制。

线程池 (KVIKIO_NTHREADS)

KvikIO 可以自动使用多个线程进行 IO。将环境变量 KVIKIO_NTHREADS 设置为线程池中的线程数。如果未设置,默认值为 1。

此设置也可以通过 defaults::thread_pool_nthreads()defaults::thread_pool_nthreads_reset() 进行控制。

任务大小 (KVIKIO_TASK_SIZE)

KvikIO 将并行 IO 操作拆分为多个任务。将环境变量 KVIKIO_TASK_SIZE 设置为最大任务大小(以字节为单位)。如果未设置,默认值为 4194304 (4 MiB)。

此设置也可以通过 defaults::task_size()defaults::task_size_reset() 进行控制。

GDS 阈值 (KVIKIO_GDS_THRESHOLD)

为了提高小 IO 请求的性能,.pread().pwrite() 实现了一个绕过线程池直接使用 POSIX 后端的快捷方式。将环境变量 KVIKIO_GDS_THRESHOLD 设置为使用 GDS 的最小大小(以字节为单位)。如果未设置,默认值为 1048576 (1 MiB)。

此设置也可以通过 defaults::gds_threshold()defaults::gds_threshold_reset() 进行控制。

弹跳缓冲区大小 (KVIKIO_BOUNCE_BUFFER_SIZE)

KvikIO 在文件和设备内存之间复制时可能需要使用中间主机缓冲区(每个线程一个)。将环境变量 KVIKIO_BOUNCE_BUFFER_SIZE 设置为这些“弹跳”缓冲区的大小(以字节为单位)。如果未设置,默认值为 16777216 (16 MiB)。

此设置也可以通过 defaults::bounce_buffer_size()defaults::bounce_buffer_size_reset() 进行控制。

HTTP 重试

当远程 IO 读取返回错误时的行为可以通过 KVIKIO_HTTP_STATUS_CODESKVIKIO_HTTP_MAX_ATTEMPTS 环境变量控制。KVIKIO_HTTP_STATUS_CODES 控制要重试的状态码,KVIKIO_HTTP_MAX_ATTEMPTS 控制在抛出异常之前的最大尝试次数。

当收到状态码在可重试代码列表中的响应时,KvikIO 将等待一段时间后重试请求。它将继续重试直到达到最大尝试次数。

默认情况下,KvikIO 将重试具有以下状态码的响应

  • 429
  • 500
  • 502
  • 503
  • 504

默认情况下,KvikIO 每次读取将尝试三次。请注意,如果您正在读取通过 KvikIO 的任务大小设置拆分成多次读取的大文件,那么每个任务都将重试,最多达到最大尝试次数。

这些设置也可以通过 defaults::http_max_attempts(), defaults::http_max_attempts_reset(), defaults::http_status_codes()defaults::http_status_codes_reset() 进行控制。

示例

#include <cstddef>
#include <cuda_runtime.h>
#include <kvikio/file_handle.hpp>
using namespace std;
int main()
{
// Create two arrays `a` and `b`
constexpr std::size_t size = 100;
void *a = nullptr;
void *b = nullptr;
cudaMalloc(&a, size);
cudaMalloc(&b, size);
// Write `a` to file
kvikio::FileHandle fw("test-file", "w");
size_t written = fw.write(a, size);
fw.close();
// Read file into `b`
kvikio::FileHandle fr("test-file", "r");
size_t read = fr.read(b, size);
fr.close();
// Read file into `b` in parallel using 16 threads
kvikio::default_thread_pool::reset(16);
{
kvikio::FileHandle f("test-file", "r");
future<size_t> future = f.pread(b_dev, sizeof(a), 0); // Non-blocking
size_t read = future.get(); // Blocking
// Notice, `f` closes automatically on destruction.
}
}
使用 cufile 注册的打开文件的句柄。

有关完整的可运行示例,请参见 https://github.com/rapidsai/kvikio/blob/HEAD/cpp/examples/basic_io.cpp