AiKraft
Главная/Блог/Гайд/NVIDIA KvikIO: Ускорение ввода-вывода…
Гайд10 мин чтения · 22 октября 2026 г.

NVIDIA KvikIO: Ускорение ввода-вывода данных в GPU через GPUDirect Storage

Глубокое руководство по использованию NVIDIA KvikIO для прямого чтения данных в память GPU, обхода CPU и максимизации производительности AI-моделей.

NVIDIA KvikIO: Ускорение ввода-вывода данных в GPU через GPUDirect Storage

В эпоху больших языковых моделей (LLM) и сложных нейросетей данные стали таким же критическим ресурсом, как и вычислительная мощность. Согласно отчету Stanford AI Index за 2025 год, вычислительная мощность для значимых AI-моделей удваивается примерно каждые пять месяцев, в то время как размер наборов данных для обучения увеличивается каждые восемь месяцев. Этот дисбаланс создает узкое горлышко: если данные не поступают на ускорители достаточно быстро, мощные GPU простаивают, ожидая загрузки информации. Традиционный путь передачи данных — через память CPU — становится неприемлемым bottleneck. Здесь на сцену выходит технология NVIDIA Magnum IO GPUDirect Storage (GDS), которая позволяет передавать данные напрямую между хранилищем и памятью GPU, минуя процессор. Однако для разработчиков на Python, которые составляют основу современного AI-стека, прямой доступ к низкоуровневым API часто сложен. Именно здесь вступает в игру библиотека NVIDIA KvikIO, предоставляющая высокоуровневый интерфейс для работы с GDS.

В этой статье мы подробно разберем, как использовать KvikIO для эффективного чтения данных в память GPU, как настроить параметры для оптимизации производительности и как диагностировать, какой именно путь передачи данных был использован системой. Мы рассмотрим архитектуру взаимодействия слоев, практические примеры кода, тонкости настройки параметров cuFile и KvikIO, а также реальные кейсы использования этой технологии в индустрии. Это руководство предназначено для инженеров по машинному обучению и разработчиков, стремящихся выжать максимум из своей инфраструктуры.

01Архитектура взаимодействия: KvikIO, cuFile и GPUDirect Storage

Чтобы понять, как работает KvikIO, необходимо рассмотреть иерархию компонентов, участвующих в процессе ввода-вывода. GPUDirect Storage (GDS) — это более широкая технология, обеспечивающая ускоренное перемещение данных между поддерживаемым хранилищем и памятью GPU. Для хранения на основе файловых систем (например, NVMe SSD) основным интерфейсом является библиотека cuFile (C API). Она предоставляет функции для регистрации буферов GPU и выполнения операций I/O.

KvikIO располагается над cuFile, выступая в роли высокоуровневого адаптера. Он предоставляет удобные интерфейсы на Python и C++, которые позволяют разработчикам работать с файлами так же естественно, как с обычными объектами, но с возможностью управления деталями передачи данных. Важно понимать, что выбор пути передачи данных происходит на двух независимых уровнях:

  1. Уровень KvikIO: Библиотека решает, использовать ли cuFile для выполнения запроса или применить собственный POSIX-совместимый путь, который предполагает буферизацию данных через память CPU.
  2. Уровень cuFile: Если KvikIO передал запрос в cuFile, то сама библиотека cuFile решает, использовать ли ускоренный путь через модуль ядра nvidia-fs (GDS) или fallback-путь через CPU.

Это разделение ответственности дает гибкость, но требует понимания того, как каждый уровень влияет на итоговую производительность. Вызов API cuFile не гарантирует, что данные прошли через GDS; это лишь означает, что KvikIO выбрал этот путь для обработки запроса.

Схема выполнения запроса в KvikIO и cuFile
Схема выполнения запроса в KvikIO и cuFile

02Требования к системе и подготовка окружения

Перед тем как приступить к работе, необходимо убедиться, что ваша инфраструктура готова к использованию GPUDirect Storage. Для успешного выполнения задач требуется следующая конфигурация:

  • Операционная система: Linux-система с установленным драйвером NVIDIA GPU и пакетом GPUDirect Storage.
  • Хранилище: Устройство хранения, поддерживаемое GDS (например, NVMe SSD), и файловая система, совместимая с GDS (например, ext4, XFS, Btrfs).
  • Топология PCIe: Желательно наличие PIX-соединения (PCIe eXpress Direct) между выбранным GPU и устройством NVMe, что означает прохождение пути через не более одного моста PCIe. Это минимизирует задержки.
  • Настройки BIOS/Kernel: Для обеспечения прямых передач между устройствами PCIe (peer-to-peer) необходимо отключить IOMMU и ACS (Access Control Services) в настройках системы.
  • Модуль ядра: Должен быть загружен модуль nvidia-fs, который обеспечивает ускоренный путь передачи данных.

Вы можете проверить топологию GPU и хранилища с помощью команды:

terminalbash
$ nvidia-smi topo -nvme

Для установки KvikIO рекомендуется создать изолированное виртуальное окружение Python. Ниже приведен пример установки библиотеки для CUDA 13:

terminalbash
$ python3 -m venv kvikio-env
$ source kvikio-env/bin/activate
$ python -m pip install kvikio-cu13

После установки убедитесь, что зависимости (включая CuPy) были корректно установлены:

terminalbash
$ python -m pip show kvikio-cu13 cupy-cuda13x
Архитектура хранения данных NVIDIA AI Storage
Архитектура хранения данных NVIDIA AI Storage

03Шаг 1: Инспекция конфигурации и параметров

Прежде чем выполнять операции ввода-вывода, критически важно проверить текущие настройки KvikIO и cuFile. По умолчанию KvikIO работает в режиме AUTO, что означает попытку использовать cuFile с автоматическим падением в режим POSIX, если cuFile недоступен. Также существует параметр gds_threshold, определяющий минимальный размер запроса, при котором KvikIO обращается к cuFile. Запросы меньшего размера обрабатываются напрямую через POSIX-путь KvikIO.

Вы можете проверить текущие настройки, используя следующий Python-код:

terminalpython
import kvikio
import kvikio.cufile_driver as cufile_driver
import kvikio.defaults as defaults

print(f"KvikIO version: {kvikio.__version__}")
print(f"cuFile version: {cufile_driver.libcufile_version()}")
print(f"Compatibility mode: {defaults.get('compat_mode').name}")
print(f"GDS threshold: {defaults.get('gds_threshold')}")

На типичной тестовой системе вывод будет выглядеть так: режим совместимости AUTO и порог GDS 16 KiB. Эти параметры можно изменять как через переменные окружения (KVIKIO_COMPAT_MODE, KVIKIO_GDS_THRESHOLD), так и программно:

terminalpython
# Установка нескольких параметров сразу
defaults.set({"task_size": 1024**3, "num_threads": 8})

# Отключение режима совместимости (принудительное использование cuFile)
defaults.set("compat_mode", kvikio.CompatMode.OFF)

Кроме того, полезно запустить диагностический скрипт GDS, чтобы убедиться, что система распознает все компоненты:

terminalbash
$ /usr/local/cuda-13.3/gds/tools/gdscheck.py -p 2>&1 | less -R
Визуализация стека технологий NVIDIA DOCA
Визуализация стека технологий NVIDIA DOCA
💡
Совет по оптимизации. Параметр task_size в KvikIO определяет размер чанков, на которые разбивается большой запрос на чтение. Оптимальное значение зависит от размера ваших данных и возможностей GPU. Слишком маленькие чанки увеличивают накладные расходы на планирование, слишком большие могут привести к неэффективному использованию памяти.

04Шаг 2: Чтение файла в память GPU

Теперь, когда окружение настроено, перейдем к практической части. Создадим тестовый файл размером 1 Гигабайт с случайными данными. Использование прямого ввода-вывода (direct I/O) и синхронизации с диском (fsync) гарантирует, что данные физически записаны на хранилище:

terminalbash
$ dd if=/dev/urandom \
    of=/mnt/nvme1/kvikio-tutorial/kvikio-example.bin \
    bs=1M count=1024 \
    oflag=direct conv=fsync \
    status=progress

Следующий код демонстрирует, как прочитать этот файл непосредственно в буфер GPU, используя библиотеку CuPy и KvikIO:

terminalpython
from pathlib import Path
import cupy as cp
import kvikio

file_path = Path("/mnt/nvme1/kvikio-tutorial/kvikio-example.bin")

# Выделение буфера в памяти GPU
gpu_buffer = cp.empty(
    file_path.stat().st_size,
    dtype=cp.uint8
)

# Чтение файла в буфер GPU
with kvikio.CuFile(file_path, "r") as file:
    bytes_read = file.read(gpu_buffer)

# Проверка результата
assert bytes_read == gpu_buffer.nbytes
print(f"Successfully read {bytes_read} bytes into GPU memory.")

Контекстный менеджер with обеспечивает корректное открытие файла и выполнение операции чтения. Возвращаемое значение подтверждает объем прочитанных байт, но, как мы увидим далее, оно не говорит нам о том, какой физический путь был использован для передачи данных.

Сетевая инфраструктура Magnum IO
Сетевая инфраструктура Magnum IO

05Шаг 3: Диагностика пути передачи данных

Самый важный аспект работы с GDS — это понимание того, прошли ли данные через ускоренный путь nvidia-fs или через эмуляцию через CPU. Для этого в cuFile встроена система статистики, которую можно включить с помощью переменной окружения CUFILE_STATS_LEVEL=3.

Чтобы проанализировать статистику, необходимо запустить скрипт в интерактивном режиме Python, чтобы процесс оставался активным после выполнения операции чтения. Затем мы можем использовать утилиту gds_stats для просмотра накопленных счетчиков:

terminalbash
$ CUFILE_STATS_LEVEL=3 python3 -i read_with_kvikio.py

После выполнения кода в интерактивной оболочке введите:

terminalbash
>>> import kvikio.cufile_driver as cufile_driver
cufile_driver.gds_stats()

В выводе статистики вы увидите два ключевых счетчика:

  • nvfs: Количество операций, прошедших через модуль ядра nvidia-fs (ускоренный путь GDS).
  • posix: Количество операций, обработанных через совместимый путь cuFile (через CPU).

В типичном успешном сценарии для файла 1 ГБ вы увидите, что все 256 операций чтения (разбитых по умолчанию на чанки по 4 МБ) прошли через nvfs, а posix равен нулю. Это подтверждает, что данные были загружены напрямую в GPU, минуя CPU.

Функциональные возможности MIO (Magnum IO)
Функциональные возможности MIO (Magnum IO)

06Шаг 4: Сравнение путей и настройка параметров

Давайте проверим, как изменение параметров влияет на выбор пути. Мы можем принудительно заставить KvikIO использовать cuFile, отключив режим совместимости:

terminalbash
$ CUFILE_STATS_LEVEL=3 \
    KVIKIO_COMPAT_MODE=off \
    python3 -i read_with_kvikio.py

В этом случае gds_stats все равно покажет операции nvfs, так как cuFile на своей стороне также выберет ускоренный путь, если система позволяет. Однако, если мы принудительно заставим cuFile использовать совместимый режим, ситуация изменится:

terminalbash
$ CUFILE_STATS_LEVEL=3 \
    KVIKIO_COMPAT_MODE=off \
    CUFILE_FORCE_COMPAT_MODE=true \
    python3 -i read_with_kvikio.py

Теперь операции будут зафиксированы в счетчике posix, так как cuFile намеренно избегает использования nvidia-fs. Наконец, если мы включим режим совместимости на уровне KvikIO:

terminalbash
$ KVIKIO_COMPAT_MODE=on \
    python3 read_with_kvikio.py

KvikIO вообще не будет вызывать cuFile, а выполнит чтение через свой собственный POSIX-бэкенд с буферизацией в CPU. В этом случае cuFile не зафиксирует операцию, так как он вообще не участвовал в процессе.

07Шаг 5: Внутренняя конфигурация cuFile

После того как KvikIO выбрал путь через cuFile, сама библиотека cuFile применяет дополнительные настройки, определяющие, как запрос будет разбит на подзадачи и распараллелен. Эти настройки задаются в файле cufile.json и работают независимо от параметров KvikIO.

Ключевые параметры cuFile включают:

  • execution.parallel_io: Включает внутреннее параллельное обработка в cuFile.
  • execution.max_io_threads: Ограничивает количество рабочих потоков cuFile для каждой очереди GPU.
  • execution.min_io_threshold_size_kb: Устанавливает целевой минимальный размер для внутренних запланированных кусков данных.
  • execution.max_request_parallelism: Ограничивает степень параллелизма, которую cuFile готовит для одного запроса.

Рассмотрим пример: если KvikIO отправляет один запрос на 1 ГБ, а в cufile.json установлено max_io_threads=4 и max_request_parallelism=4, то cuFile разобьет этот запрос на 4 части по 256 МБ. Однако, если буфер GPU не зарегистрирован для прямого DMA, cuFile будет использовать "bounce buffer" (буфер-посредник) в памяти GPU, копируя данные из него в целевой буфер. В этом случае, даже если логический размер куска 256 МБ, физическая передача через nvidia-fs может быть разбита на более мелкие чанки (например, по 16 МБ), что зависит от внутренней реализации slabs в GDS.

⚠️
Важно. Параметр min_io_threshold_size_kb не всегда определяет размер физического сетевого или дискового пакета. Он влияет на планирование задач внутри cuFile. Фактический размер передачи может быть меньше из-за ограничений драйвера или модуля nvidia-fs.

08Практическое применение в экосистеме NVIDIA

KvikIO является частью библиотеки NVIDIA CUDA-X для науки о данных (ранее известной как RAPIDS). Его интеграция с GDS изначально была разработана для библиотеки cuDF (GPU DataFrame), где параллельное чтение файлов Parquet и ORC через GDS значительно ускорило загрузку данных. Эта архитектура была перенесена в KvikIO, что сделало его универсальным инструментом.

Сегодня KvikIO используется в различных критически важных приложениях:

  • cuCIM: Для цифровых патологических исследований, где требуется обработка огромных изображений высокого разрешения.
  • cuPhoton: Для анализа научных изображений, где скорость загрузки данных напрямую влияет на время вывода моделей.
  • GPU-accelerated Presto: Для аналитических рабочих нагрузок, демонстрирующих преимущества GDS в запросах к большим данным.

Эти примеры показывают, что KvikIO — это не просто утилита для чтения файлов, а фундаментальный слой ввода-вывода, который позволяет приложениям AI и аналитики полностью использовать потенциал современных GPU-хранилищ.

09Что это значит на практике

Для разработчиков AI и ML внедрение KvikIO и GPUDirect Storage означает переход от модели, где GPU ждет данные, к модели, где данные поступают на GPU с пропускной способностью, близкой к физической границе шины PCIe. Это особенно важно для:

  1. Обучения больших моделей: Ускорение загрузки датасетов сокращает время цикла обучения, позволяя исследователям быстрее итерировать эксперименты.
  2. Инференса в реальном времени: В сценариях, где требуется быстрая подгрузка весов моделей или входных данных, задержки, вызванные копированием через CPU, могут стать критичными.
  3. Эффективности использования ресурсов: Освобождение CPU от задач копирования данных позволяет ему заниматься другими задачами, такими как предобработка данных или управление оркестраторами.

Для достижения максимальной производительности рекомендуется:

  • Всегда проверять статистику gds_stats после внедрения изменений.
  • Настраивать task_size в KvikIO и параметры параллелизма в cufile.json под конкретный объем данных и топологию системы.
  • Использовать зарегистрированные буферы GPU, если это возможно, чтобы избежать накладных расходов на копирование через bounce buffers.

Изучение документации NVIDIA GPUDirect Storage и эксперименты с настройками KvikIO на вашей конкретной инфраструктуре — лучший способ понять, как извлечь максимум из этой мощной технологии.

Источник: NVIDIA Developer ↗