PoC для validation концепта перед инвестированием в Phase 1. Структура: - tools/spike/common.h — типы SharedHeader / SlotDescriptor / NV12 meta - tools/spike/pingpong_producer.cu — аллоцирует CUDA pool, экспортирует IPC handles в /dev/shm/cuframes-spike-<key>, имитирует publish frames с monotonic pattern - tools/spike/pingpong_consumer.cu — открывает handles, читает frames, verify содержимого (no torn frames), измеряет latency, печатает summary - tools/spike/CMakeLists.txt — sm_75/86/89/90/120 для RTX 5090 - tools/spike/bench.sh — basic / multi-consumer / stress scenarios - tools/spike/README.md — what / how / acceptance Намеренные упрощения PoC (не идём в Phase 1 пока без validation): - 2-slot ring (Phase 1 будет N) - POSIX shared memory + atomic seq (без Unix socket handshake) - cudaStreamSynchronize sync (Phase 0 spike проверит будет ли достаточно; альтернатива cudaIpcEventHandle_t — отложена) - NV12 hardcoded (других форматов в Phase 1) - Drop-oldest backpressure (без ACK protocol) Acceptance Phase 0: - p99 latency на RTX 5090 для FullHD < 5 ms - throughput ≥ 1 GB/s - multi-consumer (3) с сопоставимой latency - cross-container работает - 1-hour stress без VRAM/RAM leak Если acceptance fail → дизайн пересмотр (sync через CUDA IPC events).
3.7 KiB
Phase 0 — CUDA IPC ping-pong spike
PoC для измерения latency / throughput / multi-consumer behavior без FFmpeg / Frigate / сложности. Чистый CUDA IPC между двумя процессами.
Что проверяет
- End-to-end latency: producer → write CUDA frame → consumer reads → ACK.
- Throughput: сколько FullHD-frames/sec можно протолкнуть.
- Multi-consumer: 1 producer × N consumers (zero-copy для каждого).
- Cross-container: producer и consumer в разных Docker-контейнерах.
- Crash recovery: kill consumer / producer → reconnect.
- Memory leak: 24-hour run без VRAM-роста.
Структура
tools/spike/
├── README.md (этот файл)
├── CMakeLists.txt стандартный CMake target
├── common.h shared structs/constants
├── pingpong_producer.cu producer-процесс
├── pingpong_consumer.cu consumer-процесс
└── bench.sh скрипт-обвязка с измерениями
Сборка (внутри dev-контейнера)
docker compose -f docker/docker-compose.dev.yml exec dev bash
# Внутри:
cd /workspace
cmake -B build -S tools/spike -G Ninja
cmake --build build
Артефакты: build/pingpong_producer, build/pingpong_consumer.
Запуск (single-host single-container, базовый случай)
Терминал 1 (producer — пишет FullHD-frames пока не нажмёшь Ctrl-C):
docker compose -f docker/docker-compose.dev.yml exec dev \
./build/pingpong_producer --key cam_test --width 1920 --height 1080 --fps 30
Терминал 2 (consumer — читает и логирует latency):
docker compose -f docker/docker-compose.dev.yml exec dev \
./build/pingpong_consumer --key cam_test --count 1000
После 1000 кадров consumer печатает summary:
=== cuframes spike summary ===
frames received: 1000
duration: 33.34 s
fps: 30.00
latency mean: 0.42 ms
latency p50: 0.39 ms
latency p99: 0.91 ms
latency max: 3.12 ms
producer→consumer: zero-copy ✓
Запуск (cross-container — Phase 0 critical test)
См. bench.sh — поднимает producer в одном контейнере, consumer в другом,
оба используют ipc: shareable namespace.
Acceptance criteria для Phase 0
- Базовый ping-pong работает (1×1)
- Multi-consumer (3 consumers, latency сопоставимая)
- Cross-container (producer container A → consumer container B)
- 1-hour stress без VRAM/RAM leak
- Замерено: p99 latency на RTX 5090 для FullHD-frame
- Документ
docs/benchmarks-phase0.mdс numbers
Если latency p99 > 5 ms или throughput < 1 GB/s → остановиться и
переосмыслить дизайн (возможно CUDA IPC sync через cudaIpcEventHandle_t
вместо cudaStreamSynchronize).
Что не делает spike
- Не использует FFmpeg (это Phase 2)
- Не имеет ring buffer (это Phase 1; spike использует двойной буфер)
- Не использует Unix sockets для handshake (handle передаётся через
файл
/tmp/cuframes-spike-<key>.handle) - Не делает proper backpressure (drop-oldest hardcoded)
Spike нарочно минималистичен — единственная цель замерить numbers и провалидировать concept перед инвестированием в Phase 1.