Skip to main content
Back to timeline
arXivSource publication:

Storage prefetching stops guessing from file offsets: user-space policies cut app cold start by 5.3–26.3%

Synopsis

Linux readahead infers the next page from recent file offsets, which fails when accesses follow workload structure such as sparse startup reads, B-tree key-order traversal, or tensor-layout model loading. PredictIO separates prediction from execution: the kernel delivers observed accesses and application hints to user-space policies, which emit uniform page-range requests that a kernel backend validates, bounds, and issues as asynchronous prefetch I/O. Across application launch, SQLite range scans, and llama.cpp model loading, latency drops by 5.3–26.3%, scans speed up by up to 2.99, and model loading drops by 8.8–47.9%.

Source-provided article image: PredictIO: Decoupling Workload Prediction from OS-Controlled Storage Prefetching
Figure 2 · arXiv

Interpretation

Prefetching is split into two jobs: user-space policies decide which pages to fetch, and the kernel only validates and issues asynchronous reads. Previously Linux readahead kept both prediction and execution inside the kernel, inferring the next page only from recent file offsets and page-cache state. Across application launch, SQLite range scans, and llama.cpp model loading, one event path and request interface cut cold-start latency by 5.3–26.3%, sped up SQLite scans by up to 2.99, and reduced model-loading latency by 8.8–47.9%.

Policies plug in through two paths: an event path carries kernel observations or application hints into user space, and a request path carries predictions back to the kernel for execution. Previously, workload-aware prefetch logic was embedded in individual applications and coupled to their I/O paths, making policies hard to reuse across workloads and systems. The prototype observes page-level file accesses of unmodified applications with eBPF, receives hints from SQLite, LMDB, RocksDB, and llama.cpp over Unix-domain datagram sockets, and hands page ranges to kernel worker threads through a shared-memory ring.

The kernel backend executes predictions under bounds: it skips pages already cached, in flight, beyond end-of-file, or in sparse holes, then submits asynchronous reads under queue and in-flight-page limits. Previously, application-integrated prefetchers each reimplemented page-cache coordination, risking redundant I/O and unbounded bandwidth waste from inaccurate predictions. The same tree-aware policy, unchanged and paired with a lightweight adapter, cut latency by 34.3% on SQLite and 32.0% on LMDB; a migrated RocksDB readahead policy reached roughly 4.6 speedup on a long sequential scan while staying near baseline on YCSB-C point reads, preserving its selectivity.

Perspective

The mechanism targets block-backed filesystems, and the kernel backend depends on bmap() support; the current prototype runs on Linux 6.6.138 with Ext4. The demonstrated scope is application cold start, SQLite range scans, and llama.cpp model loading, across NVMe SSDs, SATA SSDs, and SATA HDDs. Migration benefit is workload-dependent: long sequential scans gain the most, while short scans and point reads gain little.

Gains depend on how much of a workload is predictable: Firefox and VSCode improve clearly, Shotcut gains less because metadata and per-file overheads dominate startup, and PyCharm spends more startup time in computation and runtime initialization. On HDDs, speculative reads compete directly with demand reads, so relative gains shrink as devices get slower; LLM loading gains little on HDDs because loading is dominated by sequential bandwidth rather than page-fault latency.