Nsight Systems vs PyTorch Profiler: анализ узких мест передачи данных в GPU | AiManual
AiManual Logo Ai / Manual.
06 Янв 2026 Гайд

NVIDIA Nsight vs PyTorch Profiler: как найти и убить тормоза передачи данных в ML

Подробное сравнение NVIDIA Nsight Systems и PyTorch Profiler для поиска bottlenecks в передаче данных AI/ML моделей. Практические кейсы, чеклисты, примеры кода.

Ваша модель ResNet обучается в 3 раза медленнее, чем у коллеги с таким же GPU. Llama-инференс простаивает 40% времени. Вы обновили даталоадер, переписали препроцессинг, но FPS не растет.

Проблема не в слоях, не в оптимизаторе, не в learning rate. Проблема в том, что GPU ждет данные. Простаивает. Сжигает ваши деньги на аренду инстансов впустую.

Две технологии обещают помочь: NVIDIA Nsight Systems и PyTorch Profiler. Обе показывают хронологию выполнения. Обе рисуют красивые графики. Но одна видит то, что скрыто от другой.

GPU ждет - вы платите

Откройте htop во время обучения. CPU загружен на 90%, GPU - на 30%. Знакомо? Это классический data transfer bottleneck. GPU простаивает, пока CPU готовит следующий батч.

⚠️
На AWS p3.8xlarge (4 x V100) простаивающий GPU стоит $12.20 в час. Если он ждет данные 40% времени - вы выбрасываете $4.88 каждый час. За месяц тренировки - $3500 в канализацию.

Почему это происходит? Потому что:

  • DataLoader с num_workers=0 (самоубийство производительности)
  • Слишком тяжелый препроцессинг в основном процессе
  • pin_memory=False (потеря 15-20% скорости)
  • Неправильный размер батча для вашей PCIe шины
  • Конфликт за память между процессами DataLoader

Но как это доказать? Как найти конкретную операцию, которая тормозит весь пайплайн?

PyTorch Profiler: быстрый диагноз сверху

PyTorch Profiler - это как термометр. Быстро, просто, показывает температуру. Но не говорит, какая именно бактерия вызвала воспаление.

Вот как выглядит типичное использование:

import torch
from torch.profiler import profile, record_function, ProfilerActivity

with profile(
    activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
    schedule=torch.profiler.schedule(wait=1, warmup=1, active=3),
    on_trace_ready=torch.profiler.tensorboard_trace_handler('./logs'),
    record_shapes=True,
    profile_memory=True,
    with_stack=True
) as prof:
    for batch_idx, (data, target) in enumerate(train_loader):
        if batch_idx >= 5:
            break
        data = data.cuda(non_blocking=True)
        target = target.cuda(non_blocking=True)
        
        with record_function("forward"):
            output = model(data)
        
        with record_function("loss"):
            loss = criterion(output, target)
        
        with record_function("backward"):
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
        
        prof.step()

Запускаете, открываете TensorBoard, видите timeline. И тут начинается самое интересное.

1 Что PyTorch Profiler видит хорошо

Он отлично показывает:

  • Время выполнения каждого оператора (conv2d, linear, etc.)
  • Потребление памяти GPU на каждом этапе
  • Цепочку вызовов Python (благодаря with_stack=True)
  • Куча удобных готовых отчетов в TensorBoard
Сильные стороны Слабые стороны
Интеграция в одну строку кода Не видит системные вызовы
Работает в Jupyter ноутбуках Слеп к DMA операциям
Готовые отчеты TensorBoard Нет детализации по PCIe
Трассировка памяти Python Ограниченная глубина стека

Но вот что он НЕ видит. И это критично.

2 Слепые зоны PyTorch Profiler

Попробуйте найти ответы на эти вопросы в отчете PyTorch Profiler:

  • Сколько времени заняла передача данных из host memory в GPU memory?
  • Были ли задержки из-за синхронизации cudaStreamSynchronize?
  • Какой процесс потребляет CPU time во время подготовки данных?
  • Есть ли contention между процессами DataLoader за системные ресурсы?
  • Загружена ли PCIe шина на 100% или простаивает?

Не найдете. Потому что PyTorch Profiler работает на уровне PyTorch операций, а не на уровне системы. Он видит "data.cuda()", но не видит, что происходит внутри этого вызова.

Это как пытаться диагностировать болезнь двигателя, глядя только на спидометр.

💡
Используйте PyTorch Profiler для быстрой проверки: «Есть ли явные аномалии в графе вычислений?». Но для глубокого анализа data transfer bottlenecks он недостаточен.

NVIDIA Nsight Systems: рентген для вашего пайплайна

Nsight Systems - это хирургический инструмент. Он режет глубоко, до кости. Видит все: от системных вызовов до колебаний напряжения на шине PCIe.

Установка проще, чем кажется:

# Установка (Ubuntu/Debian)
wget https://developer.nvidia.com/downloads/assets/tools/secure/nsight-systems/2024_1_2/nsight-systems-linux-2024.1.2.deb
sudo apt install ./nsight-systems-linux-2024.1.2.deb

# Или через контейнер (рекомендуется)
docker run --gpus all --rm -it \
  -v $(pwd):/workspace \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  nvcr.io/nvidia/nsight-systems:2024.1 \
  /bin/bash

Запуск профилирования:

# Самый простой запуск
nsys profile -o my_report \
  --trace=cuda,nvtx,osrt,cudnn,cublas \
  python train.py

# С дополнительными опциями для data transfer анализа
nsys profile -o detailed_report \
  --trace=cuda,nvtx,osrt \
  --sample=cpu \
  --cpuctxsw=true \
  --cudabacktrace=true \
  --gpu-metrics-device=all \
  --force-overwrite true \
  python train.py --batch-size 64 --workers 4

3 Что вы увидите в отчете Nsight

Откройте .nsys-rep файл в Nsight Systems GUI. Перед вами - хронологическая лента времени. Вот на что смотреть:

  1. CPU Threads - каждый поток отображается отдельной строкой. Видно, когда DataLoader worker простаивает, ожидая GIL.
  2. GPU Streams - отдельные потоки выполнения на GPU. Видно разрывы в вычислениях (когда GPU ждет данные).
  3. Memory Transfers - синие полоски HtoD (Host to Device) и DtoH (Device to Host). Их длина - время передачи.
  4. PCIe Utilization - график загрузки шины. Если он не достигает 90% - у вас проблемы с настройкой.
  5. Context Switches - переключения между процессами. Каждое такое переключение стоит 1-2 микросекунды простоя.

Вот реальный пример из проекта по обучению Llama 3.2:

Nsight показал, что DataLoader workers тратят 60% времени на ожидание pthread_mutex_lock. Причина - глобальная блокировка в пользовательском augmentator. Исправление ускорило training на 2.3x.

4 Как читать Nsight отчет: практический кейс

Допустим, вы видите такую картину:

  1. GPU вычисляет 5ms
  2. Потом простаивает 15ms
  3. Потом получает новый батч за 2ms
  4. Снова вычисляет 5ms

Ваш GPU utilization = 5/(5+15+2) = 22.7%. Ужасно.

Смотрите на CPU threads. Видите, что DataLoader worker 0 работает 10ms, потом sleep 10ms. Почему?

Раскрываете стек вызовов (Ctrl+клик на операции). Видите:

# В стеке вызовов:
dataloader.py:get_batch()
custom_augmentor.py:heavy_transform()  # 8ms!
image_utils.py:apply_filter()          # 2ms
libjpeg-turbo:decode_jpeg()            # уже быстро

Бинго! heavy_transform() съедает 8ms. Это и есть bottleneck.

Но Nsight показывает больше. Смотрите на Memory Transfers. Видите, что после heavy_transform() идет memcpy HtoD на 1.5ms. А PCIe utilization в этот момент - всего 30%.

Значит, проблема не в шине. Проблема в том, что данные не готовы для передачи. Или pin_memory не настроен.

Совместное использование: убийственная комбинация

Один инструмент не заменяет другой. Они дополняют. Вот рабочий процесс:

5 Шаг 1: Быстрый скрининг PyTorch Profiler

Запускаете на 10-20 итерациях. Смотрите в TensorBoard:

# Минимальный код для проверки
torch.profiler.record_function("data_loading")
data = next(iter(train_loader))
torch.profiler.record_function("to_gpu")
data = data.cuda()
# ... остальной код

Если видите, что "data_loading" занимает 50% времени итерации - проблема очевидна. Переходите к шагу 2.

6 Шаг 2: Глубокий анализ Nsight Systems

Запускаете с флагами для детального анализа:

nsys profile -o deep_analysis \
  --trace=cuda,nvtx,osrt \
  --sample=cpu \
  --cpuctxsw=true \
  --cuda-memory-usage=true \
  --gpu-metrics-device=0 \
  --gpu-metrics-set=ga10x \
  python train.py --epochs 1 --steps 100

В GUI анализируете:

  1. Ищете разрывы в GPU execution timeline
  2. Смотрите, что происходит на CPU в эти моменты
  3. Проверяете длительность memcpy операций
  4. Анализируете contention между потоками

7 Шаг 3: Внедрение NVTX маркеров

Чтобы Nsight показывал понятные названия операций, добавьте NVTX маркеры:

import torch.cuda.nvtx as nvtx

class CustomDataLoader:
    def __iter__(self):
        for batch in self.dataset:
            nvtx.range_push("data_preprocessing")
            # тяжелые трансформации
            batch = self.augment(batch) 
            nvtx.range_pop()
            
            nvtx.range_push("to_gpu_async")
            batch = batch.to('cuda', non_blocking=True)
            nvtx.range_pop()
            
            yield batch

Теперь в Nsight отчете вместо анонимных блоков увидите "data_preprocessing" и "to_gpu_async".

Чеклист: 7 самых частых data transfer проблем

Вот что искать в отчетах (и как исправлять):

Проблема Как обнаружить Решение
GIL contention в DataLoader Nsight: worker threads часто в состоянии "Wait" Использовать multiprocessing с spawn (не fork)
Медленный HtoD transfer Nsight: длинные синие memcpy блоки Включить pin_memory=True в DataLoader
CPU-bound preprocessing PyTorch Profiler: долгий "__getitem__" Вынести в отдельный процесс или использовать DALI
Синхронные cuda() вызовы Nsight: разрывы между CPU и GPU работой Использовать non_blocking=True + torch.cuda.Stream
Неоптимальный batch size PCIe utilization < 70% при передаче Увеличить batch или использовать gradient accumulation
Memory fragmentation PyTorch Profiler: growing GPU memory Использовать TraceML для отслеживания утечек
Конфликт за системную память Nsight: high context switch rate Ограничить num_workers или использовать cgroups

Когда что использовать: decision tree

Не знаете, с чего начать? Вот алгоритм:

  1. GPU utilization < 50%? → Берите Nsight Systems сразу. Проблема системная.
  2. Хотите быстро проверить конкретную модель? → PyTorch Profiler на 20 итерациях.
  3. Работаете с кастомными CUDA ядрами? → Обязательно Nsight. Кастомные ядра требуют низкоуровневого анализа.
  4. Отлаживаете distributed training? → Nsight с trace=mpi,nccl.
  5. Просто проверяете, нет ли явных ошибок? → PyTorch Profiler хватит.

Ошибки, которые все совершают (и вы тоже)

Ошибка 1: Профилирование на слишком маленьком dataset. DataLoader ведет себя иначе на первом эпохе (кеширование) и на последующих.

Решение: профилируйте минимум 100-200 итераций. Или используйте --steps 200 в nsys.

Ошибка 2: Запуск профилирования в debug mode. PyTorch в debug режиме добавляет проверки, которые замедляют все в 10 раз.

Решение: убедитесь, что torch.__version__ не заканчивается на +cpu или +debug.

Ошибка 3: Игнорирование thermal throttling. GPU на 84°C работает медленнее, чем на 70°C.

Решение: смотрите GPU Temperature в Nsight Metrics. Если выше 80°C - проблема не в софте, а в охлаждении.

Производительность в продакшене: что меняется

В development среде все работает. В продакшене - падает. Почему?

Потому что:

  • На продакшене другие ограничения памяти (контейнеры, cgroups)
  • Другие версии драйверов CUDA
  • Конкуренция за ресурсы с другими процессами
  • Сетевые задержки при чтении данных из удаленного хранилища

Nsight Systems видит это. PyTorch Profiler - нет.

Особенно критично для инференса с TensorRT-LLM, где каждый миллисекунд на счету.

Будущее: что ждет профайлеры в 2024-2025

Nsight Systems становится тяжелее. Требует больше памяти. Но и дает больше данных.

PyTorch Profiler движется к интеграции с фреймворками вроде AETHER-X для кросс-платформенного профилирования.

Мой прогноз: через год мы увидим:

  1. Автоматические рекомендации по оптимизации на основе ML анализа профилей
  2. Интеграцию профилирования данных и модели в единую timeline
  3. Поддержку NPU профилирования наравне с GPU
  4. Real-time profiling в продакшене без overhead

А пока - берите Nsight для серьезной работы. PyTorch Profiler - для быстрых проверок.

И помните: простаивающий GPU - это не просто потеря производительности. Это сожженные деньги. Ваши деньги.

💡
Совет напоследок: настройте автоматическое профилирование в CI/CD. Запускайте nsys на каждом значимом коммите. Сравнивайте отчеты. Так вы поймаете регрессию производительности до того, как она попадет в продакшен.