Prism Guide: Multi-LLM Serving via GPU Memory Ballooning

Operating modern generative artificial intelligence infrastructure has become an exercise in economic survival. Cloud inference providers—such as Hyperbolic, Novita AI, Alibaba Cloud, and Hugging Face—must maintain continuous online availability for hundreds of heterogeneous foundation models and specialized fine-tuned checkpoints. Simultaneously, token pricing has plunged rapidly, turning what was once a high-margin service into a razor-thin operational business.
In production environments, the overwhelming operational expense does not stem from exotic hardware or optical interconnects, but from chronic GPU under-utilization. To strictly honor customer Service Level Objectives (SLOs)—specifically Time-to-First-Token (TTFT) and Time-Per-Output-Token (TPOT)—cloud providers routinely provision dedicated GPU worker groups for individual models. For high-volume base models like LLaMA-3.3-70B, dedicated instances achieve respectable duty cycles. However, the vast majority of deployed models represent specialized or long-tail endpoints: domain-adapted reasoning agents, code verification tools, multilingual translators, and task-specific adapters.
Empirical analyses of multi-month production traces across major inference providers demonstrate that real-world model duty cycles frequently collapse below 30%. Long-tail models sit idle for more than 70% of the day. Yet, cloud providers cannot simply shut these instances down without inducing catastrophic multi-second cold-start delays that violate enterprise latency guarantees.
Presented at the prestigious 20th USENIX Symposium on Operating Systems Design and Implementation (OSDI 2026) by a joint research consortium from UCLA, UC Berkeley, Harvard, CMU, Stanford, Rice University, ByteDance, and Alibaba Cloud, Prism introduces a transformative architectural paradigm: GPU Memory Ballooning for Multi-LLM Serving. By taking inspiration from virtual machine hypervisor memory management and introducing the open-source kvcached balloon driver, Prism unifies spatial and temporal GPU sharing into an elastic, demand-aware co-serving substrate. Deployed across clusters exceeding 10,000 GPUs, Prism achieves up to 3.3x higher TTFT SLO attainment, 2x higher TPOT SLO attainment, and over 2x infrastructure cost reduction.
In this architectural guide, we dissect the systemic failure modes of conventional GPU sharing, unpack the virtual memory mechanics of kvcached, step through production deployment on SGLang, evaluate performance against SOTA systems, and explore cluster-scale scheduling strategies for enterprise AI infrastructure.
Problem: The Multi-LLM Memory Wall and Spatial-Temporal Dilemma
To understand why multi-LLM serving requires a clean-sheet memory management architecture, systems engineers must examine the structural realities of multi-tenant model workloads and the fatal limitations of existing GPU sharing techniques.
Production Trace Analysis: Shifting Bursty Groups and Request Volatility
Prior academic research on LLM serving predominantly evaluated single-model systems under synthetic, idealized Poisson or Gamma arrival distributions. To ground systems design in empirical reality, the authors of Prism analyzed multi-tenant production traces from four major cloud environments: Hyperbolic (24 models, 4 months), Novita AI (16 models, 1 month), Chatbot Arena Battle (129 models, 16 months), and Chatbot Arena Chat (84 models, 11 days), spanning models from 1B to 70B parameters.
+-----------------------------------------------------------------------------+
| MULTI-TENANT LLM PRODUCTION WORKLOAD PHENOMENOLOGY |
+-----------------------------------------------------------------------------+
| |
| 1. MODEL LEVEL: SHIFTING BURSTY GROUPS |
| - Models receive short, intense bursts separated by long idle gaps. |
| - Average concurrent active model ratio: Only 23% to 50%! |
| - Active working set changes rapidly: 54 to 766 model switches/hour. |
| - Heterogeneous roles: Central planner LLMs sustain long activity, while|
| specialized sub-agent models trigger in sharp, intermittent bursts. |
| |
| 2. REQUEST LEVEL: DYNAMIC VOLATILITY & PATTERN SHIFTS |
| - Coefficient of variation (CV) of arrival rates routinely exceeds 1.0. |
| - Interleaved multi-model demand abruptly shifts to single-model bursts |
| within 60-second windows without predictable statistical precursors. |
| |
+-----------------------------------------------------------------------------+ This workload analysis revealed two defining operational patterns:
- Vertical Bursty Groups: At any single point in time, only a transient subset of deployed models—a “bursty group”—is actively processing requests. Across the evaluated traces, between 50% and 77% of provisioned models are completely idle. Yet, this active subset is not static; it changes between 54 and 766 times per hour as compound AI workflows, human user sessions, and automated agent loops activate different tools.
- Horizontal Activation Heterogeneity: Large general-purpose planner models sustain continuous activity, while small, specialized sub-models (such as mathematical verifiers or text formatters) activate sporadically.
The Breakdown of Pure Space Sharing
Faced with this workload profile, infrastructure operators typically evaluate two standard GPU-sharing regimes: Space Sharing (colocating multiple models concurrently on the same physical GPU) or Time Sharing (swapping models in and out of GPU High-Bandwidth Memory). Both approaches fail under production traffic:
+-----------------------------------------------------------------------------+
| THE DUAL FAILURE OF CONVENTIONAL SHARING |
+-----------------------------------------------------------------------------+
| |
| A. PURE SPACE SHARING (Static Slicing / MPS / MuxServe): |
| ┌────────────────────────────┬────────────────────────────┐ |
| │ Model A (Surging Burst!) │ Model B (Completely Idle!) │ |
| │ KV Cache: 100% SATURATED! │ KV Cache: 0% Utilized │ |
| │ Weights: Locked (40GB) │ Weights: Locked (40GB) │ |
| └────────────────────────────┴────────────────────────────┘ |
| Consequence: Model A drops packets / violates SLOs due to artificial |
| memory starvation, while adjacent GPU memory sits 100% wasted! |
| |
| B. PURE TIME SHARING (Model Swapping / QLM / ServerlessLLM): |
| Request Stream: Model A ──► Model B ──► Model A ──► Model B |
| GPU State: [Swap In A] ──► [Swap In B] ──► [Swap In A] |
| Consequence: Severe Model Thrashing! Swapping 14B-70B weights over PCIe |
| takes 1.5s - 5.0s, monopolizing bandwidth and causing 80%+ SLO misses! |
| |
+-----------------------------------------------------------------------------+ Under pure space sharing (such as static memory partitioning via NVIDIA MIG or MuxServe), the serving framework statically carves physical GPU memory between colocated models. While this prevents swapping overhead during steady-state execution, it creates artificial resource scarcity.
In production traces where models are idle for over 70% of the time, static memory partitioning leaves more than 50% of GPU High-Bandwidth Memory (HBM) completely unused. When an active model experiences a sudden traffic burst, its statically allocated Key-Value (KV) cache pool exhausts immediately. Incoming requests must queue or drop, causing massive TTFT spikes—even though vast gigabytes of reserved KV buffer sit idle inside the adjacent inactive model’s partition!
The Breakdown of Pure Time Sharing
Conversely, pure time sharing (such as QLM or ServerlessLLM) unloads inactive models to host CPU DRAM, loading weights only when requests arrive.
While this eliminates memory fragmentation during prolonged idle periods, it suffers from catastrophic model thrashing during volatile, interleaved traffic. When user interactions alternate rapidly between two or more models, the serving cluster spends more wall-clock time executing PCIe weight transfers and engine re-initializations than computing inference tokens. Queues explode, and Time-to-First-Token latencies climb into multi-second delays that violate enterprise SLAs.
High-throughput enterprise workloads—whether orchestrating complex multi-agent reasoning chains or executing distributed web scraping workflows—demand an infrastructure layer that bridges this divide. The industry required an elastic systems mechanism capable of fluidly shifting between spatial and temporal sharing at runtime.
Solution: GPU Memory Ballooning and Elastic Virtual Paging
To resolve the spatial-temporal sharing dilemma, the architects of Prism established a foundational insight: GPU memory is the single unifying bottleneck in multi-LLM serving, and spatial vs. temporal sharing merely govern different allocations of that exact same physical memory.
+-----------------------------------------------------------------------------+
| THE UNIFYING MEMORY-CENTRIC INSIGHT |
+-----------------------------------------------------------------------------+
| |
| TIME-SHARING OBJECTIVE: SPACE-SHARING OBJECTIVE: |
| "How to efficiently allocate physical "How to scale KV-cache |
| GPU memory for dynamic model weights?" capacity between models?" |
| │ │ |
| └───────────────┬─────────────────────┘ |
| ▼ |
| UNIFIED VIA ELASTIC GPU MEMORY BALLOONING |
| |
| - Reclaim unused KV-cache from low-rate models to scale up active models |
| - Reclaim memory from idle models to swap in newly active model weights |
| - Execute bidirectional resizing transparently at 2MB page granularity |
| |
+-----------------------------------------------------------------------------+ The Concept of GPU Memory Ballooning
In operating systems and hypervisor virtualization (such as VMware ESXi or Linux KVM), memory ballooning is a classic technique used to dynamically adjust the memory allocation of guest virtual machines without restarting them. A pseudo-device driver (the balloon driver) inside the guest VM allocates memory from the guest OS when instructed by the hypervisor, pinning those physical pages so the hypervisor can safely reassign them to another VM under memory pressure. When the guest VM requires memory again, the balloon deflates, releasing pages back to the guest.
Prism translates this elegant operating system abstraction directly into GPU silicon for multi-LLM co-serving:
- The LLM Balloon Driver (
kvcached): An elastic memory management layer inserted between the LLM serving runtime (e.g., SGLang) and the low-level CUDA driver. - Decoupled Virtual and Physical GPU Addressing: Traditional LLM engines statically allocate their entire KV-cache tensor pool at boot time (e.g., allocating 40GB of contiguous physical memory). In contrast, Prism reserves a massive virtual address space during engine initialization, but allocates and maps physical GPU memory pages on-demand at a fine-grained 2 Megabyte granularity.
- Transparent Inflation and Deflation: When a colocated model sits idle or processes low-token streams,
kvcachedinflates the balloon, unmapping physical 2MB pages from its virtual KV tensor and returning them to a global GPU physical memory pool. When an active model faces an intense burst, the balloon deflates, dynamically binding physical memory pages into its virtual address space in milliseconds—with zero changes to PagedAttention CUDA kernels.
+-----------------------------------------------------------------------------+
| VIRTUAL VS PHYSICAL MEMORY DECOUPLING IN KVCACHED |
+-----------------------------------------------------------------------------+
| |
| MODEL A VIRTUAL KV POOL (Reserved: 40GB Virtual Address Space) |
| [ Page 0 ][ Page 1 ][ Page 2 ][ Page 3 ][ Page 4 ][ Page 5 ] ... |
| │ │ │ │ |
| ▼ ▼ ▼ ▼ |
| ┌───────────────────────────────────────────────────────────────────────┐ |
| │ GPU PHYSICAL MEMORY POOL (Managed by kvcached via CUDA VMM) │ |
| │ [2MB Phys] [2MB Phys] [2MB Phys] [2MB Phys] [2MB Free] [2MB Free] │ |
| └───────────────────────────────────────────────────────────────────────┘ |
| ▲ ▲ |
| │ │ |
| MODEL B VIRTUAL KV POOL (Reserved: 40GB Virtual) │ │ |
| [ Page 0 ][ Page 1 ][ Page 2 ][ Page 3 ] ... ──────┴──────────┘ |
| |
+-----------------------------------------------------------------------------+ Four Structural Architectural Invariants
To make GPU memory ballooning practical for production serving, Prism enforces four strict system invariants:
- R1: Fast Reallocation Between Weights and KV-Cache: Released model weight memory can be repurposed immediately as KV-cache blocks for running models within sub-second timescales.
- R2: Universal Architecture Compatibility: Different foundation models possess radically different layer counts ($L$), attention heads ($H$), and head dimensions ($D$). Prism operates beneath tensor layouts at raw 2MB physical page boundaries, making memory fungible across diverse model families (e.g., LLaMA, Qwen, DeepSeek, Mistral).
- R3: Minimal Fragmentation: By standardizing allocations to uniform 2MB physical tiles, Prism completely avoids external memory fragmentation and eliminates complex secondary indexing layers.
- R4: Zero Kernel Disruption: Existing high-performance FlashAttention and PagedAttention kernels expect contiguous virtual pointers. By manipulating the virtual-to-physical page table via CUDA Virtual Memory Management (VMM) APIs, the underlying attention kernels execute without modification.
For applications requiring continuous, high-volume data streams—such as live real-time data fetching pipelines—Prism guarantees that memory expands and contracts dynamically without stalling active inference streams.
Architecture: The kvcached Driver and Two-Tier Control Plane
The Prism framework is structured as a decoupled, two-tier architecture: a high-performance GPU Data Plane governed by the kvcached balloon driver, and an intelligent Memory-Centric Control Plane comprising a Global Placement Scheduler and a Local Request Arbitrator.
+-----------------------------------------------------------------------------+
| PRISM SYSTEM ARCHITECTURE OVERVIEW |
+-----------------------------------------------------------------------------+
| |
| Incoming Inference Requests (HTTP / gRPC via Redis Request Queue) |
| │ |
| ┌─────▼───────────────────────────────────────────────────────────────┐ |
| │ 1. GLOBAL MEMORY-CENTRIC SCHEDULER │ |
| │ - Tracks global GPU cluster memory headroom and model states │ |
| │ - Computes Demand-Complementary Placement via KVPR Optimization │ |
| │ - Issues Model Eviction / Activation / Migration Commands │ |
| └─────┬───────────────────────────────────────────────────────────────┘ |
| │ (ZeroMQ Control Bus) |
| ├─────────────────────────────────┐ |
| ▼ ▼ |
| ┌───────────────────────────────┐ ┌───────────────────────────────────┐ |
| │ 2. LOCAL REQUEST ARBITRATOR │ │ 2. LOCAL REQUEST ARBITRATOR │ |
| │ (GPU Group 0: Ranks 0..1) │ │ (GPU Group 1: Ranks 2..3) │ |
| │ - Slack-Aware Queue Sched │ │ - Slack-Aware Queue Sched │ |
| │ - Moore-Hodgson Algorithm │ │ - Moore-Hodgson Algorithm │ |
| └─────┬─────────────────────────┘ └─────┬─────────────────────────────┘ |
| │ │ |
| ┌─────▼─────────────────────────┐ ┌─────▼─────────────────────────────┐ |
| │ 3. SGLang SERVING ENGINES │ │ 3. SGLang SERVING ENGINES │ |
| │ Model A (70B) & Model B (8B)│ │ Model C (14B) & Model D (8B) │ |
| └─────┬─────────────────────────┘ └─────┬─────────────────────────────┘ |
| │ │ |
| ┌─────▼─────────────────────────────────▼─────────────────────────────┐ |
| │ 4. kvcached BALLOON DRIVER (CUDA Virtual Memory Management - VMM) │ |
| │ - cuMemAddressReserve / cuMemCreate / cuMemMap / cuMemSetAccess │ |
| │ - 2MB Fine-Grained Physical Page Allocation & Instant Reclamation│ |
| └─────────────────────────────────────────────────────────────────────┘ |
| |
+-----------------------------------------------------------------------------+ The kvcached Driver Microarchitecture
The kvcached balloon driver operates as a shared dynamic library (libkvcached.so) loaded directly into the serving engine process. Built upon low-level CUDA Driver Virtual Memory Management (VMM) APIs, kvcached manages memory across three explicit lifecycles:
- Virtual Address Space Reservation: During engine boot,
kvcachedinvokescuMemAddressReserve()to claim a continuous 64GB–128GB virtual address window for each model’s KV tensor. Crucially, this operation reserves address space in the GPU’s memory management unit (MMU) but allocates zero physical bytes of HBM. - On-Demand Page Backing: As input tokens arrive and KV blocks are allocated by SGLang’s scheduler,
kvcachedchecks whether the target virtual offsets are mapped. If unmapped, it requests physical memory chunks from the GPU driver usingcuMemCreate(), binds them to the virtual addresses viacuMemMap(), and sets read-write permissions withcuMemSetAccess(). - Instant Memory Deflation: When a request completes, or when the global scheduler commands memory reclamation,
kvcachedunmaps physical handles viacuMemUnmap()and destroys physical allocations withcuMemRelease(), immediately freeing physical HBM for other models.
Because memory allocation and mapping occur at the 2MB boundary, mapping latencies remain under 10 to 25 microseconds, making dynamic ballooning effectively invisible to running attention computations.
Global Scheduler: KVPR-Driven Model Placement
To place heterogeneous models across a cluster of GPUs without triggering memory contention, Prism introduces the Key-Value Pressure Ratio (KVPR) metric.
For any model $m_i$ characterized by an average request arrival rate $r_i$, an SLO latency target $s_i$, and physical model weight footprint $w_i$, its SLO-weighted compute demand is defined as $d_i = \frac{r_i}{s_i}$. When a set of models $\mathcal{M}g$ is colocated on a GPU group $g$ with total physical HBM capacity $C$, the shared memory available for KV caching is: $$S_g = C - \sum{m_i \in \mathcal{M}_g} w_i$$
The Key-Value Pressure Ratio for GPU group $g$ is formulated as the ratio of aggregate SLO-weighted demand to remaining shared KV-cache capacity: $$\text{KVPR}(g) = \frac{\sum_{m_i \in \mathcal{M}g} d_i}{S_g} = \frac{\sum{m_i \in \mathcal{M}g} \frac{r_i}{s_i}}{C - \sum{m_i \in \mathcal{M}_g} w_i}$$
+-----------------------------------------------------------------------------+
| KVPR-DRIVEN DEMAND-COMPLEMENTARY PLACEMENT LOGIC |
+-----------------------------------------------------------------------------+
| |
| 1. Sort all deployed models in descending order of demand density (d_i/w_i).|
| |
| 2. For each model m_k: |
| - Candidate Evaluation: Compute prospective KVPR across all GPU groups. |
| - Placement Objective: Assign m_k to the GPU group that minimizes |
| the resulting maximum KVPR: |
| |
| g* = argmin [ (W_before + d_k) / (S_before - w_k) ] |
| |
| 3. Mathematical Guarantee: Bounded by Graham's Multiprocessing Theorem: |
| |
| KVPR_max <= KVPR_OPT * [ 1 + C / (S_gmax - w_k) ] |
| |
+-----------------------------------------------------------------------------+ By balancing models with complementary demand patterns—pairing high-demand, low-weight models with low-demand, high-weight models—the global scheduler prevents any individual GPU from becoming a tail-latency bottleneck.
Local Scheduler: Slack-Aware Request Arbitration
Once models are assigned to a GPU group, incoming requests must be scheduled to prevent short, latency-critical requests from being blocked by heavy, long-context requests.
Prism implements a local request queue based on a generalized variant of the Moore-Hodgson Algorithm for minimizing the number of late jobs:
- Slack Estimation: For each request $r$, Prism computes its remaining latency slack: $$\text{Slack}(r) = a_r + s_r - \text{CurrentTime} - e_r$$ where $a_r$ is the arrival timestamp, $s_r$ is the TTFT SLO target, and $e_r$ is the estimated prefill execution duration ($e_r = \frac{p_r}{c}$, proportional to prompt length $p_r$ and hardware compute throughput $c$).
- Priority-Based Admission: Requests are sorted by earliest deadline. If the scheduler detects that admitting request $r$ causes a downstream deadline violation, it identifies the request with the largest execution time in the active batch ($r_{\max} = \arg\max \frac{p_r’}{c}$), evicting or deferring it to CPU memory to salvage the SLOs of all remaining requests.
Implementation: Integrating kvcached with SGLang and CUDA VMM
Deploying Prism in a production cluster requires integrating kvcached into the core tensor management layer of the serving engine. Below, we examine the low-level C++ CUDA VMM driver implementation and its Python bindings for SGLang.
+-----------------------------------------------------------------------------+
| CUDA VMM BALLOON DRIVER WORKFLOW |
+-----------------------------------------------------------------------------+
| |
| 1. Initialization: |
| cuMemAddressReserve(ptr, 64GB, alignment=2MB, flags=0) |
| |
| 2. Dynamic Expansion (Balloon Deflation): |
| cuMemCreate(memHandle, 2MB, prop={type: POS_PINNED, id: gpu_id}, 0) |
| cuMemMap(ptr + offset, 2MB, 0, memHandle, 0) |
| cuMemSetAccess(ptr + offset, 2MB, desc={flags: READ_WRITE}, count=1) |
| |
| 3. Dynamic Reclamation (Balloon Inflation): |
| cuMemUnmap(ptr + offset, 2MB) |
| cuMemRelease(memHandle) |
| |
+-----------------------------------------------------------------------------+ Step 1: Low-Level CUDA VMM Driver (kvcached_driver.cpp)
The following C++ source demonstrates how kvcached uses the CUDA Driver API to manage physical memory pages beneath an arbitrary PyTorch virtual tensor pointer:
#include <cuda.h>
#include <cuda_runtime.h>
#include <iostream>
#include <stdexcept>
#include <unordered_map>
#include <vector>
#define CHECK_CUDA_DRV(call) \
do { \
CUresult err = call; \
if (err != CUDA_SUCCESS) { \
const char* szErrName = NULL; \
cuGetErrorName(err, &szErrName); \
throw std::runtime_error(std::string("CUDA Driver Error: ") + \
szErrName); \
} \
} while (0)
class KVCacheBalloonDriver {
public:
static const size_t PAGE_SIZE = 2 * 1024 * 1024; // 2MB granularity
KVCacheBalloonDriver(int device_id, size_t max_virtual_bytes)
: device_id_(device_id), max_virtual_bytes_(max_virtual_bytes), base_va_(0) {
CHECK_CUDA_DRV(cuInit(0));
CHECK_CUDA_DRV(cuDeviceGet(&device_, device_id_));
CHECK_CUDA_DRV(cuCtxCreate(&context_, 0, device_));
// Step 1: Reserve virtual address window without backing physical HBM
CHECK_CUDA_DRV(cuMemAddressReserve(&base_va_, max_virtual_bytes_, PAGE_SIZE, 0, 0));
std::cout << "[kvcached] Reserved " << (max_virtual_bytes_ >> 30)
<< " GB Virtual Window at 0x" << std::hex << base_va_ << std::dec << std::endl;
}
~KVCacheBalloonDriver() {
for (auto& pair : mapped_pages_) {
cuMemUnmap(pair.first, PAGE_SIZE);
cuMemRelease(pair.second);
}
if (base_va_) {
cuMemAddressFree(base_va_, max_virtual_bytes_);
}
cuCtxDestroy(context_);
}
CUdeviceptr get_base_address() const { return base_va_; }
void allocate_and_map_page(size_t page_index) {
CUdeviceptr target_va = base_va_ + (page_index * PAGE_SIZE);
if (mapped_pages_.find(target_va) != mapped_pages_.end()) {
return; // Already mapped
}
// Configure physical memory allocation request
CUmemAllocationProp prop = {};
prop.type = CU_MEM_ALLOCATION_TYPE_PINNED;
prop.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
prop.location.id = device_id_;
CUmemGenericAllocationHandle mem_handle;
CHECK_CUDA_DRV(cuMemCreate(&mem_handle, PAGE_SIZE, &prop, 0));
CHECK_CUDA_DRV(cuMemMap(target_va, PAGE_SIZE, 0, mem_handle, 0));
// Enable Read/Write access on the target GPU
CUmemAccessDesc access_desc = {};
access_desc.location.type = CU_MEM_LOCATION_TYPE_DEVICE;
access_desc.location.id = device_id_;
access_desc.flags = CU_MEM_ACCESS_FLAGS_PROT_READWRITE;
CHECK_CUDA_DRV(cuMemSetAccess(target_va, PAGE_SIZE, &access_desc, 1));
mapped_pages_[target_va] = mem_handle;
}
void reclaim_and_unmap_page(size_t page_index) {
CUdeviceptr target_va = base_va_ + (page_index * PAGE_SIZE);
auto it = mapped_pages_.find(target_va) != mapped_pages_.end() ? mapped_pages_.find(target_va) : mapped_pages_.end();
if (it == mapped_pages_.end()) {
return; // Not mapped
}
CHECK_CUDA_DRV(cuMemUnmap(target_va, PAGE_SIZE));
CHECK_CUDA_DRV(cuMemRelease(it->second));
mapped_pages_.erase(it);
}
size_t get_physical_memory_usage() const {
return mapped_pages_.size() * PAGE_SIZE;
}
private:
int device_id_;
CUdevice device_;
CUcontext context_;
size_t max_virtual_bytes_;
CUdeviceptr base_va_;
std::unordered_map<CUdeviceptr, CUmemGenericAllocationHandle> mapped_pages_;
}; Step 2: Python SGLang Integration Hook (prism_sglang_manager.py)
In SGLang, the KV-cache manager (KVCachePool) interacts with the balloon driver through lightweight Python bindings. The following implementation demonstrates dynamic page provisioning during token batch generation:
#!/usr/bin/env python3
# Prism Elastic Memory Manager Hook for SGLang Serving Engine
# Dynamically manages 2MB physical pages for PagedAttention token blocks
import torch
import ctypes
from typing import Dict, Set
class PrismKVCachePool:
PAGE_SIZE_BYTES = 2 * 1024 * 1024 # 2MB
def __init__(self, device_id: int, max_tokens: int, head_dim: int, num_heads: int, num_layers: int):
self.device_id = device_id
self.max_tokens = max_tokens
self.token_stride_bytes = head_dim * num_heads * 2 * 2 # FP16 (K+V)
self.tokens_per_page = self.PAGE_SIZE_BYTES // self.token_stride_bytes
self.total_pages = (max_tokens + self.tokens_per_page - 1) // self.tokens_per_page
self.max_virtual_bytes = self.total_pages * self.PAGE_SIZE_BYTES
print(f"[*] Initializing Prism Elastic Pool: {self.total_pages} Virtual Pages ({self.max_virtual_bytes / (1<<30):.2f} GB)")
# Load C++ kvcached runtime driver
self.allocated_pages: Set[int] = set()
def ensure_capacity_for_tokens(self, active_token_count: int):
required_pages = (active_token_count + self.tokens_per_page - 1) // self.tokens_per_page
if required_pages > len(self.allocated_pages):
for page_idx in range(len(self.allocated_pages), required_pages):
self.allocated_pages.add(page_idx)
print(f"[kvcached] Deflated Balloon: Provisioned {required_pages - len(self.allocated_pages)} pages. "
f"Active HBM: {len(self.allocated_pages) * 2} MB")
def release_unused_pages(self, target_active_tokens: int):
retained_pages = (target_active_tokens + self.tokens_per_page - 1) // self.tokens_per_page
pages_to_reclaim = [idx for idx in self.allocated_pages if idx >= retained_pages]
for idx in pages_to_reclaim:
self.allocated_pages.remove(idx)
if pages_to_reclaim:
print(f"[kvcached] Inflated Balloon: Reclaimed {len(pages_to_reclaim)} pages. "
f"Current HBM Footprint: {len(self.allocated_pages) * 2} MB")
if __name__ == "__main__":
pool = PrismKVCachePool(device_id=0, max_tokens=32768, head_dim=128, num_heads=32, num_layers=32)
pool.ensure_capacity_for_tokens(active_token_count=8192)
pool.release_unused_pages(target_active_tokens=2048) Step 3: Fast Model Activation Pipeline
When a model is completely idle, its weights are offloaded to host CPU DRAM. To eliminate cold-start lag when new requests arrive, Prism implements a three-stage accelerated activation pipeline:
- Pinned Host Staging: Model weights in CPU memory are stored in pinned (page-locked) host memory pools, enabling maximum PCIe Gen5 line-rate saturation (up to 64 GB/s per x16 slot).
- Asynchronous Pipelined Transfer: Weight loading is decomposed into layer chunks. As Layer 0 is copied over PCIe, the GPU initializes Layer 0 CUDA Graph executors concurrently.
- Fast Startup Metrics: As evaluated on NVIDIA H100 systems, small models (1B–8B) activate from host memory in under 0.7 seconds, 14B models in 1.3 seconds, and large 70B models in 1.5 seconds—completing well within multi-second conversational TTFT budgets.
Comparison: Prism vs MuxServe vs QLM vs ServerlessLLM
To contextualize Prism’s systems contributions, we compare its architectural attributes against leading multi-LLM serving frameworks: MuxServe (spatial sharing), QLM (temporal queue-based sharing), ServerlessLLM (checkpoint-accelerated serverless sharing), and vLLM / SGLang baseline (dedicated instances).
+----------------------------------------------------------------------------------------------------+
| MULTI-LLM SERVING ARCHITECTURE COMPARISON |
+--------------------------+-----------------------+------------------------+------------------------+
| Feature / Metric | Prism (OSDI 2026) | MuxServe (SOSP 2024) | QLM (SoCC 2024) |
+--------------------------+-----------------------+------------------------+------------------------+
| Primary Sharing Mode | Unified Elastic S/T | Pure Spatial (Static) | Pure Temporal (Swap) |
| Memory Allocation Scheme | CUDA VMM 2MB Balloon | Static Slice Partition | Full Weight Swapping |
| Kernel Modifications | Zero (PagedAttention) | Substantial (New Kern) | Zero |
| Tail-Latency TTFT SLO | 3.3x Higher Attain. | Drops on Bursts | Severe Thrashing |
| P95 TPOT Performance | 18.82 ms (H100) | 21.21 ms (H100) | Degrades under Batch |
| Model Radix Capacity | 58+ Models on 16 GPUs | Limited by Static HBM | High Swap Overhead |
| Cluster Placement Logic | KVPR Demand-Aware | Greedy / Fixed Map | First-Available Device |
| In-flight Preemption | Slack-Aware (Moore-H) | Static Queue Drop | Preempt on Swap |
| Production Deployment | 10K+ GPUs (Novita/Hyp)| Research Prototype | Research Prototype |
+--------------------------+-----------------------+------------------------+------------------------+ Key Performance Trade-offs
- SLO Attainment Under Bursting: In the presence of unpredictable traffic surges, MuxServe’s static partitions cause active models to run out of KV memory, driving TTFT SLO violations to over 40%. QLM swaps weights so aggressively between alternating models that engine restarts consume more time than inference. Prism continuously harvests unused memory from idle colocated models, maintaining 99% TTFT and TPOT attainment.
- Hardware Efficiency and GPU Counts: When evaluated across 58 real-world models from the Chatbot Arena and Hyperbolic traces, Prism satisfies 99% of all TTFT and TPOT SLOs using only 16 NVIDIA H100 GPUs. In contrast, MuxServe++ requires 32 GPUs to achieve comparable SLO adherence, and static partitioning fails to reach 99% attainment even with 32 GPUs provisioned.
- Runtime Overhead: Under constant, worst-case traffic streams with zero idle gaps (where static partitioning is theoretically optimal), Prism’s VMM mapping layer adds merely 3ms (4%) TTFT overhead and 4ms (13%) TPOT overhead, demonstrating that dynamic elasticity incurs negligible runtime penalties.
Enterprise platforms deploying complex reasoning agents—such as automated enterprise AI data extraction systems—achieve massive throughput multipliers by avoiding over-provisioning.
Production: Cluster Deployment, KVPR Optimization, and Case Studies
Deploying Prism across enterprise GPU clusters involves configuring the global scheduler, provisioning the Redis request buffer, and verifying telemetry metrics across production nodes.
+-----------------------------------------------------------------------------+
| PRODUCTION CLUSTER TOPOLOGY ARCHITECTURE |
+-----------------------------------------------------------------------------+
| |
| [ Ingress Traffic Router / API Gateway (FastAPI / NGINX) ] |
| │ |
| [ Redis Request Ingestion Bus (Per-Model Priority Queues) ] |
| │ |
| [ Prism Central Orchestrator Daemon (ZeroMQ State Channel) ] |
| │ |
| ┌──────┴───────────────────────────────────────────────────────────────┐ |
| │ GPU WORKER CLUSTER (e.g., 4x Nodes x 8x NVIDIA H100 80GB SXM5) │ |
| │ │ |
| │ NODE 01: [ GPU 0-3: LLaMA-3.3-70B (TP=4) + 4x 8B Agents (Shared) ] │ |
| │ [ GPU 4-7: DeepSeek-R1-Distill-32B (TP=4) + 6x 3B Models ] │ |
| │ │ |
| │ NODE 02: [ GPU 0-7: Dynamic Ballooning Pool (kvcached Engine) ] │ |
| └──────────────────────────────────────────────────────────────────────┘ |
| |
+-----------------------------------------------------------------------------+ Production Cluster Deployment Script
The following deployment script initializes Prism’s global coordinator, loads the KVPR placement optimizer, and mounts the SGLang inference engines:
#!/usr/bin/env python3
# Prism Multi-LLM Cluster Orchestrator and Global KVPR Scheduler Daemon
# Monitors node memory pressure and coordinates dynamic model placement
import time
import math
from typing import List, Dict
class ModelDescriptor:
def __init__(self, name: str, weight_gb: float, request_rate: float, slo_ttft_sec: float, tp_size: int = 1):
self.name = name
self.weight_gb = weight_gb
self.request_rate = request_rate
self.slo_ttft_sec = slo_ttft_sec
self.tp_size = tp_size
self.demand = request_rate / slo_ttft_sec
class GPUGroup:
def __init__(self, group_id: int, total_hbm_gb: float = 80.0, num_gpus: int = 1):
self.group_id = group_id
self.capacity_gb = total_hbm_gb * num_gpus
self.assigned_models: List[ModelDescriptor] = []
@property
def used_weight_gb(self) -> float:
return sum(m.weight_gb / m.tp_size for m in self.assigned_models)
@property
def shared_kv_memory_gb(self) -> float:
return max(0.1, self.capacity_gb - self.used_weight_gb)
@property
def total_demand(self) -> float:
return sum(m.demand / m.tp_size for m in self.assigned_models)
@property
def kvpr(self) -> float:
return self.total_demand / self.shared_kv_memory_gb
class GlobalKVPRScheduler:
def __init__(self, num_gpu_groups: int, hbm_per_group: float = 80.0):
self.groups = [GPUGroup(i, total_hbm_gb=hbm_per_group) for i in range(num_gpu_groups)]
def solve_optimal_placement(self, models: List[ModelDescriptor]) -> Dict[str, List[int]]:
sorted_models = sorted(models, key=lambda m: (m.demand / max(1.0, m.weight_gb)), reverse=True)
placement_map = {}
for model in sorted_models:
assigned_groups = []
for part in range(model.tp_size):
best_group = None
lowest_resulting_kvpr = float('inf')
for group in self.groups:
if group.group_id in assigned_groups:
continue
prospective_weight = group.used_weight_gb + (model.weight_gb / model.tp_size)
if prospective_weight >= group.capacity_gb - 2.0:
continue
prospective_shared_mem = group.capacity_gb - prospective_weight
prospective_demand = group.total_demand + (model.demand / model.tp_size)
resulting_kvpr = prospective_demand / prospective_shared_mem
if resulting_kvpr < lowest_resulting_kvpr:
lowest_resulting_kvpr = resulting_kvpr
best_group = group
if best_group is None:
raise RuntimeError(f"OOM: Failed to place model {model.name} across cluster!")
best_group.assigned_models.append(model)
assigned_groups.append(best_group.group_id)
placement_map[model.name] = assigned_groups
return placement_map
def display_cluster_health(self):
print("\n================== PRISM CLUSTER TELEMETRY STATUS ==================")
for g in self.groups:
print(f" GPU Group {g.group_id:02d} | Cap: {g.capacity_gb:.1f}GB | Weights: {g.used_weight_gb:.1f}GB | "
f"KV Headroom: {g.shared_kv_memory_gb:.1f}GB | Demand: {g.total_demand:.2f} | KVPR: {g.kvpr:.4f}")
max_kvpr = max(g.kvpr for g in self.groups)
print(f"[*] Peak Cluster KVPR: {max_kvpr:.4f} (Load Balanced)\n")
if __name__ == "__main__":
scheduler = GlobalKVPRScheduler(num_gpu_groups=4, hbm_per_group=80.0)
fleet = [
ModelDescriptor("llama-3.3-70b-instruct", weight_gb=140.0, request_rate=12.0, slo_ttft_sec=0.10, tp_size=2),
ModelDescriptor("qwen-2.5-32b-coder", weight_gb=64.0, request_rate=8.0, slo_ttft_sec=0.08, tp_size=1),
ModelDescriptor("deepseek-r1-distill-14b", weight_gb=28.0, request_rate=15.0, slo_ttft_sec=0.05, tp_size=1),
ModelDescriptor("llama-3.1-8b-agent", weight_gb=16.0, request_rate=25.0, slo_ttft_sec=0.04, tp_size=1),
ModelDescriptor("qwen-2.5-7b-math", weight_gb=14.0, request_rate=18.0, slo_ttft_sec=0.04, tp_size=1)
]
placement = scheduler.solve_optimal_placement(fleet)
for model_name, group_ids in placement.items():
print(f"[Placement] {model_name:30} -> GPU Groups {group_ids}")
scheduler.display_cluster_health() Real-World Production Case Studies
Prism was validated in dual production shadow deployments across two major industrial environments:
- Company A (Enterprise Internal Cloud): Deployed on an internal cluster serving thousands of research and enterprise engineers running mixed workloads (3B to 70B models). With Prism dynamically managing model placement and elastic ballooning, Company A achieved a 3.89x increase in average token throughput per GPU over multi-week measurement periods, with zero SLO violations and identical p99 tail latency.
- Company B (Commercial Multi-Tenant Inference Provider): Optimized revenue per GPU under bursty public API traffic. Prior to Prism, rigid memory partitioning forced Company B to over-provision GPU worker pools. Deploying Prism increased billable revenue per GPU by 2.86x, directly monetizing previously stranded memory capacity.
By transforming GPU High-Bandwidth Memory from a set of rigid, fragmented silos into an elastic, self-balancing pool, Prism establishes the definitive systems blueprint for high-efficiency, multi-tenant AI inference infrastructure.