Home · ASPLOS 2022 · Memory Systems & Caches

TMO: transparent memory offloading in datacenters

Johannes Weiner, Niket Agarwal, Dan Schatzberg, Leon Yang, Hao Wang, Blaise Sanouillet and 5 others

Conference
ASPLOS 2022
Published
2022
Pages
609-621
Citations
94

Meta taught the Linux kernel to measure how much work an application loses to memory shortage, then used that one signal to automatically push each container's cold memory out to compressed RAM or SSD — saving 20–32% of DRAM across millions of servers.

The argument in one glance

  1. Problem

    DRAM is becoming the biggest line item in the server bill

    Memory demand keeps growing while DRAM scaling slows and prices swing. At Meta, DRAM is headed toward 33% of server cost and 38% of server power. Meanwhile about 35% of allocated memory sits untouched for over five minutes — paid for at DRAM prices, used at archive frequency.

  2. What people did

    Swap cold pages to cheaper storage, transparently, in the kernel

    Google pioneered this at scale: compress cold pages into a RAM pool (zswap) and cap the rate at which pages come back. It works, and it requires no application changes.

  3. Why it fell short

    One tier, offline profiling, and a proxy metric that lies

    The pioneering system supports only compressed memory — but some data barely compresses, and SSDs are ten times cheaper per byte. It needs offline profiling per application. And its control signal, the page swap-in rate, does not measure harm: the paper shows a faster device with a higher swap-in rate delivering better performance.

  4. This paper's idea

    Measure lost work directly, and let one control loop drive every backend

    TMO adds a kernel mechanism — pressure stall information — that measures, in real time, the fraction of work a container loses waiting for memory. A userspace agent keeps that number just below one thousandth, reclaiming memory when there is slack. The same loop, with the same global settings, drives compressed memory and SSDs across every application, and has saved 20–32% of fleet memory for over a year.

Why this problem is worth solving

Every server in a large fleet carries DRAM sized for its worst moment, and most of that DRAM spends most of its time holding data nobody reads. The paper measures both halves of this waste precisely.

The cost half: across Meta’s hardware generations, DRAM is projected to reach 33% of server cost and its power draw 38% of server infrastructure power. The alternatives are dramatically cheaper. A compressed-memory pool (cold pages compressed in RAM) costs about a third of raw DRAM for typical 3× compressibility. An NVMe SSD — solid-state drive attached over the fast NVMe interface — contributes under 3% of server cost, and per byte of capacity it is about ten times cheaper than even compressed memory.

The opportunity half: the authors measured how recently seven large applications touched their memory. On average, 35% of allocated memory had not been touched in the last five minutes — with enormous variance, from 19% cold (a cache service, almost everything hot) to 62% cold (the Web application). Cold memory in DRAM is money parked in the wrong asset.

There is also a second, less obvious pool of savings. The paper names the memory tax: memory consumed not by the application itself but by the machinery of running applications in a datacenter — logging, profiling, service discovery (the datacenter tax, 13% of server memory), plus the routing and proxy sidecars of microservice architectures (the microservice tax, 7% more). One fifth of fleet memory pays this tax, and most of it has looser performance requirements than application memory — an ideal first target.

Offloading means moving cold pages out of DRAM into a cheaper backend and faulting them back on access. Doing this transparently — in the kernel, with no application changes — is the only approach that scales to thousands of diverse workloads. The question the paper answers is the control question: how much can each container be squeezed, on which backend, before the application suffers?

What people did before, and where it broke

The closest prior system is Google’s fleet-wide zswap deployment (the paper calls it g-swap). It compresses cold pages into a RAM pool and controls aggressiveness with a target promotion rate: keep pages-swapped-back-per- second below a threshold chosen by offline profiling plus machine learning. It was the proof that kernel-driven offloading works at datacenter scale. Three limits remained.

One backend. g-swap supports only compressed memory. But compression is hostage to the data: Meta’s advertising models store quantized byte-encoded values that compress at just 1.3–1.4×, making a compressed pool nearly pointless — while an SSD stores them at a tenth of the cost. A real fleet needs heterogeneous backends, and the backends differ wildly: the 90th- percentile read from compressed memory takes about 40 microseconds, while SSD read latency across Meta’s generations spans 470 microseconds to 9.3 milliseconds — a 20× spread within one fleet.

Offline profiling. Per-application profiling does not scale to thousands of services that change daily.

The proxy metric lies. A promotion rate counts events; it does not measure harm. The same rate that is catastrophic on a slow SSD is harmless on a fast one. Worse, the paper demonstrates the metric inverting: under TMO, a host with a faster SSD sustained a higher swap-in rate — and processed more requests per second, because aggressive offloading freed memory the application put to use. A threshold on promotion rate would have forbidden exactly the behavior that improved performance.

There was also a problem inside Linux itself. The kernel’s reclaim algorithm, shaped in the era of spinning disks, treated swap as an emergency valve and skewed heavily toward evicting file cache first — it would throw away a workload’s actively-used file pages long before touching cold anonymous memory. Offloading needed reclaim to be rebalanced, not just triggered.

The TMO control loop

  1. Workloads

    Unmodified applications in containers; also the sidecar containers paying the memory tax.

  2. PSI (kernel) new

    Measures, per container, the fraction of time lost stalled on memory, CPU, and I/O.

  3. Senpai (userspace) new

    Every six seconds, asks the kernel to reclaim a small amount from each container — smaller as pressure nears the threshold.

  4. Kernel reclaim new

    Picks the coldest pages, balancing file cache against anonymous memory by refault and swap-in rates.

  5. Backends

    Compressed RAM pool (zswap) or SSD swap; file pages simply drop back to the filesystem.

The feedback signal (PSI) and the actuator policy (Senpai plus the rebalanced reclaim) are the contributions. PSI and the reclaim changes are upstream Linux; Senpai is open source.

The idea

PSI: measure the harm itself

Pressure stall information (PSI) is the paper’s foundational contribution: a kernel mechanism that reports, for each process, container, or the whole machine, the share of potential work lost while stalled waiting for a resource — computed separately for memory, CPU, and I/O.

For memory, PSI counts time in exactly three situations that only occur under shortage: a process forced to reclaim pages while allocating; a process waiting on I/O for a refault — a fault on a page that was resident recently and got evicted; and a process blocked reading a page back from swap. Two aggregates are kept: some (at least one process in the container is stalled — a latency signal) and full (all are stalled — a productivity-collapse signal). TMO’s control loop uses some.

The metric’s power is what it automatically accounts for. A slow SSD makes each stall longer, so pressure rises — the device’s performance is priced in. An application that touches offloaded pages often stalls often — its sensitivity is priced in. An application with internal parallelism hides stalls — priced in. None of this needs profiling, models, or device tables. The cost is a little bookkeeping at context switches — negligible in production — and PSI now ships enabled by default in major Linux distributions, including Android.

Senpai: hold pressure at “barely measurable”

Senpai, a userspace agent, turns the signal into action. Every six seconds, for every container, it computes how much memory to ask the kernel to reclaim:

reclaim = current_memory × 0.0005 × max(0, 1 − PSI_some / 0.1%)

Read it from the right. The threshold is 0.1% — one thousandth of runtime lost to memory stalls. If a container’s pressure exceeds that, reclaim stops entirely; the workload gets room. Far below it, Senpai trims 0.05% of the container’s footprint per cycle, capped at 1% per period. As pressure approaches the threshold, the steps shrink toward zero. The equilibrium is a container running with the minimum memory it needs, plus a whisper of deliberate, harmless pressure to prove it.

Two design details carry production weight. Squeezing is gradual (full contraction takes minutes) but expansion is instant — a growing workload is never blocked; Senpai originally adjusted cgroup memory limits, but a limit can block a rapidly growing container, so the authors added a stateless memory.reclaim file to the kernel instead: reclaim exactly this much, hold nothing. And Senpai watches I/O pressure too, because offloading’s harm can arrive sideways — through a busier SSD — rather than as memory stalls. It also throttles offload writes to about 1 megabyte per second per host, protecting SSD write endurance. The reclaim work costs 0.05% of fleet CPU cycles.

What to offload: fix the kernel’s old bias

Senpai decides how much; the kernel’s reclaim algorithm decides which pages, using its existing least-recently-used lists — cheap and battle-tested. But the historic file-cache bias had to go. The authors added non-resident cache tracking: when a file page is evicted, a per-container counter value is stored in a shadow entry; on a later fault, the reuse distance tells the kernel whether this was a refault of recently-resident data (working set!) or a first touch. Reclaim now takes file cache alone until refaults appear, then balances file cache against anonymous memory by comparing the refault rate with the swap-in rate — minimizing total paging. These changes were upstreamed into Linux.

The backend itself is per-application, chosen by data compressibility: zswap (compression with zstd) for compressible workloads, SSD swap for the rest. Senpai needs no reconfiguration either way — a slower backend produces more pressure per offloaded page, and the loop backs off by itself.

Senpai squeezes one Web container

PSI = the container's memory pressure (share of time lost to memory stalls, 'some' variant). Threshold = 0.1%, the production setting. Cycle = one six-second Senpai period. Numbers inside the trace are illustrative; the formula, thresholds, and behaviors are the paper's.

Step 1 of 6

Comfortable and wasteful

The container holds 40 GB. Pressure reads 0.00% — no process ever stalls on memory. That comfort is information: some of those pages are cold, and the kernel will find them. Senpai requests the standard trim: 0.05% of the footprint, about 20 MB.

footprint 40 GB | PSI 0.00% (threshold 0.1%)
reclaim = 40 GB × 0.0005 × (1 − 0) = 20 MB

Why it works

Because PSI counts only stall time from qualifying memory events, it is a direct measurement of harm — not a proxy like swap-in counts that must be reinterpreted per device and per application. → Because harm is measured where it happens, one global threshold (0.1%) transfers across thousands of applications and a 20×-latency spread of backends: slow hardware raises pressure faster and the loop backs off by itself. → Because the squeeze is proactive but gentle — trims of 0.05% every six seconds, shrinking near the threshold, with instant release on growth — the system discovers each container’s true working set without ever gating an allocation. → Because reclaim balances file cache against anonymous memory using refault evidence rather than the old file-first bias, both kinds of cold memory are offloaded and total paging is minimized. → Therefore the fleet runs with DRAM sized near the sum of true working sets instead of allocated footprints — 20–32% smaller — while user-facing services hold their latency targets.

What it costs

  • A thousandth of runtime, on purpose. Steady-state operation keeps every container slightly memory-starved; that whisper of stall time is the price of knowing the working set. The reclaim machinery itself costs 0.05% of CPU cycles.
  • SSD wear is a real budget. Offload writes are throttled to about 1 MB/s per host — a hard constraint that caps how much anonymous memory can churn through an SSD backend.
  • Backend choice is still manual. Whether an application gets zswap or SSD swap is decided by humans looking at compressibility. The authors name the fix — a kernel-managed hierarchy (warm pages compressed, cold pages to SSD, NVM and CXL tiers later) — as future work.
  • The knobs were tuned empirically. The global threshold and ratio came from iterative production experiments; the paper shows a slightly more aggressive configuration saving more memory but visibly cutting Web’s request rate — through file-cache evictions of application bytecode, an I/O-side effect a memory-only view would miss.
  • Reaction to contraction is slow. Squeezing takes minutes by design; TMO harvests steady-state waste, it does not respond to emergencies — that remains the job of out-of-memory killers.

The evaluation

TMO’s evaluation is a production report, not a testbed: more than a year running across millions of servers, with A/B load tests on tens of production hosts for the detailed studies.

What TMO saved, and against what

PropertyPrior practiceTMO in production
Fleet-wide memory savings
Per-application savings by backendcompressed memory or nothing
Memory-bound Web hosts
Control metric under hardware diversity
Production measurements at Meta: over a year, millions of servers; A/B studies on production Skylake 64 GB hosts running the Web application under load-testing.Underlined values explain themselves when clicked.

Two deployment stories are worth keeping. The rollout order was tax-memory first (relaxed SLAs), then file-cache-only mode fleet-wide, then full swap for the largest applications — each step de-risking the next. And the observability was worth money on its own: PSI-driven accounting exposed one application repeatedly re-extracting a self-extracting binary into file cache; extracting it once ahead of time cut that application’s memory by 70% — a finding conventional accounting missed because it discounts file cache entirely.

Check your understanding

  1. 1. Why does TMO reject the swap-in ("promotion") rate as its control signal, even though it is easy to measure?

  2. 2. A container’s memory PSI (some) reads 0.0% for days. What does TMO conclude, and do?

  3. 3. Predict: TMO is deployed unchanged on hosts whose SSD is 10× slower than the fleet average. What happens to that host’s offloading behavior?

  4. 4. Why did TMO need to change the Linux kernel’s reclaim algorithm rather than just trigger it more often?

Related papers on Memory Systems & Caches

See all 118 →