中文翻译暂不可用,显示俄语原文。
Как работает asynchronous execution на Hopper (copy engine vs compute)?
Краткий тезис
Архитектура NVIDIA Hopper (H100) вводит два выделенных copy engine для асинхронного копирования данных между хостом и устройством (H2D/D2H), которые могут работать параллельно с compute engine (исполнением ядер). Дополнительно Tensor Memory Accelerator (TMA) обеспечивает асинхронное копирование между глобальной и разделяемой памятью (D2D). Это позволяет перекрывать (overlap) передачу данных с вычислениями, скрывая latency и повышая утилизацию GPU. Для LLM-инференса и агентных RAG-систем такой механизм критичен: можно prefetch’ить следующий батч или контекст, пока обрабатывается текущий.
1. Термины и контекст
Asynchronous execution — выполнение операций (копирование, вычисления) без блокировки основного потока. В CUDA это реализуется через streams и events.
Copy engine — аппаратный блок GPU, специализирующийся на копировании данных между памятью хоста и устройства (H2D/D2H) или между устройствами (P2P). В H100 их два: один для H2D, другой для D2H.
Compute engine — блок, исполняющий CUDA-ядра (kernel). В H100 это набор SM (Streaming Multiprocessors) с поддержкой Tensor Cores.
TMA (Tensor Memory Accelerator) — новый блок в Hopper для асинхронного копирования данных из глобальной памяти в разделяемую (shared memory) и обратно. Поддерживает многомерные массивы, выравнивание и трансформации.
Overlap — техника, при которой передача данных и вычисления выполняются одновременно, скрывая задержки (latency) копирования.
2. Архитектура H100: два copy engine + compute
В H100 реализована асимметричная схема:
| Engine | Назначение | Пропускная способность |
|---|---|---|
| Copy engine 0 (H2D) | Копирование с хоста на устройство | до 50 GB/s (PCIe Gen5) |
| Copy engine 1 (D2H) | Копирование с устройства на хост | до 50 GB/s |
| Compute engine | Исполнение ядер | до 989 TFLOPS (FP8) |
Все три engine могут работать параллельно, если они используют разные streams и не конфликтуют по ресурсам памяти.
Пример параллелизма:
- Stream A: копирование следующего батча с хоста на GPU (H2D)
- Stream B: выполнение ядра для текущего батча
- Stream C: копирование результатов предыдущего батча на хост (D2H)
Таким образом, за время одного kernel launch можно полностью скрыть latency передачи данных.
3. Как работает copy engine: DMA, streams, events
Copy engine использует DMA (Direct Memory Access) — прямой доступ к памяти без участия ядер. Операции запускаются через cudaMemcpyAsync() и выполняются в указанном stream.
Ключевые моменты:
- Копирование в одном stream блокирует последующие операции в том же stream, но не в других.
- Для синхронизации используются events:
cudaEventRecord()иcudaStreamWaitEvent(). - Copy engine может работать только с памятью, закреплённой (pinned) на хосте (cudaHostAlloc или
cudaMallocHost). Без pinned memory копирование идёт через промежуточный буфер и не может быть асинхронным.
Пример кода:
cudaStream_t stream1, stream2;
cudaStreamCreate(&stream1);
cudaStreamCreate(&stream2);
// Асинхронное копирование H2D в stream1
cudaMemcpyAsync(d_data, h_data, size, cudaMemcpyHostToDevice, stream1);
// Запуск ядра в stream2 (параллельно копированию)
kernel<<<grid, block, 0, stream2>>>(d_other);
// Синхронизация: ждём завершения копирования
cudaStreamSynchronize(stream1);
4. TMA (Tensor Memory Accelerator) — асинхронное D2D
TMA — это аппаратный блок, который может копировать данные из глобальной памяти в разделяемую (shared memory) асинхронно, без участия потоков (warps). Он поддерживает:
- Многомерные тензоры (1D, 2D, 3D, 4D) с произвольными шагами (strides).
- Трансформации (например, транспонирование, swizzle).
- Выравнивание по границам кэш-линий.
- Асинхронность: копирование запускается одной инструкцией (cp.async.bulk), а завершение проверяется через cp.async.bulk.wait_group.
Сравнение TMA и обычного copy engine:
| Характеристика | Copy engine (H2D/D2H) | TMA (D2D) |
|---|---|---|
| Тип памяти | Хост ↔ Device | Global → Shared |
| Участие потоков | Нет (DMA) | Нет (аппаратный блок) |
| Поддержка многомерных копий | Нет (только линейные) | Да |
| Трансформации | Нет | Да (swizzle, transpose) |
| Использование в ядре | Только до/после kernel | Внутри kernel (async) |
| Пропускная способность | ~50 GB/s | ~3 TB/s (HBM3) |
TMA особенно полезен для операций, требующих загрузки данных в shared memory перед вычислением (например, матричное умножение, attention).
5. Пример: асинхронный pipeline для LLM inference
Рассмотрим батч-обработку запросов в LLM (например, для агентного RAG, где каждый запрос требует поиска и генерации).
Без асинхронности:
- Копировать входные данные (prompt) на GPU.
- Выполнить forward pass.
- Копировать результаты на хост.
- Повторить для следующего батча.
Всё последовательно → GPU простаивает во время копирования.
С асинхронностью (overlap):
cudaStream_t computeStream, h2dStream, d2hStream;
// Инициализация streams
for (int i = 0; i < num_batches; ++i) {
// Prefetch: копируем следующий батч в h2dStream
if (i + 1 < num_batches)
cudaMemcpyAsync(d_input_next, h_input[i+1], size, cudaMemcpyHostToDevice, h2dStream);
// Вычисляем текущий батч в computeStream
launch_llm_kernel(d_input[i], d_output[i], computeStream);
// Копируем результат предыдущего батча на хост в d2hStream
if (i > 0)
cudaMemcpyAsync(h_output[i-1], d_output[i-1], size, cudaMemcpyDeviceToHost, d2hStream);
// Синхронизация перед следующей итерацией (можно через events)
cudaStreamSynchronize(computeStream);
}
В результате latency копирования скрывается за вычислениями. Для LLM с большими батчами (например, 4096 токенов) это даёт прирост throughput до 20–30%.
6. Применение в Agentic RAG
Агентные RAG-системы часто выполняют несколько параллельных действий:
- Поиск в векторной БД (CPU-bound).
- Загрузка документов в память GPU (H2D).
- Генерация ответа LLM (GPU compute).
Используя асинхронные copy engine, можно:
- Пока LLM генерирует ответ для одного запроса, prefetch’ить контекст для следующего.
- Если агент вызывает несколько инструментов (например, поиск + суммаризация), загружать их результаты на GPU параллельно.
Пример архитектуры:
Поток 1 (CPU): поиск документов → формирование промпта → pinned buffer
Поток 2 (GPU H2D): асинхронное копирование промпта на GPU
Поток 3 (GPU compute): инференс LLM
Поток 4 (GPU D2H): копирование ответа на хост
Все потоки работают одновременно, утилизация GPU близка к 100%.
7. Ограничения и best practices
- Pinned memory обязательно: без неё
cudaMemcpyAsyncведёт себя как синхронный. - Не все копирования можно перекрыть: если kernel использует ту же память, что копируется, нужна синхронизация.
- TMA требует поддержки в коде: нужно использовать специальные инструкции PTX или библиотеки (CUTLASS, CuTe).
- Число streams ограничено: обычно 2–4 достаточно.
- Профилирование: используйте
nsys(NVIDIA Nsight Systems) для визуализации overlap.
8. Пет-проект для закрепления
Задача: Реализовать асинхронный pipeline для batch-инференса небольшой LLM (например, GPT-2) с overlapping копирования и вычислений.
Инструменты: Python + PyTorch + CUDA streams (через torch.cuda.Stream), или C++/CUDA.
Шаги:
- Создать три CUDA streams:
h2d,compute,d2h. - Подготовить pinned memory на хосте для входных данных (использовать
torch.utils.cpp_extensionилиcudaHostAlloc). - В цикле по батчам:
- Запустить асинхронное копирование следующего батча в
h2dstream. - Запустить kernel (forward) в
computestream. - Запустить копирование предыдущего результата в
d2hstream.
- Запустить асинхронное копирование следующего батча в
- Измерить время выполнения с overlap и без.
- Визуализировать timeline через Nsight Systems.
Ожидаемый результат: Ускорение в 1.5–2 раза по сравнению с последовательным выполнением для 4–8 батчей.
9. Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 703 | Оптимизация latency в RAG |
| 704 | Batching и динамический батчинг |
| 705 | GPU memory management (pinned memory, unified memory) |
| 706 | Tensor Cores и mixed precision |
| 708 | Pipeline parallelism для LLM |
| 710 | Профилирование GPU приложений |
10. Навигация
- Предыдущий: 706
- Следующий: 708
- Индекс: 00. Индекс разборов
Навигация
- Предыдущий: 706
- Следующий: 708
- Индекс: 00. Индекс разборов