Skip to content

Commit b832def

Browse files
committed
add separate allocator for MiriMachine
1 parent e053b0b commit b832def

File tree

8 files changed

+409
-30
lines changed

8 files changed

+409
-30
lines changed

miri-script/src/commands.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::BTreeMap;
1+
use std::collections::HashMap;
22
use std::ffi::{OsStr, OsString};
33
use std::fmt::Write as _;
44
use std::fs::{self, File};
@@ -489,9 +489,7 @@ impl Command {
489489
sh.read_dir(benches_dir)?
490490
.into_iter()
491491
.filter(|path| path.is_dir())
492-
// Only keep the basename: that matches the usage with a manual bench list,
493-
// and it ensure the path concatenations below work as intended.
494-
.map(|path| path.file_name().unwrap().to_owned().into_string().unwrap())
492+
.map(|path| path.into_os_string().into_string().unwrap())
495493
.collect()
496494
} else {
497495
benches.into_iter().collect()
@@ -532,16 +530,14 @@ impl Command {
532530
stddev: f64,
533531
}
534532

535-
let gather_results = || -> Result<BTreeMap<&str, BenchResult>> {
533+
let gather_results = || -> Result<HashMap<&str, BenchResult>> {
536534
let baseline_temp_dir = results_json_dir.unwrap();
537-
let mut results = BTreeMap::new();
535+
let mut results = HashMap::new();
538536
for bench in &benches {
539-
let result = File::open(path!(baseline_temp_dir / format!("{bench}.bench.json")))
540-
.context("failed to read hyperfine JSON")?;
541-
let mut result: serde_json::Value = serde_json::from_reader(BufReader::new(result))
542-
.context("failed to parse hyperfine JSON")?;
543-
let result: BenchResult = serde_json::from_value(result["results"][0].take())
544-
.context("failed to interpret hyperfine JSON")?;
537+
let result = File::open(path!(baseline_temp_dir / format!("{bench}.bench.json")))?;
538+
let mut result: serde_json::Value =
539+
serde_json::from_reader(BufReader::new(result))?;
540+
let result: BenchResult = serde_json::from_value(result["results"][0].take())?;
545541
results.insert(bench as &str, result);
546542
}
547543
Ok(results)
@@ -553,15 +549,15 @@ impl Command {
553549
serde_json::to_writer_pretty(BufWriter::new(baseline), &results)?;
554550
} else if let Some(baseline_file) = load_baseline {
555551
let new_results = gather_results()?;
556-
let baseline_results: BTreeMap<String, BenchResult> = {
552+
let baseline_results: HashMap<String, BenchResult> = {
557553
let f = File::open(baseline_file)?;
558554
serde_json::from_reader(BufReader::new(f))?
559555
};
560556
println!(
561557
"Comparison with baseline (relative speed, lower is better for the new results):"
562558
);
563-
for (bench, new_result) in new_results {
564-
let Some(baseline_result) = baseline_results.get(bench) else { continue };
559+
for (bench, new_result) in new_results.iter() {
560+
let Some(baseline_result) = baseline_results.get(*bench) else { continue };
565561

566562
// Compare results (inspired by hyperfine)
567563
let ratio = new_result.mean / baseline_result.mean;

src/alloc_bytes.rs renamed to src/alloc/alloc_bytes.rs

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@ use std::{alloc, slice};
55
use rustc_abi::{Align, Size};
66
use rustc_middle::mir::interpret::AllocBytes;
77

8+
#[cfg(target_os = "linux")]
9+
use crate::alloc::isolated_alloc::IsolatedAlloc;
810
use crate::helpers::ToU64 as _;
911

12+
#[derive(Clone, Copy, Debug)]
13+
pub enum MiriAllocParams {
14+
Global,
15+
Isolated,
16+
}
17+
1018
/// Allocation bytes that explicitly handle the layout of the data they're storing.
1119
/// This is necessary to interface with native code that accesses the program store in Miri.
1220
#[derive(Debug)]
@@ -18,13 +26,16 @@ pub struct MiriAllocBytes {
1826
/// * If `self.layout.size() == 0`, then `self.ptr` was allocated with the equivalent layout with size 1.
1927
/// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
2028
ptr: *mut u8,
29+
/// Whether this instance of `MiriAllocBytes` had its allocation created by calling `alloc::alloc()`
30+
/// (`Global`) or the discrete allocator (`Isolated`)
31+
params: MiriAllocParams,
2132
}
2233

2334
impl Clone for MiriAllocBytes {
2435
fn clone(&self) -> Self {
2536
let bytes: Cow<'_, [u8]> = Cow::Borrowed(self);
2637
let align = Align::from_bytes(self.layout.align().to_u64()).unwrap();
27-
MiriAllocBytes::from_bytes(bytes, align)
38+
MiriAllocBytes::from_bytes(bytes, align, self.params)
2839
}
2940
}
3041

@@ -37,8 +48,23 @@ impl Drop for MiriAllocBytes {
3748
} else {
3849
self.layout
3950
};
51+
4052
// SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
41-
unsafe { alloc::dealloc(self.ptr, alloc_layout) }
53+
unsafe {
54+
match self.params {
55+
MiriAllocParams::Global => alloc::dealloc(self.ptr, alloc_layout),
56+
MiriAllocParams::Isolated => {
57+
#[cfg(target_os = "linux")]
58+
{
59+
IsolatedAlloc::dealloc(self.ptr, alloc_layout)
60+
}
61+
#[cfg(not(target_os = "linux"))]
62+
{
63+
unreachable!()
64+
}
65+
}
66+
}
67+
}
4268
}
4369
}
4470

@@ -67,6 +93,7 @@ impl MiriAllocBytes {
6793
fn alloc_with(
6894
size: u64,
6995
align: u64,
96+
params: MiriAllocParams,
7097
alloc_fn: impl FnOnce(Layout) -> *mut u8,
7198
) -> Result<MiriAllocBytes, ()> {
7299
let size = usize::try_from(size).map_err(|_| ())?;
@@ -80,19 +107,35 @@ impl MiriAllocBytes {
80107
Err(())
81108
} else {
82109
// SAFETY: All `MiriAllocBytes` invariants are fulfilled.
83-
Ok(Self { ptr, layout })
110+
Ok(Self { ptr, layout, params })
84111
}
85112
}
86113
}
87114

88115
impl AllocBytes for MiriAllocBytes {
89-
fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
116+
type AllocParams = MiriAllocParams;
117+
118+
fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align, params: MiriAllocParams) -> Self {
90119
let slice = slice.into();
91120
let size = slice.len();
92121
let align = align.bytes();
93122
// SAFETY: `alloc_fn` will only be used with `size != 0`.
94-
let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
95-
let alloc_bytes = MiriAllocBytes::alloc_with(size.to_u64(), align, alloc_fn)
123+
let alloc_fn = |layout| unsafe {
124+
match params {
125+
MiriAllocParams::Global => alloc::alloc(layout),
126+
MiriAllocParams::Isolated => {
127+
#[cfg(target_os = "linux")]
128+
{
129+
IsolatedAlloc::alloc(layout)
130+
}
131+
#[cfg(not(target_os = "linux"))]
132+
{
133+
unreachable!()
134+
}
135+
}
136+
}
137+
};
138+
let alloc_bytes = MiriAllocBytes::alloc_with(size.to_u64(), align, params, alloc_fn)
96139
.unwrap_or_else(|()| {
97140
panic!("Miri ran out of memory: cannot create allocation of {size} bytes")
98141
});
@@ -102,12 +145,26 @@ impl AllocBytes for MiriAllocBytes {
102145
alloc_bytes
103146
}
104147

105-
fn zeroed(size: Size, align: Align) -> Option<Self> {
148+
fn zeroed(size: Size, align: Align, params: MiriAllocParams) -> Option<Self> {
106149
let size = size.bytes();
107150
let align = align.bytes();
108151
// SAFETY: `alloc_fn` will only be used with `size != 0`.
109-
let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) };
110-
MiriAllocBytes::alloc_with(size, align, alloc_fn).ok()
152+
let alloc_fn = |layout| unsafe {
153+
match params {
154+
MiriAllocParams::Global => alloc::alloc_zeroed(layout),
155+
MiriAllocParams::Isolated => {
156+
#[cfg(target_os = "linux")]
157+
{
158+
IsolatedAlloc::alloc_zeroed(layout)
159+
}
160+
#[cfg(not(target_os = "linux"))]
161+
{
162+
unreachable!()
163+
}
164+
}
165+
}
166+
};
167+
MiriAllocBytes::alloc_with(size, align, params, alloc_fn).ok()
111168
}
112169

113170
fn as_mut_ptr(&mut self) -> *mut u8 {

0 commit comments

Comments
 (0)