Skip to content

cong-or/snarf

Repository files navigation

snarf

Cache-line false sharing linter for Rust structs.

snarf demo


Finds Rust structs where atomic or contended fields share a cache line with other fields. This is potential false sharing, not proven — snarf detects the layout but not runtime behavior, so you decide which fields are actually contended.

The Slowdown That Doesn't Show Up in Profiles — why this matters.


Install and run

cargo install cargo-snarf
cargo snarf

No output means no issues found. If snarf finds contended fields sharing a cache line, it prints a layout diagram and exits non-zero. In a workspace it discovers all crates automatically.

snarf requires nightly Rust to get exact type sizes via cargo +nightly build -Zprint-type-sizes. Install it:

rustup toolchain install nightly

CI

- name: Cache-line sanity check
  run: |
    rustup toolchain install nightly --profile minimal
    cargo install cargo-snarf && cargo snarf

For PR annotations without blocking:

- name: Cache-line annotations
  run: |
    rustup toolchain install nightly --profile minimal
    cargo install cargo-snarf && cargo snarf --format github --warn-only

This repo runs snarf on itself — see ci.yml.

Options

Flag What it does
--strict Warn on all multi-field cache lines, not just contended ones
--format json Machine-readable output
--format github GitHub Actions annotations on the PR diff
--warn-only Report issues but exit 0
--threshold N Minimum fields per line to warn (default: 2)
--line-size N Cache line size in bytes (default: 64, use 128 for Apple M-series)
--no-send-sync-check Warn even on !Send/!Sync structs (see below)
--color never No ANSI escape codes

By default snarf only warns when an Atomic*/Cell/RefCell/UnsafeCell field shares a cache line with other fields. Detection is recursive, so Option<AtomicU64> and Arc<Mutex<AtomicU64>> are both caught. --strict warns on all multi-field lines regardless.

Structs containing !Send or !Sync types (Rc, Cell, RefCell, raw pointers, lock guards) are automatically suppressed since they can't be shared across threads, making false sharing impossible. Suppressed structs print a note to stderr. Use --no-send-sync-check to disable this and warn on all structs.


How it works

Parses structs with syn, then gets exact type sizes and field offsets from cargo +nightly build -Zprint-type-sizes. This resolves all types (custom structs, enums, non-repr(C) layouts, niche-optimized Options) with no guessing.

  • All types resolved, including custom and cross-crate types
  • Non-repr(C) structs get exact field offsets from the compiler
  • Niche optimization (Option<&T>, Option<NonZeroU64>) handled correctly

Validation

The validation/ directory has a controlled experiment that correlates snarf's static warnings with real hardware cache-line contention measured by perf c2c. Two #[repr(C)] structs (one with co-located atomics, one with cache-line padding) are hammered from threads pinned to separate P-cores. The script runs snarf and perf c2c, then compares HITM event counts to snarf's warnings.

cd validation && ./run.sh   # requires sudo for perf c2c

Limitations

  • repr(packed) not yet supported
  • Type name collisions: if two modules define a type with the same name (e.g. a::Config and b::Config), only the first is used (a warning is printed)

Name

snarf — hacker slang: to grab data greedily.

License

MIT

Packages

 
 
 

Contributors