ferrite

Userspace RAM tester for Linux with parallel test patterns and ECC monitoring

CLI Tool Active Updated 2d ago

ferrite is a userspace RAM tester for Linux, written in Rust. It allocates a large block of physical memory, locks it against swapping with mlock, and runs a battery of test patterns — solid bits, walking ones and zeros, checkerboard, and stuck-address — to surface stuck bits, address-line faults, and coupling errors without rebooting. It is not a replacement for memtest86+; it is the fast sanity check you run on a live machine when you suspect a bad stick of RAM.

The compiler is trying to delete your test

A memory tester's entire job is to write a value, read it back, and confirm it survived the round trip to the DRAM chips. To an optimizing compiler, that round trip has no observable effect — the straightforward code folds down to nothing. ferrite forces every access to happen: each write is a write_volatile, each read a read_volatile, so LLVM cannot elide the test.

Volatile guarantees the access occurs, not that it reaches the chips. A normal cached write can land in L1 and never travel to DRAM — you would be testing the cache, not the memory. So where the CPU supports it, ferrite fills using non-temporal AVX-512 streaming stores (_mm512_stream_si512), which bypass every cache level and write straight to main memory, then issues an _mm_sfence to drain the write-combining buffers before the verify pass reads the values back. Both phases are spread across cores with Rayon.

Keeping the AVX-512 path honest in CI

Development machines have AVX-512; CI runners frequently do not. To keep coverage meaningful on both, the fill and verify operations are split into three layers — a pure scalar implementation that coverage is measured against, the AVX-512 intrinsics that are excluded from coverage, and a thin dispatch layer that selects between them at runtime. CI exercises the scalar path, local runs exercise the SIMD path, and the behaviour they implement is identical.

Pinning memory against a hostile kernel

The kernel regards your pages as fair game: it will swap them to disk and migrate them around to defragment memory. mlock pins the allocation against swapping, but even locked pages can be relocated by the kernel's compaction machinery — and a relocation would invalidate every physical address ferrite had recorded. So for the duration of a run ferrite also sets vm.compact_unevictable_allowed to 0, restoring the original value on exit through an RAII guard, and re-checks the page mappings between passes to confirm nothing moved underneath it. Locking large regions needs privilege — root, a raised RLIMIT_MEMLOCK, or CAP_IPC_LOCK on the binary.

From a flipped bit to a failing DIMM

A useful failure report does not stop at 'bit 14 was wrong.' ferrite resolves the virtual address of every failing 64-bit word to its physical address through /proc/self/pagemap, then matches that physical address against the machine's memory topology — SMBIOS Type 17 records merged with the kernel's EDAC view — to name the actual module. Around each run it snapshots EDAC's correctable and uncorrectable ECC counters and reports the delta, and it classifies the bit errors it observes as stuck-bit or coupling faults. The result points at a part you can physically pull and replace, not just an address.

Output for humans and machines

When stdout is a terminal, ferrite renders an inline ratatui display with per-region heatmaps, live progress, and a scrolling log. Redirected or piped, it falls back to plain headless text, or — with --format json — streams newline-delimited JSON for scripting. Diagnostic logs and final results travel on separate channels, so machine-readable output is never contaminated by human-facing chatter.

Limitations

Userspace testing cannot reach all of RAM. The kernel, other running processes, and ferrite itself occupy memory the test can never touch, and any single run only covers what it managed to allocate and lock. For exhaustive, every-byte coverage you still want memtest86+ running from outside a live OS. ferrite makes the opposite trade: less than total coverage, in exchange for never having to reboot.

On this page