Skip to content

Commit 6ba60e9

Browse files
committed
ci: custom global allocator for benchmarks (#3776)
Use a custom global allocator for benchmarks. Will hopefully fix the wild variance in many benchmarks that we've been seeing, which I believe is caused by unpredictable behavior in the system allocator.
1 parent ae6654f commit 6ba60e9

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

tasks/benchmark/src/lib.rs

+38
Original file line numberDiff line numberDiff line change
@@ -1 +1,39 @@
1+
use std::alloc::{GlobalAlloc, Layout, System};
2+
13
pub use criterion::*;
4+
5+
#[global_allocator]
6+
static GLOBAL: NeverGrowInPlaceAllocator = NeverGrowInPlaceAllocator;
7+
8+
/// Global allocator for use in benchmarks.
9+
///
10+
/// A thin wrapper around Rust's default [`System`] allocator. It passes through `alloc`
11+
/// and `dealloc` methods to [`System`], but does not implement [`GlobalAlloc::realloc`].
12+
///
13+
/// Rationale for this is:
14+
///
15+
/// `realloc` for default [`System`] allocator calls `libc::realloc`, which may either:
16+
/// 1. allow the allocation to grow in place. or
17+
/// 2. create a new allocation, and copy memory from old allocation to the new one.
18+
///
19+
/// Whether allocations can grow in place or not depends on the state of the operating system's
20+
/// memory tables, and so is inherently non-deterministic. Using default `System` allocator
21+
/// therefore produces large and unpredictable variance in benchmarks.
22+
///
23+
/// By not providing a `realloc` method, this custom allocator delegates to the default
24+
/// [`GlobalAlloc::realloc`] implementation which *never* grows in place.
25+
/// It therefore represents the "worse case scenario" for memory allocation performance.
26+
/// This behavior is consistent and predictable, and therefore stabilizes benchmark results.
27+
pub struct NeverGrowInPlaceAllocator;
28+
29+
/// SAFETY: Methods simply delegate to `System` allocator
30+
#[allow(unsafe_code, clippy::undocumented_unsafe_blocks)]
31+
unsafe impl GlobalAlloc for NeverGrowInPlaceAllocator {
32+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
33+
System.alloc(layout)
34+
}
35+
36+
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
37+
System.dealloc(ptr, layout);
38+
}
39+
}

0 commit comments

Comments
 (0)