Files
cuframes/spike/vmm_fd_pingpong/README.md
T
gx 4862247fe2
build / cmake build (CUDA 12.4, Ubuntu 22.04) (push) Successful in 1m46s
build / ffmpeg filter patch (out-of-tree) (push) Failing after 1m30s
v0.4: VMM + POSIX FD — namespace decoupling (no pid share required)
Заменяет cudaMalloc + cudaIpcGetMemHandle на cuMemCreate (VMM) +
cuMemExportToShareableHandle(POSIX_FILE_DESCRIPTOR). FDs передаются consumer'у
через sendmsg(SCM_RIGHTS) в handshake. Frigate (s6-overlay не даёт share PID)
и любой другой consumer работают БЕЗ pid namespace share — только volume mount
unix socket'a /run/cuframes и IPC share для /dev/shm header.

Sync: cudaEventRecord+IPC events → cuStreamSynchronize в do_publish.
Producer ждёт ~1 ms что stream flush'нулся, потом atomic_store(seq).
Consumer читает seq через memory_order_acquire и копирует DtoD без
event wait — HW coherence гарантирована на одном GPU.

ABI break (согласован с user'ом):
  - magic 0xCC7C1DCC → 0xCC7C1DCE (старые consumers fail cleanly)
  - protocol V3 → V4
  - libcuframes.so.0 SOVERSION остаётся, но .so.0.3.0 → .so.0.4.0
  - EXTERNAL ownership убран (VMM требует cuMemCreate-allocated memory,
    нельзя export'нуть произвольный cudaMalloc-pointer как POSIX FD)
  - cuframes-rtsp-source переведён на LIBRARY mode + один D2D memcpy
    в acquire'нутый slot (overhead малый — публишер всё равно делал такой
    D2D из FFmpeg hwframe pool в EXTERNAL pool раньше)

Размер: granularity 2 MB на 5090 → NV12 1920×1080 (~3.1 MB) округляется до
4 MB, +1 MB на slot × 16 × 4 камеры = +64 MB VRAM. Терпимо.

Packet ring (cuframes_packets://) НЕ затронут — отдельный SHM с своим
magic, работает как раньше.

PoC + smoke в spike/:
  - vmm_fd_pingpong/ — minimal cuMemCreate+FD round-trip
  - smoke_v04/ — full publisher+subscriber, 100/100 frames без pid share

Base image: Dockerfile.runtime → CUDA 12.4 (был 13.0). Matching prod
pipeline + Frigate base, иначе libcudart conflict при load.

Compose stack (localhost-infra repo) — параллельный commit:
  - убран pid: container:cuframes-pub-parking из subscribers
  - image теги: gx/cuframes:0.4, gx/cuda-grid-pipeline:phase8,
    gx/frigate:cuframes-v0.4

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 20:13:31 +01:00

70 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# vmm_fd_pingpong — spike для cuframes v0.4
Проверка: можно ли заменить CUDA IPC mem handles на VMM (cuMemCreate)
+ POSIX FD export, чтобы убрать требование shared pid/ipc namespaces
между producer и consumer контейнерами.
## Результат: ✅ работает
Запуск 2 контейнеров без shared pid/ipc, только volume mount для
unix-сокета:
```
producer: granularity=2097152
producer: alloc size=16777216
producer: exported fd=37 for handle
producer: listening on /run/spike/pingpong.sock, awaiting consumer...
consumer: connected to producer
consumer: recv fd=38 size=16777216 magic=0xa7
consumer: imported handle OK
consumer: mapped + access OK
consumer: verify mismatch=0/1048576 → ACK=O
consumer: done (OK)
```
## Ключевые наблюдения
- **Granularity на 5090 = 2 MB**. 1920×1080 NV12 (~3.1 MB) округлится до 4 MB.
16 slots × 4 камеры × +1 MB = +64 MB VRAM поверх текущих cuda IPC аллокаций.
- **FD передаётся через `sendmsg(SCM_RIGHTS)`** — kernel прокидывает реальный FD
в receiver namespace, переименовывая в свободный номер. Volume mount unix
socket'а — единственное требование (`/run/cuframes` уже монтируется как shared).
- **`cuMemImportFromShareableHandle`** принимает FD как `(void *)(uintptr_t)fd`.
- **Доступ на consumer side требует `cuMemSetAccess` с правильным `CUmemLocation`** —
device id из своего `cuDeviceGet`, не наследуется от producer.
## Замена events (упрощение этапа C)
CUDA events для IPC не имеют POSIX FD path. Внедрять external semaphores
(OPAQUE_FD) — отдельный API, другая sigal/wait семантика. **Вместо этого:**
producer вызывает `cuStreamSynchronize(stream)` ПЕРЕД `atomic_store(seq)` в
`do_publish`. Consumer тогда просто читает seq и копирует DtoD — без event wait.
Overhead: ~1 ms на publish × 25 fps = 2.5% CPU time producer'а. Memory
coherence гарантирована (один GPU, hardware ensures writes visible после
stream sync).
## Сборка
```bash
docker run --rm -v $PWD:/work -w /work nvidia/cuda:12.4.1-devel-ubuntu22.04 \
bash -c "apt-get install -y build-essential && make"
```
## Запуск теста
```bash
sudo mkdir -p /var/run/spike-pingpong && sudo chmod 777 /var/run/spike-pingpong
docker run -d --name spike-prod --runtime=nvidia --gpus all \
-v $PWD:/work -v /var/run/spike-pingpong:/run/spike \
nvidia/cuda:12.4.1-base-ubuntu22.04 /work/producer
docker run --rm --name spike-cons --runtime=nvidia --gpus all \
-v $PWD:/work -v /var/run/spike-pingpong:/run/spike \
nvidia/cuda:12.4.1-base-ubuntu22.04 /work/consumer
docker logs spike-prod && docker rm -f spike-prod
```