Skip to content

Commit 321f6f3

Browse files
authored
Merge pull request #1815 from o1-labs/dw/move-alloc-test
Vendor: move alloc-test into mina-rust monorepo
2 parents 57071d8 + c544ec6 commit 321f6f3

File tree

16 files changed

+940
-2
lines changed

16 files changed

+940
-2
lines changed

.github/workflows/tests.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ jobs:
283283
--exclude transaction_fuzzer \
284284
--exclude mina-archive-breadcrumb-compare \
285285
--exclude webrtc-sniffer
286+
# --exclude alloc-test
286287
# --exclude mina-tree
287288
# --exclude redux-rs
288289
# --exclude vrf

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3131

3232
### Changes
3333

34+
- **Dependencies**: vendor alloc-test into `vendor/alloc-test` to centralize all
35+
code in the monorepo ([#1815](https://github.com/o1-labs/mina-rust/pull/1815))
3436
- **Dependencies**: vendor redux-rs into `vendor/redux` to centralize all code
3537
in the monorepo ([#1814](https://github.com/o1-labs/mina-rust/pull/1814))
3638
- **Build System**: enforce GNU sed on macOS, require `brew install gnu-sed`

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ members = [
2727
"tools/ledger-tool",
2828
"tools/transport",
2929
"tools/webrtc-sniffer",
30+
"vendor/alloc-test",
3031
"vendor/redux",
3132
"vendor/salsa-simple",
3233
"vrf",
@@ -42,7 +43,7 @@ indexing_slicing = "warn"
4243
[workspace.dependencies]
4344
aes = "0.8"
4445
aes-gcm = "0.10.3"
45-
alloc-test = { git = "https://github.com/openmina/alloc-test.git" }
46+
alloc-test = { path = "vendor/alloc-test" }
4647
anyhow = "1.0.81"
4748
argon2 = { version = "0.5.3", features = ["std"] }
4849
ark-ec = { version = "0.5.0", features = ["std"] }

vendor/alloc-test/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "alloc-test"
3+
version = "0.1.1"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
clap = { version = "4.0.18", features = ["derive", "env"], optional = true }
10+
derive_builder = "0.11.2"
11+
derive_more = { version = "0.99.17", features = [
12+
"display",
13+
], default-features = false }
14+
num = "0.4.0"
15+
serde = { version = "1.0.146", features = ["derive"] }
16+
serde_json = { version = "1.0", optional = true }
17+
thiserror = "1.0.37"
18+
toml = { version = "0.5.9", optional = true }
19+
wasm-bindgen = "0.2.83"
20+
wasm-bindgen-test = { version = "0.3.33", optional = true }
21+
22+
[features]
23+
default = ["benchmark"]
24+
benchmark = ["dep:clap", "dep:toml", "dep:serde_json", "dep:wasm-bindgen-test"]
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use std::alloc::{GlobalAlloc, Layout};
2+
3+
#[derive(Debug, Default)]
4+
pub struct TracingAllocator<H: 'static, A>(A, H)
5+
where
6+
A: GlobalAlloc;
7+
8+
impl<H, A> TracingAllocator<H, A>
9+
where
10+
A: GlobalAlloc,
11+
{
12+
pub const fn new(hooks: H, allocator: A) -> Self {
13+
TracingAllocator(allocator, hooks)
14+
}
15+
}
16+
17+
// pub const fn default_tracing_allocator() -> TracingAllocator<MemoryTracingHooks, System> {
18+
// TracingAllocator(System, MemoryTracingHooks)
19+
// }
20+
21+
unsafe impl<H, A> GlobalAlloc for TracingAllocator<H, A>
22+
where
23+
A: GlobalAlloc,
24+
H: AllocHooks,
25+
{
26+
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
27+
let size = layout.size();
28+
let align = layout.align();
29+
let pointer = self.0.alloc(layout);
30+
self.1.on_alloc(pointer, size, align);
31+
pointer
32+
}
33+
34+
unsafe fn dealloc(&self, pointer: *mut u8, layout: Layout) {
35+
let size = layout.size();
36+
let align = layout.align();
37+
self.0.dealloc(pointer, layout);
38+
self.1.on_dealloc(pointer, size, align);
39+
}
40+
41+
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
42+
let size = layout.size();
43+
let align = layout.align();
44+
let pointer = self.0.alloc_zeroed(layout);
45+
self.1.on_alloc_zeroed(pointer, size, align);
46+
pointer
47+
}
48+
49+
unsafe fn realloc(&self, old_pointer: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
50+
let old_size = layout.size();
51+
let align = layout.align();
52+
let new_pointer = self.0.realloc(old_pointer, layout, new_size);
53+
self.1
54+
.on_realloc(old_pointer, new_pointer, old_size, new_size, align);
55+
new_pointer
56+
}
57+
}
58+
59+
/// Trait for implementing allocation hooks in a tracing allocator.
60+
///
61+
/// # Safety
62+
///
63+
/// Implementors must ensure that hook methods do not allocate memory
64+
/// (to avoid infinite recursion) and are safe to call from any thread
65+
/// at any time during allocation operations.
66+
pub unsafe trait AllocHooks {
67+
fn on_alloc(&self, pointer: *mut u8, size: usize, align: usize);
68+
fn on_dealloc(&self, pointer: *mut u8, size: usize, align: usize);
69+
fn on_alloc_zeroed(&self, pointer: *mut u8, size: usize, align: usize);
70+
fn on_realloc(
71+
&self,
72+
old_pointer: *mut u8,
73+
new_pointer: *mut u8,
74+
old_size: usize,
75+
new_size: usize,
76+
align: usize,
77+
);
78+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
use super::measure::MemoryStats;
2+
3+
pub fn alloc_benchmark<F: FnOnce() -> O, O>(id: &str, f: F) -> MemoryStats {
4+
let (_, stats) = crate::alloc::measure::trace_allocs(f);
5+
log!("\nmemory allocation stats for `{id}`:\n{stats}");
6+
stats
7+
}
8+
9+
pub fn alloc_log_toml<F: Fn() -> O, O>(id: &str, f: F) -> MemoryStats {
10+
let (_, stats) = super::measure::trace_allocs(f);
11+
log!(
12+
"\nperformance stats for `{id}`:\n{stats}",
13+
stats = toml::to_string(&stats).unwrap()
14+
);
15+
stats
16+
}
17+
18+
#[macro_export]
19+
macro_rules! alloc_bench {
20+
($test:ident, $thresh:expr) => {
21+
$crate::threshold::check_threshold_with_args(
22+
|| $crate::alloc::benchmark::alloc_benchmark(stringify!($test), $test),
23+
"alloc_bench",
24+
stringify!($test),
25+
$thresh,
26+
)
27+
};
28+
}
29+
30+
#[macro_export]
31+
macro_rules! alloc_bench_cmp_with_toml {
32+
($test:ident $(,)?) => {{
33+
let value = $crate::alloc::benchmark::alloc_log_toml(stringify!($test), $test);
34+
Result::<
35+
$crate::alloc::measure::MemoryStats,
36+
$crate::threshold::CheckThresholdError<$crate::alloc::compare::AllocThresholdsError>,
37+
>::Ok(value)
38+
}};
39+
($test:ident, $toml:expr, $limits:expr $(,)?) => {{
40+
$crate::threshold::check_threshold_with_str(
41+
|| $crate::alloc::benchmark::alloc_benchmark(stringify!($test), $test),
42+
$toml,
43+
$limits,
44+
)
45+
}};
46+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use derive_builder::Builder;
2+
use thiserror::Error;
3+
4+
use super::measure::MemoryStats;
5+
use crate::threshold::{Threshold, ThresholdError, ThresholdFor};
6+
7+
/// Limits for each allocation statistics parameter.
8+
#[derive(Debug, Builder)]
9+
pub struct AllocThresholds {
10+
#[builder(default)]
11+
pub current: Threshold<usize>,
12+
#[builder(default)]
13+
pub peak: Threshold<usize>,
14+
#[builder(default)]
15+
pub total_size: Threshold<usize>,
16+
#[builder(default)]
17+
pub total_num: Threshold<usize>,
18+
#[builder(default)]
19+
pub reallocs: Threshold<usize>,
20+
}
21+
22+
#[derive(Debug, Error)]
23+
#[error("Allocation parameter `{param}`: {error}")]
24+
pub struct AllocThresholdsError {
25+
error: ThresholdError<usize>,
26+
param: &'static str,
27+
}
28+
29+
macro_rules! check {
30+
($f:ident, $l:expr, $v:expr, $r:expr) => {
31+
$l.$f
32+
.check(&$v.$f, &$r.$f)
33+
.map_err(|e| AllocThresholdsError {
34+
error: e,
35+
param: stringify!($f),
36+
})
37+
};
38+
}
39+
40+
impl ThresholdFor<MemoryStats> for AllocThresholds {
41+
type Error = AllocThresholdsError;
42+
43+
fn check_threshold(
44+
&self,
45+
value: &MemoryStats,
46+
ref_value: &MemoryStats,
47+
) -> Result<(), Self::Error> {
48+
self.check(value, ref_value)
49+
}
50+
}
51+
52+
impl AllocThresholds {
53+
pub fn check(
54+
&self,
55+
value: &MemoryStats,
56+
ref_value: &MemoryStats,
57+
) -> Result<(), AllocThresholdsError> {
58+
check!(current, self, value, ref_value)?;
59+
check!(peak, self, value, ref_value)?;
60+
check!(total_size, self, value, ref_value)?;
61+
check!(total_num, self, value, ref_value)?;
62+
check!(reallocs, self, value, ref_value)?;
63+
Ok(())
64+
}
65+
}
66+
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
71+
#[test]
72+
fn limits() {
73+
let rs = MemoryStats {
74+
current: 100,
75+
peak: 1000,
76+
total_size: 2000,
77+
total_num: 100,
78+
reallocs: 0,
79+
};
80+
let vs = MemoryStats {
81+
current: 110,
82+
peak: 1100,
83+
total_size: 2200,
84+
total_num: 110,
85+
reallocs: 1,
86+
};
87+
88+
let ls = AllocThresholdsBuilder::default().build().unwrap();
89+
assert!(ls.check_threshold(&rs, &rs).is_ok());
90+
assert!(ls.check_threshold(&vs, &rs).is_ok());
91+
92+
let ls = AllocThresholdsBuilder::default()
93+
.current(Threshold::Cap(1))
94+
.build()
95+
.unwrap();
96+
let r = ls.check(&vs, &rs);
97+
assert!(r.unwrap_err().param == "current");
98+
99+
let ls = AllocThresholdsBuilder::default()
100+
.reallocs(Threshold::Cap(0))
101+
.build()
102+
.unwrap();
103+
let r = ls.check(&vs, &rs);
104+
assert!(r.unwrap_err().param == "reallocs");
105+
}
106+
}

0 commit comments

Comments
 (0)