https://github.com/e2b-dev/mem-bench
Memory Benchmark
https://github.com/e2b-dev/mem-bench
Last synced: 30 days ago
JSON representation
Memory Benchmark
- Host: GitHub
- URL: https://github.com/e2b-dev/mem-bench
- Owner: e2b-dev
- Created: 2026-04-15T16:20:01.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-17T09:19:23.000Z (3 months ago)
- Last Synced: 2026-06-15T05:35:04.744Z (30 days ago)
- Language: Rust
- Size: 26.4 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# mem-bench
Linux memory benchmark suite measuring the throughput of various memory-copy
mechanisms and the latency of page faults across different memory backings.
All benchmarks are built on [Criterion](https://github.com/bheisler/criterion.rs)
and produce HTML reports with throughput plots and cross-run regression detection.
---
## Benchmark suites
### `memcpy` — copy throughput
Measures how fast data can be moved between memory regions using five different
kernel/userspace mechanisms. Each benchmark is parameterised over **copy size**
and, where applicable, **page size** (standard 4 KiB vs huge 2 MiB).
| Benchmark | Source | Destination | Mechanism |
|---|---|---|---|
| `process_vm_readv` | child process mmap | local mmap | `process_vm_readv(2)` |
| `mmap_to_file` | anonymous mmap | regular file | `pwrite(2)` |
| `mmap_to_mmap` | anonymous mmap | anonymous mmap | `memcpy` |
| `fd_to_fd` | regular file | regular file | `sendfile(2)` |
| `memfd_to_mmap` | memfd | anonymous mmap | `pread(2)` |
**Sizes tested** (default): 4 KiB, 64 KiB, 1 MiB, 16 MiB, 256 MiB, 1 GiB,
4 GiB, 16 GiB, 30 GiB.
**Huge page variants** are available for all benchmarks except `fd_to_fd`
(file page-cache always uses regular pages). Huge page benchmarks skip sizes
below 16 MiB (the first multiple of the 2 MiB huge-page size in the list).
**`process_vm_readv`** forks a child process that allocates the source region
and then sleeps; the parent reads from it across the process boundary. The child
is killed and reaped at the end of each benchmark case.
**`mmap_to_file` / `fd_to_fd`** create files on the filesystem pointed to by
`BENCH_DIR` (see [Configuration](#configuration)) so they reflect real
filesystem behaviour rather than tmpfs.
---
### `page_fault` — page-fault latency
Measures the time to fault in a fixed number of pages (`N_FAULT_PAGES = 128`)
after `MADV_DONTNEED` strips them from the process's page table. The
`MADV_DONTNEED` call is outside the timed region; only the subsequent page
accesses are measured.
`write_volatile` is used (rather than a read) so that:
- anonymous accesses allocate a real page instead of mapping the shared zero-page;
- file/memfd accesses trigger a copy-on-write fault from the page cache.
Parameterised over **backing** × **page size**:
| Backing | Standard (4 KiB) | Huge (2 MiB) |
|---|---|---|
| `anon` — anonymous private pages | ✓ | ✓ |
| `file` — regular on-disk file (`BENCH_DIR`) | ✓ | — |
| `memfd` — `memfd_create` / tmpfs | ✓ | ✓ |
`file + huge` is not supported: mapping a plain file with `MAP_HUGETLB`
requires the file to reside on a hugetlbfs mount.
**Throughput** is reported as page faults per second (criterion label:
`elements/s`). Invert to get average latency per fault.
Region sizes:
- Standard: 128 × 4 KiB = 512 KiB
- Huge: 128 × 2 MiB = 256 MiB (requires 256 MiB of pre-allocated huge pages)
---
## Running
```sh
# Run both suites
cargo bench
# Run a single suite
cargo bench --bench memcpy
cargo bench --bench page_fault
# Filter by benchmark group or case (criterion name filter)
cargo bench --bench memcpy -- mmap_to_mmap
cargo bench -- "page_fault/memfd/2m"
```
HTML reports are written to `target/criterion/report/index.html` and updated
automatically on every run, including cross-run regression comparisons.
```sh
xdg-open target/criterion/report/index.html
```
---
## Configuration
All options are set via environment variables.
### `BENCH_DIR`
Directory used for **real on-disk files** (`mmap_to_file`, `fd_to_fd`,
`page_fault/file`). Defaults to the current working directory.
Set this to a mount point to benchmark a specific filesystem:
```sh
BENCH_DIR=/mnt/nvme cargo bench --bench memcpy -- mmap_to_file
BENCH_DIR=/mnt/hdd cargo bench --bench memcpy -- fd_to_fd
```
Files are created as anonymous temporaries (unlinked immediately) and cleaned
up automatically.
### `BENCH_SIZE` *(memcpy suite only)*
Restrict the `memcpy` suite to one or more copy sizes instead of sweeping all
sizes. Accepts a comma-separated list of values; each value is either a raw byte
count or a number with a `KB`, `MB`, or `GB` suffix.
```sh
BENCH_SIZE=1GB cargo bench --bench memcpy
BENCH_SIZE=256MB,1GB,4GB cargo bench --bench memcpy
BENCH_SIZE=256MB cargo bench --bench memcpy -- mmap_to_mmap
BENCH_SIZE=4096 cargo bench --bench memcpy # raw bytes
```
### Huge pages
Huge-page benchmarks require 2 MiB huge pages to be pre-allocated in the
kernel's hugetlb pool. Check the current pool:
```sh
cat /proc/sys/vm/nr_hugepages # number of pre-allocated pages
cat /proc/meminfo | grep HugePages
```
Allocate enough pages (example: 512 pages = 1 GiB):
```sh
echo 512 | sudo tee /proc/sys/vm/nr_hugepages
```
For the largest `page_fault/huge` case (256 MiB) at least **128** pages are
needed. For the largest `memcpy` huge-page case (30 GiB source + destination)
at least **30720** pages are needed per mapping.
Huge-page benchmarks will `assert!`-fail at startup if the pool is exhausted.