// Phase 0 spike — общие типы / константы для producer и consumer. // // NB: реальный protocol будет в libcuframes (Phase 1). Здесь — минимум // для PoC measurement. #pragma once #include #include #include #include namespace cuframes_spike { // Slot — 1 frame в shared VRAM. Producer пишет, consumer читает. // Используем double-buffering (2 slot'а) — пока consumer читает slot A, // producer пишет в slot B. Поможет уменьшить contention в PoC. constexpr int RING_SIZE = 2; // Format hardcoded для PoC: NV12 (как выдаёт NVDEC по умолчанию). // Y plane + UV plane (subsampled 2x2). struct FrameMeta { int32_t width; int32_t height; int32_t pitch_y; // строка Y, выровнен на 256 для CUDA int32_t pitch_uv; // строка UV int32_t format; // 0 = NV12 }; // Descriptor одного slot'а. Хранится в /tmp/cuframes-spike-.handle // — это POSIX shared memory. struct SlotDescriptor { cudaIpcMemHandle_t handle; // 64 байта от NVIDIA для IPC uint64_t producer_seq; // обновляется атомарно при publish uint64_t consumer_ack_count; // сколько consumers подтвердили int64_t pts_ns; // timestamp когда producer публикнул }; // Header shared memory file. struct SharedHeader { uint32_t magic; // 0xCC7C1DCC ("CUFRAMES C0") uint32_t version; FrameMeta meta; SlotDescriptor slots[RING_SIZE]; uint64_t global_seq; // монотонная последовательность producer }; constexpr uint32_t CUFRAMES_SPIKE_MAGIC = 0xCC7C1DCCu; constexpr uint32_t CUFRAMES_SPIKE_VERSION = 1; // Helper: error check + abort. #define CHECK_CUDA(call) do { \ cudaError_t _err = (call); \ if (_err != cudaSuccess) { \ fprintf(stderr, "CUDA error at %s:%d: %s\n", \ __FILE__, __LINE__, cudaGetErrorString(_err)); \ std::exit(1); \ } \ } while (0) // Получить timestamp в наносекундах (для latency-замеров). static inline int64_t now_ns() { timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return static_cast(ts.tv_sec) * 1000000000LL + ts.tv_nsec; } } // namespace cuframes_spike