Four mechanisms let more than one workload use one GPU: MPS, time-slicing, MIG, and vGPU. Most write-ups explain how each works and stop, which leaves you no closer to picking one. This article is the comparison instead: six axes that actually discriminate between them, a matrix that scores all four on every axis, and the three workload shapes that usually settle the argument before you get to the matrix at all. The mechanics live in the linked articles — what follows is how to choose.
Four mechanisms, one question
The four options are not four points on a single line. They differ in which layer enforces the split. MIG partitions a supported datacentre GPU in hardware, giving each instance its own SMs, L2 slices and memory paths — see MIG partitioning for the geometry. MPS works one layer up: many client processes funnel into a single GPU context so their kernels are genuinely co-resident. Time-slicing is the driver alternating whole contexts in time; both are covered in GPU scheduling. vGPU sits below the guest operating system entirely, with a hypervisor mediating a virtual device into each VM — that model, and live migration, belong to vGPU.
Because the enforcing layer differs, so does everything you care about operationally. The question worth asking is not “which is best” but which failure mode can you tolerate, and at what price in utilization.
Six axes worth scoring
Isolation strength is how well the mechanism prevents one tenant from taking resources it was not given — and whether the guarantee is enforced or merely conventional. Achievable utilization is how much of the device you can actually keep busy once the mechanism is in place, which is not the same as how many tenants you can fit.
The next two are routinely collapsed into one, and they are different. Blast radius is what happens when a neighbour misbehaves within spec: it allocates every free byte of HBM, saturates memory bandwidth, or evicts your working set from L2, and your p99 doubles even though nobody broke a rule. Failure containment is what happens when a neighbour crashes — an unrecoverable fault, an ECC or XID event — and the useful question is the recovery unit: what has to be restarted to get healthy again, and who else goes down with it.
Finally, reconfiguration cost is what it takes to change the split once the fleet is live, and observability is whether your metrics can name the tenant that hurt you.
The decision matrix
Scored on those six axes, with mechanisms as columns:
| Axis | MPS | Time-slicing | MIG | vGPU |
|---|---|---|---|---|
| Isolation strength | Soft ceilings, own address space | Temporal only | Hard, in silicon | VM boundary, time-shared compute |
| Achievable utilization | Highest for small kernels | Moderate, no concurrency | Lowest, capacity stranded | Moderate, per-VM overhead |
| Blast radius | Wide: bandwidth, L2, HBM | Widest: no memory cap | Narrow: separate paths | Memory narrow, latency wide |
| Failure containment (recovery unit) | Client process, server caveat | Process, often whole device | GPU instance | Guest VM |
| Reconfiguration cost | Restart daemon, seconds | Config flag, cheapest | Drain node, privileged | Reboot guest, per-VM |
| Observability | Poor per-client attribution | Aggregate only | Per-instance counters | Good on host, thin in guest |
No column wins. MIG buys the best isolation and containment by permanently giving up the ability to lend an idle partition's silicon to a busy one. MPS buys the best utilization by putting everyone in one shared memory system. Time-slicing buys the lowest operational cost by guaranteeing nothing. vGPU buys the strongest tenant boundary and pays for it with a compute path that is still time-shared underneath. Read the matrix as a list of prices, not of scores.
Isolation and utilization pull opposite ways
The first two rows are the core trade, and they are anti-correlated for a structural reason: isolation means reserving, and reserved capacity that goes unused is stranded. A MIG instance sized for a model that is idle at 3 a.m. cannot lend its SMs to the busy instance next door. That is the cost of the guarantee, not a defect.
MPS is the opposite: because clients share one context, small kernels from different processes run concurrently and fill SMs that any one process would leave idle. It is the only one of the four that raises utilization by creating real concurrency. Time-slicing does not — contexts alternate, so one runs at a time and the context switches are pure overhead. It recovers capacity only from workloads with a low duty cycle, where the win is that an idle notebook yields the device rather than holding it. Default vGPU scheduling is temporal too, so it inherits the same ceiling unless the vGPU is MIG-backed.
Blast radius and the recovery unit
Under MPS the blast radius is the whole device. The active-thread-percentage ceiling caps how many SMs a client may occupy, but nothing caps memory bandwidth, L2 footprint, or the HBM one client can allocate. A well-behaved neighbour that simply runs a bandwidth-bound kernel will move your tail latency. Time-slicing is worse still: the common Kubernetes device-plugin approach advertises one GPU as N schedulable replicas but partitions no memory, so pods share one unpartitioned HBM pool and their combined allocations can exceed it — one allocation storm produces out-of-memory errors for everyone. MIG narrows this to almost nothing because the memory path itself is partitioned. vGPU hard-partitions the framebuffer but time-shares the engines, so memory is contained and latency is not.
Containment differs again. Volta-and-later MPS gives each client its own GPU address space, so a client fault no longer automatically kills its peers — but the MPS server is still shared, and any fault severe enough to require a device reset takes down every process on that GPU regardless of mechanism. MIG contains most faults to the instance. vGPU has the cleanest answer: reboot the guest.
Reconfiguration cost: how fast can you change your mind
This row decides more real deployments than isolation does, because demand shifts and a split you cannot change becomes a split you are stuck with.
Time-slicing is nearly free to change — a replica count in the device plugin's configuration and a restart. MPS is close behind: start or stop the daemon, and per-client thread percentages are environment variables set at launch. MIG is the expensive one. Changing profiles requires that no clients hold the device, is a privileged operation, and in a cluster usually means cordoning and draining the node before the instances can be destroyed and recreated. Plan MIG geometry as a node-pool decision with a lifetime of weeks, not as something an autoscaler retunes. vGPU sits in between: a profile is fixed for the life of a guest, so changing it means a VM restart.
Observability: can you name the tenant that hurt you
This axis is the one most often discovered too late. When a shared GPU gets slow, the first question is always which tenant caused it, and two of the four mechanisms cannot answer.
Under MPS the device sees a single context. Utilization and memory counters attribute to the MPS server, not to the client that generated the work, so per-client accounting has to be reconstructed from application-level metrics you instrument yourself. Time-slicing is similar: the device reports one aggregate utilization figure and nothing about which slice consumed it. MIG is the strong case — instances are first-class objects with their own identifiers, and monitoring tooling reports memory and utilization per instance, so attribution is a query rather than an investigation. vGPU gives the host good per-vGPU engine and framebuffer metrics, while the view from inside a guest is deliberately narrow. If you owe someone an SLO, you need a mechanism whose telemetry can defend it.
Three workload shapes that settle it
Many small inference jobs, one trusted team. Each replica launches kernels too small to fill the device and spends much of its time waiting on request arrival. This is MPS's home ground: co-residency converts that idle silicon into throughput, and the shared-fate risk is acceptable because the processes are yours. Move to MIG only when one of those models carries a latency SLO you must defend against its noisy neighbours.
A few large training jobs. The honest answer is usually do not share at all. A well-tuned training step already saturates SMs and memory bandwidth, so any sharing mechanism subtracts throughput and adds jitter that shows up as stragglers at every collective. Give these whole GPUs and let the cluster scheduler queue them.
Untrusted multi-tenant. MPS is designed for cooperating processes and should never carry a trust boundary. The defensible options are MIG for containers you still control, and vGPU — ideally MIG-backed, which is the only configuration that gives a VM-grade security boundary and hard performance isolation at once — when tenants bring their own kernel.
The decision path, and mixing mechanisms in one fleet
Compressed to a sequence: does the workload already saturate the device? Then do not share. Is there a trust boundary between tenants? Then vGPU, MIG-backed if you also owe performance guarantees. Is there an SLO you have to defend with numbers? Then MIG, and budget for the drain-to-reconfigure cost. Are the processes yours, cooperative, and individually too small for the GPU? Then MPS. Is this development, CI, or notebooks where access matters and predictability does not? Then time-slicing, because it is the cheapest thing that works.
Nothing forces one answer per fleet, and the mature pattern is not to try. Split the cluster into node pools by mechanism — a MIG pool for tenanted serving, an MPS pool for internal inference, whole GPUs for training, a time-sliced pool for development — label the nodes, and let the scheduler route by workload shape. That keeps each mechanism's blast radius inside the pool that accepted it, which is the real goal.