Memory tiering has two distinct parts. The mechanism moves a page to compressed memory, an SSD, or remote capacity and brings it back on a fault. The policy decides which page to move and whether likely future accesses justify prefetching it. Linux combines these parts in the kernel, which gives applications a mature swap path but makes new policy deployment slow and risky.

Google’s PageFlex separates them[1]. It keeps the fault handler, swap backend, cgroup controls, and ordinary application interface in Linux. It delegates non-critical reclamation and prefetch decisions to eBPF-assisted policy code and a user-space agent. This boundary avoids the two costs of earlier external pagers: userfaultfd can add more than 50% to a zswap refault, while a custom memory library requires application changes and replaces infrastructure already deployed across a fleet.

The objective is not to make page faults programmable. A fault is too latency-sensitive to cross into a policy daemon. PageFlex instead exposes events and state needed for decisions that can run asynchronously, then enforces batched hints through existing madvise operations. Policy can change quickly without moving the mechanism that must remain fast and compatible.

eBPF observes state without exporting every page

A paging policy needs more than a list of virtual addresses. It may consume allocation, free, swap-in, swap-out, access-bit, and periodic-scan events. It also needs per-page history such as an age, frequency, or weight. Copying that state to user space on every event would replace kernel rollout cost with memory bandwidth and context-switch cost.

PageFlex installs eBPF handlers at selected paging events. A policy subscribes only to signals it needs. Handlers update a small persistent field associated with each page and can aggregate state before user-space processing. Because the eBPF verifier constrains memory access and execution, policy code receives controlled access to kernel information rather than an unrestricted module interface.

Reclamation is expressed as a generic page weight. An LRU-like policy can use recency, LFU can use counters, and Hyperbolic caching can combine frequency and age. The user-space agent periodically receives candidates, orders them by the policy’s weight, and asks the kernel to reclaim a batch. Linux still performs the actual page transition and invokes the configured swap backend.

Prefetch policy follows the same split. Event handlers observe faults and access patterns; a user-space component detects trends and submits batched page-in hints. PageFlex reimplements Linux read-ahead and the Leap strided-access algorithm without altering the page-fault path. The paper reports 17 lines for Hyperbolic weight updates and 21 additional lines around borrowed Leap logic, illustrating that the interface is smaller than a complete pager.

PageFlex places a policy boundary beside the Linux paging mechanism. Kernel page events invoke verified eBPF handlers that update small per-page weights. A user-space agent ranks or predicts pages away from the fault path and returns batched madvise hints. Linux continues to execute reclaim, swap, and refault with the existing backend and unchanged application ABI. Original figure created for this article.

The distinction between observation and action matters for safety. A buggy ranking can choose poor victims and hurt performance, but it does not implement disk I/O, page-table repair, or the fault handler. Operators can replace policy code and preserve the mechanism they already test and monitor.

Equivalent policy establishes the overhead floor

Before claiming a better policy, PageFlex compares equivalent implementations. Redis and synthetic benchmarks using its LRU model ran at most 1% slower than a functionally equivalent in-kernel g-swap policy. A PageFlex implementation of Linux read-ahead improved performance by 76% over no prefetching on an SSD-like backend, close to the kernel implementation’s 82% improvement. When prefetching offered no benefit, supporting overhead was 0.8%.

The microsecond breakdown explains why retaining the kernel path is important. With zswap, a normal swap-in median was about 3.5 microseconds. A PageFlex prefetch hit was near 1.08 microseconds because the page was already resident. Misses remained close to the native major-fault path, with approximately 0.5 to 1 microsecond of additional latency attributed partly to eBPF. By contrast, an extra userfaultfd round trip can consume the entire benefit of a sophisticated victim policy.

Control work is measurable even when the application effect is small. Periodic page-table scans were 17% slower than the in-kernel g-swap implementation because eBPF executed for each observed page. Enforcing page actions from user space through syscalls took 14% longer. PageFlex batches up to 64 pages because reclamation is asynchronous; one syscall per page would make the boundary too expensive.

These figures should not be mixed. Less than 1% application slowdown describes the end-to-end result of an equivalent policy under evaluated workloads. Seventeen and 14% describe specific control operations. They can both be true because those operations are not the application’s dominant execution time. A scan-heavy workload or a much shorter policy interval could move the control cost onto the critical path.

Flexibility becomes useful only when the policy differs

The framework’s purpose is to run policies that the fleet kernel does not yet contain. On a synthetic workload designed to favor frequency, PageFlex LFU offloaded up to twice as much memory as LRU at the same slowdown. Hyperbolic caching produced up to 5% more memory savings on real workload traces. A PageFlex Leap implementation reduced refault rate for strided access by 75.4% relative to Linux read-ahead, which does not infer the stride.

PageFlex can also specialize within one process. A key/value service can give index, cache, and background regions different weights. Under the paper’s performance target, a workload-aware policy saved up to 36% more memory for one key/value workload and 6% more for GAPBS PageRank than LRU. This is the result a global kernel policy cannot easily obtain: page meaning comes from the application phase or region, but enforcement remains transparent to application loads and stores.

The upper numbers describe favorable structure, not guaranteed fleet savings. LFU wins when reuse frequency predicts the future; it can retain stale once-popular pages after a phase change. Stride prefetching wins when access distance is regular; it can waste I/O and memory on irregular traversal. Specialization increases the number of policy configurations an operator must validate and roll back.

Compatibility is an operational feature

Hyperscale paging systems already combine kernel reclaim, cgroup feedback, compressed memory, SSD swap, metrics, and SLO controllers. Replacing the mechanism would require retesting failure handling and every backend. PageFlex’s ABI-compatible design lets an unmodified process continue to fault and reclaim through Linux. A policy can be deployed to a cgroup or memory region and withdrawn without relinking the service.

This also narrows the failure domain. If the user-space agent is late, reclamation decisions become stale rather than making page faults wait for it. If an eBPF handler fails verification, it never loads. Existing kernel fallback remains available. The design does not eliminate policy-induced outages, but it gives them a different shape from memory-corruption bugs in an unrestricted module.

The model still relies on kernel hooks and a reserved per-page field. Upstream compatibility and rebasing remain engineering work. Verifier safety prevents arbitrary memory access but does not prove that a policy’s decisions are beneficial. Fleet admission needs budgets for handler time, scan frequency, map memory, syscall rate, and the number of distinct policies.

Where to place the policy boundary

PageFlex is useful when the mechanism is stable and expensive to replace, policy changes faster than the kernel, and decisions tolerate batching. Proactive reclamation and prefetch meet those conditions. Demand faults, page-table updates, and swap-device completion do not; they stay in the kernel.

The same rule applies beyond paging. Storage placement, network routing, and accelerator scheduling often have a fast mechanism and a slower optimizer. Moving only the optimizer to a flexible environment preserves a tested data path. The interface must expose enough state to make a better decision without streaming the entire data path across the boundary.

An operator evaluating PageFlex should first reproduce an equivalent policy and measure application slowdown, fault latency, scan CPU, syscall rate, and memory used for metadata. Only then should a new policy be compared at the same application SLO, not the same offload percentage. A policy that saves more memory by causing more expensive refaults is not an efficiency gain.

The reusable contribution is therefore the delegation line. PageFlex keeps the Linux mechanism and application contract, uses eBPF for bounded in-kernel observation, and moves complex ranking to code that can evolve faster. Its results show that this line can keep end-to-end overhead under 1% for equivalent policies while making specialized policies practical. They also show where the bill remains: every scan, metadata update, batch, and mistaken prediction must still fit the workload’s performance budget.

This article is an editorial analysis by Silicon & Systems. It restates the architecture, measurements, and limits in our own words. No source sentence, table, or figure is reproduced; the figure was created for this article. The paper is available from the USENIX ATC 2025 presentation page. Copyright remains with the authors, 2025.