Home · ASPLOS 2022 · Datacenter, Cloud & Networking

VELTAIR: towards high-performance multi-tenant deep learning services via adaptive compilation and scheduling

Zihan Liu, Jingwen Leng, Zhihui Zhang, Quan Chen, Chao Li and Minyi Guo

Conference
ASPLOS 2022
Published
2022
Pages
388-401
Citations
52

Serving many models on one CPU, the right schedule changes with load and the right machine code changes with neighbor noise — VELTAIR compiles each layer once into a small Pareto family from locality-greedy to parallelism-heavy, then picks code versions and layer-block sizes on the fly, landing within 10% of interference-free speed.

The argument in one glance

  1. Problem

    One model cannot fill a server, so tenants must share — and interfere

    Inference runs at small batch sizes, leaving a 64-core CPU mostly idle per request: a Threadripper 3990X sustains ~300 queries per second on MLPerf vision models. Sharing the machine across models recovers the throughput — and creates contention on the L3 cache and memory bandwidth that inflates a task’s latency by up to 1.8× under heavy co-location.

  2. What people did

    Smarter multi-tenant schedulers on specialized hardware

    PREMA time-multiplexes an NPU with preemption; AI-MT overlaps compute- and memory-bound layers; Planaria spatially partitions a systolic array per task; datacenter QoS managers like PARTIES partition conventional resources. All schedule fixed binaries at fixed granularities — whole models, or single layers.

  3. Why it fell short

    Fixed granularity wastes the machine, and fixed code fights the neighbors

    Model-wise scheduling allocates for a model’s peak layer, leaving a 47% core-usage gap; layer-wise scheduling tracks needs precisely but collides constantly (high conflict rate, per-layer overhead). Worse, the best block size changes with load — 6 layers at 150 QPS, 11 at 200. And code auto-tuned in isolation bets everything on cache locality, exactly the resource neighbors steal: the optimal binary depends on interference that only exists at runtime.

  4. This paper's idea

    Adapt both knobs: multi-version code, dynamic-size layer blocks

    VELTAIR extends TVM’s auto-scheduler to harvest, in a single search pass, several implementations per layer along the parallelism-locality Pareto frontier — from locality-greedy (fast when quiet) to parallelism-heavy (tolerant when noisy). A runtime scheduler measures interference, picks each block’s version, and forms layer blocks whose size follows a dynamic threshold set by idle cores. Result: 45–71% more QPS at the same QoS than Planaria, half the average latency, within 10% of isolated execution.

Why this problem is worth solving

Inference serving has an occupancy problem. Training saturates machines; serving arrives one query at a time, and a single small-batch inference cannot use 64 cores. The paper’s measurement: an AMD Threadripper 3990X serves around 300 queries per second on MLPerf vision models — one machine, many customers’ worth of capacity. So providers co-locate: multiple models, multiple tenants, one CPU. (This paper deliberately targets general-purpose hardware — the CPUs many companies actually serve on — where resource boundaries are softest.)

Co-location’s tax is

performance loss from contention on shared resources — last-level cache capacity, cache bandwidth, memory bandwidth — between co-running tasks that hold separate cores but not separate memories
. Measured here: up to 1.8× latency inflation for a model under heavy co-running pressure. For latency-critical services with
quality-of-service targets — per-query latency deadlines; the serving metric is how many queries per second can be sustained with 95% of tasks meeting their deadline
, that tax converts directly into lost capacity.

The paper’s framing insight is that two decisions govern this tax, and both are conventionally frozen. The schedule — at what granularity work claims cores — is fixed per system. And the code — the loop tiling, unrolling, and parallelization of every layer, produced by compilers like TVM (see the TensorIR and AStitch explainers elsewhere on this site) — is auto-tuned once, in isolation, on a quiet machine. Multi-tenancy invalidates the quiet machine. VELTAIR is, by its authors’ account, the first system to treat compilation itself as a serving-time knob.

What people did before, and where it broke

Multi-tenant DNN schedulers. PREMA (temporal multiplexing with preemption), AI-MT (overlapping compute- and memory-heavy layers), and Planaria (spatially splitting a systolic array) advanced accelerator sharing; PARTIES and similar QoS managers partition resources for conventional interactive services. All hold both granularity and code fixed. Some (AI-MT, Planaria) even split layers into sub-layers — which the analysis here shows is overly fine: layer-wise is already conflict-dominated.

The granularity dilemma, measured. Scheduling whole models (first-come-first-served) allocates each model’s peak requirement for its whole runtime; since per-layer needs are jagged, cores idle — a 47% gap versus the per-layer minimum at 75% load. Scheduling single layers tracks the jagged profile precisely but pays a conflict rate an order of magnitude higher (every layer boundary is a reallocation, and concurrent tenants’ reallocations collide) plus per-layer scheduling overhead. Fixed blocks of layers sit between — but the best block size moves with load: 6 layers wins at 150 QPS, 11 at 200. No static choice survives a bursty day.

The compilation blind spot. Auto-tuned kernels (TVM outperforms even Intel’s MKL-DNN library here) are searched on an idle machine. The search rewards big tiles that live in the L3 cache — maximum locality. Under a noisy neighbor, that bet inverts: the cache is contended, big-tile code stalls, and a differently-compiled version of the same layer — smaller tiles, more parallelism — wins. The optimal binary is a function of interference level, which is unknowable at compile time.

VELTAIR: an offline compiler and an online scheduler

  1. Single-pass multi-version compiler new

    Extends TVM’s auto-scheduler: during ONE search pass per layer (~20 minutes), it harvests candidate implementations along the parallelism-locality Pareto frontier instead of just the single winner — from high-locality/big-tile (best when quiet) to high-parallelism/small-tile (tolerant when noisy). Naively searching per interference level would take five passes (~2 hours); this adds almost nothing.

  2. Version selection new

    Up to V=5 dominant implementations are kept per layer, each annotated with the interference range where it wins. Benefits saturate at 4 versions; only 3% of layers need all 5 — most need 2–3 to stay within 10% of the per-level optimum, keeping code storage modest.

  3. Dynamic layer-block formation new

    Per model, compute each layer’s core requirement to meet QoS and the model-wide average. Layers whose requirement exceeds average + threshold are conflict-prone: they become block-starting pivots. Within each block, work is smoothed — peak layers borrow time from cheap ones — so the block’s core claim is flat and modest.

  4. Runtime threshold + interference proxy new

    The threshold comes from spare capacity: total cores minus all active models’ average needs, distributed proportionally (64 cores, models averaging 12/12/24 → 16 idle → thresholds 4/4/8). A linear-model interference proxy reads system state and selects each block’s code version. Total scheduling overhead: under 0.1 ms per model.

  5. Execution engine

    Blocks from all tenants queue and execute; conflict rate stays near model-wise scheduling’s low level while core usage stays within 10% of layer-wise’s minimum.

Both algorithms are O(N) scans over a model's layers — the adaptivity costs microseconds, not milliseconds.

The idea

Interference tolerance is a compilable property. The two code versions that win at the extremes differ systematically: the quiet-machine winner uses large tiles (locality — data parked in the shared L3) and moderate parallelism; the noisy-machine winner uses small tiles and maximal parallelism (little cache footprint to lose, more cores to hide latency). These are not two tricks but two ends of the classic parallelism-locality trade-off, and the intermediate points form a

the set of options where improving one objective necessarily worsens the other — here, no version is both more local and more parallel than another frontier member
. That geometry is the compiler insight: the auto-scheduler’s search already traverses this space, so one pass can emit the whole family — the naive alternative (re-search under five artificial interference levels, ~2 hours per layer) is replaced by bookkeeping.

Conflict-prone layers should start blocks. The scheduling insight is about shape: a model’s per-layer core requirement is jagged, and conflicts concentrate at the spikes — layers demanding far more cores than the model’s average. The block-formation algorithm walks the layers once, splits at every spike (requirement > average + threshold), and flattens each block internally by letting the spike borrow schedule slack from its cheaper neighbors while the block still meets its share of the QoS budget. Blocks claim cores rarely (low conflict, like model-wise) but claim only what they need (low waste, like layer-wise).

Let spare capacity set the aggression. The threshold — how much a block may exceed the average before being split — is not tuned but computed: idle cores (total minus sum of active models’ averages) are distributed proportionally to each model’s appetite. Heavy load → few idle cores → threshold near zero → many small, frugal blocks; light load → generous thresholds → big blocks that sprint. The system’s granularity breathes with its load, which is exactly what the static block-size study said was needed.

A ResNet-50 query threads through a noisy afternoon

Block = consecutive layers scheduled as one unit; pivot = conflict-prone layer starting a block. Version 1 = high-locality code (big tiles), version 5 = high-parallelism code (small tiles). thres = per-model core threshold from idle capacity. Numbers follow the paper's 64-core Threadripper setup; the query walk is illustrative.

Step 1 of 6

Offline, months earlier: one search, five binaries

Each ResNet-50 layer went through one TVM auto-scheduler pass (~20 min). Along the way, VELTAIR harvested the Pareto frontier: version 1 tiles for the L3 (fastest alone), version 5 splits fine and parallelizes wide (degrades least under contention), versions between interpolate. Each is tagged with the interference range it dominates.

one pass ≈ 20 min vs 5 passes ≈ 2 h
kept: ≤5 dominant versions/layer (3% of layers need 5)

Why it works

  • Interference changes which loop structure is optimal → compiling one binary per layer bakes in a bet about neighbors → a small Pareto family per layer (locality → parallelism) lets the runtime re-bet every block, at code-selection cost only.
  • The auto-scheduler already explores the parallelism-locality space → harvesting the frontier during one pass is nearly free → five interference-specialized versions cost one search, not five.
  • Conflicts concentrate at core-requirement spikes → splitting blocks exactly at spikes and smoothing within them gives model-wise conflict rates at layer-wise efficiency → the false dilemma between waste and collisions dissolves.
  • The right granularity depends on spare capacity → deriving the threshold from idle cores makes block size track load automatically → no operator-tuned constant to go stale.
  • Both runtime algorithms are linear scans plus a linear proxy → under 0.1 ms per model → adaptivity never becomes its own interference source.

What it costs

  • Code storage. Up to five binaries per layer — mitigated by keeping only dominant versions (most layers need 2–3; only 3% need five).
  • A proxy, not a measurement. Interference level comes from a linear model over observable system state; mispredictions pick suboptimal versions (bounded by the versions’ own robustness).
  • CPU-centric mechanics. The knobs (tiles vs threads, L3 behavior, core counts) are general-purpose-hardware concepts; porting to GPUs/accelerators with hard partitions changes the trade-off space.
  • QoS model. Per-layer core requirements derive from profiled latencies against per-model QoS budgets; new models need that profiling pass.
  • Latency-critical focus. Best-effort co-location is sketched as an extension, not evaluated.

The evaluation

Seven MLPerf-derived models spanning weight classes — light (EfficientNet, MobileNet-V2, Tiny-YOLOv2), medium (ResNet-50, GoogLeNet), heavy (SSD, BERT-Large) — arrive as Poisson streams on a 64-core AMD Threadripper 3990X. Baselines: PREMA-style temporal multiplexing, Planaria-style layer-wise spatial scheduling (adapted to CPU), plus VELTAIR ablations (adaptive scheduling only, adaptive compilation only, full).

Multi-tenant serving strategies on one 64-core CPU

PropertyPREMA-style (temporal)Planaria-style (layer-wise spatial)VELTAIR (adaptive both)
What adapts
QPS at 95% QoS satisfaction
Average query latencyHigh under loadReference
Resource efficiency vs conflictsEfficient but serialized
64-core AMD Threadripper 3990X; MLPerf-derived models with per-model QoS targets (light/medium/heavy classes); Poisson arrivals; metrics: QPS with 95% of tasks meeting QoS, average latency, CPU usage efficiency. Version-count sensitivity: gains saturate at 4 versions; scheduling + proxy overhead < 0.1 ms per model; TVM-generated kernels outperform MKL-DNN as the single-tenant baseline.Underlined values explain themselves when clicked.

Check your understanding

  1. 1. A layer’s auto-tuned kernel uses large tiles that fit the L3 cache. A noisy co-tenant starts thrashing that cache. Predict which alternative compilation of the SAME layer now wins.

  2. 2. Model-wise scheduling wastes cores (47% gap) while layer-wise scheduling conflicts constantly. How do VELTAIR’s layer blocks escape the dilemma?

  3. 3. Searching optimal code per interference level would take ~2 hours per layer (five auto-scheduler passes). VELTAIR gets five versions in ~20 minutes. What’s the trick?

  4. 4. With 64 cores and active models averaging 12, 12, and 24 cores, VELTAIR sets block thresholds of 4, 4, and 8. What behavior does this formula produce as the machine fills up?

Related papers on Datacenter, Cloud & Networking

See all 163 →