In the modern compute landscape, an H100 isn’t just a chip; it’s a high-stakes real estate market. With organizations burning through millions in capital expenditure to secure silicon, the “GPU Tax”—the delta between peak theoretical performance and actual utilization—has become the most expensive inefficiency in the enterprise stack.
But here is the kicker: as we shift from training massive LLMs to serving them in real-time applications (think voice AI agents with <200ms latency or high-frequency algorithmic trading), the challenge isn’t just “having” GPUs. It’s the ability to slice, dice, and orchestrate those GPUs across hundreds of tenants with sub-millisecond overhead.
If you are seeing 50ms of “noise” before your model even starts its first forward pass, you aren’t just losing time; you’re losing money. Welcome to the world of high-performance GPU virtualization.
The Physics of the Problem: Why GPUs Hate Sharing
In a traditional CPU world, multi-tenancy is “solved.” The Linux kernel is a master of preemptive multitasking. It can context-switch between thousands of threads, giving each the illusion of a dedicated processor.
GPUs are different. Architecturally, a GPU is a throughput monster, not a latency ninja. It expects to be fed massive blocks of contiguous data to process across thousands of small, relatively “dumb” cores (CUDA cores).
When you try to run multiple workloads on a single GPU, you hit three walls:
- Memory Contention: Two models trying to allocate VRAM simultaneously leads to the dreaded
Out of Memory (OOM)error, crashing the entire engine. - Kernel Queuing: Standard NVIDIA drivers use a “First-In, First-Out” (FIFO) scheduler. If Tenant A submits a heavy image-generation task, Tenant B’s sub-millisecond sentiment analysis task sits in the hardware queue, twiddling its thumbs.
- Context Switch Penalty: Swapping the entire state of a GPU (registers, shared memory, program counters) is orders of magnitude heavier than a CPU context switch. We’re talking about moving megabytes of state, which can take several milliseconds—an eternity when your total inference budget is 10ms.
To achieve sub-millisecond orchestration, we have to bypass the “standard” way of doing things.
The Virtualization Spectrum: From Time-Slicing to MIG
To orchestrate at scale, we need to choose our virtualization primitive. There is no one-size-fits-all, but the industry has settled on four primary strategies.
1. Time-Slicing (The “Fair-Share” Approach)
This is the default Kubernetes behavior for GPU sharing. It uses a simple round-robin scheduler.
- The Technical Substance: The driver allows multiple processes to submit work to the GPU. The hardware scheduler gives each process a “slice” of time.
- The Catch: There is zero isolation. If one tenant triggers a kernel panic or consumes 100% of the memory bandwidth, everyone else suffers. For sub-millisecond inference, time-slicing is usually a non-starter because of the unpredictable tail latency (p99).
2. NVIDIA MPS (Multi-Process Service)
MPS is the “unsung hero” of the inference world. It allows multiple CUDA processes to share the same hardware resources concurrently by funneling them through a single “server” process.
- Why it works: Instead of context switching, MPS overlays kernels from different processes onto the GPU simultaneously. It effectively turns a “single-tenant” hardware scheduler into a multi-tenant one.
- The Win: You get massive utilization gains. If Model A only uses 30% of the Streaming Multiprocessors (SMs), Model B can use the other 70% at the exact same time.
- The Infrastructure Detail: You can set “active thread percentage” limits for each tenant. For example,
export CUDA_MPS_ACTIVE_THREAD_PERCENTAGE=30.
3. MIG (Multi-Instance GPU)
Introduced with the Ampere (A100) architecture, MIG is the “hard partition.” It carves the GPU into up to seven independent hardware instances.
- The Architecture: Each instance has its own dedicated memory controllers, cache, and SMs.
- The Benefit: Perfect Isolation. A failure in Instance 1 has zero impact on Instance 2. It’s the closest thing to having seven separate physical GPUs.
- The Trade-off: It is rigid. You cannot dynamically reconfigure MIG instances without a reset, which makes it difficult for “bursty” serverless workloads.
4. Software-Defined Partitioning (The Next Frontier)
Companies like Run:ai and CoreWeave are building abstraction layers that sit above the driver, using interceptors to manage GPU memory and compute at the API level. This allows for “fractional GPUs” that feel like MIG but offer the flexibility of Time-Slicing.
Sub-Millisecond Orchestration: The Orchestrator’s Blueprint
Building a sub-millisecond orchestrator is about eliminating “jitter” in the stack. If you’re using standard Kubernetes with a 1-second polling interval for your metrics, you’ve already lost.
Here is how we architect for the “Speed of Light” inference.
Zero-Copy Data Paths
The biggest latency killer in multi-tenant systems is moving data from the CPU to the GPU (Host-to-Device). In a multi-tenant environment, if you have to copy input data multiple times across memory boundaries, you’ve added 2-5ms of latency.
We utilize GPUDirect RDMA and Shared Memory (shm) segments. Instead of the orchestrator receiving a request and “sending” it to the GPU pod, the orchestrator places the request in a shared memory region that the GPU process is already polling.
The “Warp-Drive” Scheduler
Standard K8s schedulers are too slow. For sub-millisecond orchestration, you need a custom side-car or daemonset written in a systems language like Rust or C++ that handles request steering at the local node level.
// Pseudocode for a high-speed GPU Request Steerer
while (true) {
auto request = shared_memory_queue.pop();
if (request) {
// Use CUDA Streams to launch kernel asynchronously
// This avoids blocking the orchestrator thread
launch_inference_kernel<<<grid, block, 0, tenant_streams[request.tenant_id]>>>(
request.input_ptr,
request.output_ptr
);
// Record event for latency tracking without blocking
cudaEventRecord(tenant_stop_events[request.tenant_id], tenant_streams[request.tenant_id]);
}
}
CUDA Streams and Priority Gold-Slicing
In a multi-tenant setup, not all tenants are equal. We use CUDA Streams with Priority. NVIDIA allows you to create streams with different priorities:
int priority_high, priority_low;
cudaDeviceGetStreamPriorityRange(&priority_low, &priority_high);
cudaStreamCreateWithPriority(&stream_high, cudaStreamNonBlocking, priority_high);
cudaStreamCreateWithPriority(&stream_low, cudaStreamNonBlocking, priority_low);
By mapping your “Premium Tier” tenants to high-priority streams, the hardware scheduler will prioritize their kernels over “Free Tier” or “Batch” workloads at the hardware level, ensuring sub-millisecond response even under load.
The Hype Context: Why This is Blowing Up Now
If you’ve been on Tech Twitter or LinkedIn lately, you’ve seen the hype around “Serverless GPUs” and “100 tokens per second.” This isn’t just marketing fluff; it’s a response to a fundamental shift in AI.
- The Rise of Small Language Models (SLMs): While GPT-4 gets the headlines, models like Mistral-7B, Llama-3-8B, and Phi-3 are what developers are actually deploying. These models don’t need a full H100. Running one 8B model on an 80GB H100 is like driving a Ferrari to the mailbox. Multi-tenancy is the only way to make the unit economics work.
- The “Agentic” Shift: AI agents are performing loops of reasoning. If an agent needs to call an LLM 10 times to solve a task, and each call has 100ms of orchestration overhead, the agent feels “slow” and “robotic.” Sub-millisecond orchestration is the prerequisite for AI that feels human.
- The Groq Effect: Companies like Groq (with their LPU) have set a new bar for speed. To compete, the GPU-based clouds (AWS, Azure, Lambda) have to optimize their software stack to reduce the “Orchestration Tax.”
Advanced Engineering Curiosity: eBPF for GPU Observability
One of the biggest challenges in multi-tenant GPU environments is fairness. How do you know if Tenant A is slowing down Tenant B?
Standard tools like nvidia-smi poll at 1Hz (once per second). That’s a blind spot the size of a galaxy. A kernel can execute in 50 microseconds. In one second, you could have 20,000 kernels run.
At the cutting edge, we are using eBPF (Extended Berkeley Packet Filter) to hook into the NVIDIA UVM (Unified Memory) and ioctl calls. By tracing the nv_ioctl calls, we can measure exactly how much time the GPU is spending on a specific PID’s kernels with microsecond precision.
The observability stack looks like this:
- Data Collector: A Rust-based agent using
libbpfto trace GPU ioctls. - Time-Series Store: VictoriaMetrics or high-cardinality Prometheus.
- The Loop: If the agent detects a “noisy neighbor” (a tenant exceeding their allocated SM-hours), it dynamically adjusts the MPS thread percentage in real-time.
Managing the “Cold Start” in Multi-Tenancy
In a truly elastic multi-tenant system, you don’t want 100 models sitting in VRAM all the time. But loading a model from disk to VRAM can take seconds.
To achieve sub-millisecond orchestration (even if the inference itself takes longer), we employ VRAM Paging and Weight Streaming.
Instead of loading the whole model, we keep the “hot” layers in VRAM and stream the “cold” layers using NVMe-over-Fabrics or GPUDirect Storage.
- The Trick: We use a technique called Model Multiplexing. We keep a “Base Model” (e.g., Llama-3) in VRAM and only swap out the LoRA (Low-Rank Adaptation) adapters for each tenant.
- The Scale: A LoRA adapter is only ~100MB, whereas the base model is 15GB+. Swapping 100MB over the PCIe Gen5 bus takes less than a millisecond. This allows one GPU to serve hundreds of “different” models as if they were all resident in memory.
The Infrastructure Stack: A High-Level Summary
To pull this off at the scale of a Netflix or Uber, your stack ends up looking like a finely tuned orchestra:
| Layer | Technology | Role |
|---|---|---|
| Compute | NVIDIA H100 / A100 | The raw horsepower. |
| Interconnect | InfiniBand / RoCE v2 | RDMA for zero-copy data transfer. |
| Partitioning | NVIDIA MPS + Custom LoRA Swapper | Concurrent execution with isolation. |
| Orchestrator | K8s + Custom Rust Scheduler | Sub-millisecond request steering. |
| Telemetry | eBPF + DCGM | Microsecond-level usage tracking. |
The Road Ahead: The Software-Defined GPU
We are moving toward a future where the physical boundaries of the GPU disappear. Technologies like CXL (Compute Express Link) will eventually allow GPUs to access system memory with the same latency as local VRAM, effectively making “OOM” errors a thing of the past.
But until then, the “Billion-Dollar Slice” remains a software engineering problem. The winners in the AI race won’t just be the ones with the most chips; they will be the ones who can orchestrate those chips with the highest surgical precision.
If you can squeeze 100 tenants onto a single H100 without a single one of them feeling a millisecond of lag, you haven’t just optimized your infrastructure—you’ve unlocked a level of compute efficiency that was previously thought to be impossible.
Keep the kernels small, the streams prioritized, and the memory shared. The era of the micro-tenant GPU is here.