Skip to content
Published on

MIG and Time-Slicing — Two Ways to Share One GPU

Share
Authors

Introduction — Two Ways to Share One Card

The previous post argued that a GPU is an extended resource requested only in whole integers, and that with no isolation in the hardware you cannot simply share it. Yet in practice reasons to share keep appearing. You want several laptop-sized inference models on one card, and there is no budget to hand eight developers a card each.

NVIDIA offers two answers, and they share little beyond a resemblance in the pitch. One divides time; the other divides hardware. The criterion for choosing is not performance. It is isolation.

Metric names and configuration were verified against the official documentation and repositories on 2026-08-12. They can differ between releases, so check again against the version you are running.

Time-Slicing — Dividing Time

Time-slicing configures the device plugin to advertise one physical GPU as multiple replicas. The hardware does not change at all. Only the number the scheduler sees goes up.

The ConfigMap structure the official documentation shows looks like this.

apiVersion: v1
kind: ConfigMap
metadata:
  name: time-slicing-config
data:
  any: |-
    version: v1
    flags:
      migStrategy: none
    sharing:
      timeSlicing:
        renameByDefault: false
        failRequestsGreaterThanOne: false
        resources:
          - name: nvidia.com/gpu
            replicas: 4

Three fields carry the weight. replicas sets how many the single card is advertised as. renameByDefault chooses whether those replicas are advertised under the original name or a share-specific one: set it true and the advertised resource becomes nvidia.com/gpu.shared, set it false and the name stays nvidia.com/gpu. failRequestsGreaterThanOne decides whether to reject a container that asks for more than one replica.

renameByDefault is the most dangerous switch here in practice. Leave it false and existing manifests start receiving a shared GPU one day without anyone touching them. Set it true and the name changes, so pods that want sharing must be edited, but nothing breaks silently.

You apply it through the ClusterPolicy.

kubectl create -n gpu-operator -f time-slicing-config.yaml

kubectl patch clusterpolicies.nvidia.com/cluster-policy \
  -n gpu-operator --type merge \
  -p '{"spec": {"devicePlugin": {"config": {"name": "time-slicing-config-all", "default": "any"}}}}'

For per-node configuration, label the node with nvidia.com/device-plugin.config to select which key of the ConfigMap applies. The replication factor is visible as the nvidia.com/gpu.replicas label.

And the documentation carries one sentence in bold that matters most: unlike MIG, there is no memory or fault isolation between replicas. What that means operationally comes up shortly.

MIG — Dividing Hardware

MIG partitions a GPU into multiple instances at the hardware level. Each instance gets a physically separate memory slice and compute allocation, so in the wording of the documentation it provides separate and secure GPU instances for CUDA applications. There is a condition attached. It only works on GPUs based on the NVIDIA Ampere and later architectures. A100 is the example the documentation names.

Under the GPU Operator, MIG is driven by node labels.

# Check whether the node supports MIG
kubectl get nodes -L nvidia.com/mig.capable,nvidia.com/mig.strategy

# Apply a profile
kubectl label nodes <node-name> nvidia.com/mig.config=all-1g.5gb --overwrite

# Track the rollout (pending / rebooting / success / failed)
kubectl get node <node-name> -o jsonpath='{.metadata.labels.nvidia\.com/mig\.config\.state}{"\n"}'

nvidia.com/mig.config.state acts as the state machine. Right after labeling it goes to pending, passes through rebooting if needed, and lands on success or failed. Plenty of time gets wasted waiting without watching that label.

How resources are advertised depends on the strategy. The single strategy covers the case where MIG is enabled on all GPUs on a node with a uniform profile; the mixed strategy covers the case where it is not. Under mixed, resources split by profile, and per the repository documentation an A100 40GB surfaces nvidia.com/mig-1g.5gb, nvidia.com/mig-2g.10gb, nvidia.com/mig-3g.20gb, and nvidia.com/mig-7g.40gb, while an A100 80GB surfaces nvidia.com/mig-1g.10gb, nvidia.com/mig-2g.20gb, nvidia.com/mig-3g.40gb, and nvidia.com/mig-7g.80gb. Per-profile counts also appear as labels such as nvidia.com/mig-1g.10gb.count.

The chart default strategy is mig.strategy: single. To pass a custom configuration to the MIG Manager, the chart comment states the ConfigMap must have a key named config.yaml.

What the Isolation Gap Actually Produces

Tabulating the difference:

Itemtime-slicingMIG
What is dividedtimehardware
Memory isolationnoneyes
Fault isolationnoneyes
Supported hardwareeffectively unrestrictedAmpere and later
How it is appliedConfigMap and ClusterPolicynode labels and MIG Manager
Node restartnot neededcan be needed on profile change
Advertised resourceoriginal name or share-only nameseparate name per profile

The two isolation rows are the ones that matter. Under time-slicing, if one replica consumes all the VRAM, another replica on the same card fails its memory allocation. From the scheduler's point of view both pods received their resources correctly, while in reality one is starving the other. Worse is the missing fault isolation: if one workload puts the GPU into a bad state, every replica on that card goes down together.

Hence the decision criterion. Can the replicas trust each other? Several copies of one service owned by one team can. Different teams, different customers, or a notebook environment where users upload their own code cannot.

Choosing Between Them

The split usually runs like this.

Time-slicing fits development and experimentation environments, interactive notebooks, and batch jobs that touch the GPU only briefly. What those share is that a broken isolation boundary costs you a retry. You are inside a trust boundary, a human is watching, and rerunning is acceptable.

MIG fits production inference serving, multi-tenancy, and any service that has to promise latency. For anything carrying an SLO the choice is effectively made for you. No promise survives a world where the neighbor instance's load moves your latency.

Neither fits more often than people expect. If you are serving a large model and VRAM is already tight, there is nothing to divide. What you need then is not sharing but tuning batch size and KV cache configuration, and that judgment needs observability data. The next two posts cover where that data comes from.

Closing — Sharing Is a Trust Problem, Not a Utilization Problem

Treat GPU sharing purely as a utilization problem and you will land on time-slicing nearly every time. It is simple to configure, it does not care about hardware, and the effect is immediate. Then one day a pod kills another pod and finding out why takes a full day.

Choose the sharing mechanism by trust boundary, not by utilization. Inside one boundary, divide time. Across a boundary, divide hardware. If the hardware cannot, do not divide. Following that order removes a large class of incidents that are painful to explain afterwards.

The next post turns to seeing how the GPUs you configured are actually being used: the DCGM Exporter.

Try It Yourself

Series

References