4862247fe2
Заменяет 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>
3.0 KiB
3.0 KiB
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).
Сборка
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"
Запуск теста
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