Files
gx 604cffb5e5 spike(phase0): minimal CUDA IPC ping-pong producer/consumer
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).
2026-05-14 21:20:39 +01:00

3.7 KiB
Raw Permalink Blame History

Phase 0 — CUDA IPC ping-pong spike

PoC для измерения latency / throughput / multi-consumer behavior без FFmpeg / Frigate / сложности. Чистый CUDA IPC между двумя процессами.

Что проверяет

  1. End-to-end latency: producer → write CUDA frame → consumer reads → ACK.
  2. Throughput: сколько FullHD-frames/sec можно протолкнуть.
  3. Multi-consumer: 1 producer × N consumers (zero-copy для каждого).
  4. Cross-container: producer и consumer в разных Docker-контейнерах.
  5. Crash recovery: kill consumer / producer → reconnect.
  6. 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.