Skip to content

Commit 70ebd4e

Browse files
committed
WIP
Modified-by: Tomasz Andrzejak <andreiltd@gmail.com>
1 parent 8687504 commit 70ebd4e

File tree

14 files changed

+5709
-117
lines changed

14 files changed

+5709
-117
lines changed

Cargo.lock

Lines changed: 195 additions & 112 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ hyperlight-component-macro = { path = "src/hyperlight_component_macro", version
4848

4949
[workspace.lints.rust]
5050
unsafe_op_in_unsafe_fn = "deny"
51+
unexpected_cfgs = { level = "warn", check-cfg = [ 'cfg(loom)' ] }
5152

5253
# this will generate symbols for release builds
5354
# so is handy for debugging issues in release builds

src/hyperlight_common/Cargo.toml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,19 @@ Hyperlight's components common to host and guest.
1515
workspace = true
1616

1717
[dependencies]
18-
flatbuffers = { version = "25.9.23", default-features = false }
18+
arbitrary = {version = "1.4.2", optional = true, features = ["derive"]}
1919
anyhow = { version = "1.0.100", default-features = false }
20+
atomic_refcell = "0.1.13"
21+
bitflags = "2.10.0"
22+
bytemuck = { version = "1.24", features = ["derive"] }
23+
bytes = { version = "1", default-features = false }
24+
fixedbitset = { version = "0.5.7", default-features = false }
25+
flatbuffers = { version = "25.9.23", default-features = false }
2026
log = "0.4.29"
21-
tracing = { version = "0.1.43", optional = true }
22-
arbitrary = {version = "1.4.2", optional = true, features = ["derive"]}
27+
smallvec = "1.15.1"
2328
spin = "0.10.0"
2429
thiserror = { version = "2.0.16", default-features = false }
30+
tracing = { version = "0.1.43", optional = true }
2531

2632
[features]
2733
default = ["tracing"]
@@ -32,6 +38,19 @@ mem_profile = []
3238
std = ["thiserror/std", "log/std", "tracing/std"]
3339
init-paging = []
3440

41+
[dev-dependencies]
42+
criterion = "0.8.1"
43+
hyperlight-testing = { workspace = true }
44+
quickcheck = "1.0.3"
45+
rand = "0.9.2"
46+
47+
[target.'cfg(loom)'.dev-dependencies]
48+
loom = "0.7"
49+
3550
[lib]
3651
bench = false # see https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options
3752
doctest = false # reduce noise in test output
53+
54+
[[bench]]
55+
name = "buffer_pool"
56+
harness = false
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
use std::hint::black_box;
2+
3+
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
4+
use hyperlight_common::virtq::{BufferPool, BufferProvider};
5+
6+
// Helper to create a pool for benchmarking
7+
fn make_pool<const L: usize, const U: usize>(size: usize) -> BufferPool<L, U> {
8+
let base = 0x10000;
9+
BufferPool::<L, U>::new(base, size).unwrap()
10+
}
11+
12+
// Single allocation performance
13+
fn bench_alloc_single(c: &mut Criterion) {
14+
let mut group = c.benchmark_group("alloc_single");
15+
16+
for size in [64, 128, 256, 512, 1024, 1500, 4096].iter() {
17+
group.throughput(Throughput::Elements(1));
18+
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
19+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
20+
b.iter(|| {
21+
let alloc = pool.alloc(black_box(size)).unwrap();
22+
pool.dealloc(alloc).unwrap();
23+
});
24+
});
25+
}
26+
group.finish();
27+
}
28+
29+
// LIFO recycling
30+
fn bench_alloc_lifo(c: &mut Criterion) {
31+
let mut group = c.benchmark_group("alloc_lifo");
32+
33+
for size in [256, 1500, 4096].iter() {
34+
group.throughput(Throughput::Elements(100));
35+
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
36+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
37+
b.iter(|| {
38+
for _ in 0..100 {
39+
let alloc = pool.alloc(black_box(size)).unwrap();
40+
pool.dealloc(alloc).unwrap();
41+
}
42+
});
43+
});
44+
}
45+
group.finish();
46+
}
47+
48+
// Fragmented allocation worst case
49+
fn bench_alloc_fragmented(c: &mut Criterion) {
50+
let mut group = c.benchmark_group("alloc_fragmented");
51+
52+
group.bench_function("fragmented_256", |b| {
53+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
54+
55+
// Create fragmentation pattern: allocate many, free every other
56+
let mut allocations = Vec::new();
57+
for _ in 0..100 {
58+
allocations.push(pool.alloc(128).unwrap());
59+
}
60+
for i in (0..100).step_by(2) {
61+
pool.dealloc(allocations[i]).unwrap();
62+
}
63+
64+
b.iter(|| {
65+
let alloc = pool.alloc(black_box(256)).unwrap();
66+
pool.dealloc(alloc).unwrap();
67+
});
68+
});
69+
70+
group.finish();
71+
}
72+
73+
// Realloc operations
74+
fn bench_realloc(c: &mut Criterion) {
75+
let mut group = c.benchmark_group("realloc");
76+
77+
// In-place grow (same tier)
78+
group.bench_function("grow_inplace", |b| {
79+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
80+
b.iter(|| {
81+
let alloc = pool.alloc(256).unwrap();
82+
let grown = pool.resize(alloc, black_box(512)).unwrap();
83+
pool.dealloc(grown).unwrap();
84+
});
85+
});
86+
87+
// Relocate grow (cross tier)
88+
group.bench_function("grow_relocate", |b| {
89+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
90+
b.iter(|| {
91+
let alloc = pool.alloc(128).unwrap();
92+
// Block in-place growth
93+
let blocker = pool.alloc(256).unwrap();
94+
let grown = pool.resize(alloc, black_box(1500)).unwrap();
95+
pool.dealloc(grown).unwrap();
96+
pool.dealloc(blocker).unwrap();
97+
});
98+
});
99+
100+
// Shrink
101+
group.bench_function("shrink", |b| {
102+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
103+
b.iter(|| {
104+
let alloc = pool.alloc(1500).unwrap();
105+
let shrunk = pool.resize(alloc, black_box(256)).unwrap();
106+
pool.dealloc(shrunk).unwrap();
107+
});
108+
});
109+
110+
group.finish();
111+
}
112+
113+
// Free performance
114+
fn bench_free(c: &mut Criterion) {
115+
let mut group = c.benchmark_group("free");
116+
117+
for size in [256, 1500, 4096].iter() {
118+
group.bench_with_input(BenchmarkId::from_parameter(size), size, |b, &size| {
119+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
120+
b.iter(|| {
121+
let alloc = pool.alloc(size).unwrap();
122+
pool.dealloc(black_box(alloc)).unwrap();
123+
});
124+
});
125+
}
126+
127+
group.finish();
128+
}
129+
130+
// Cursor optimization
131+
fn bench_last_free_run(c: &mut Criterion) {
132+
let mut group = c.benchmark_group("last_free_run");
133+
134+
// With cursor optimization (LIFO)
135+
group.bench_function("lifo_pattern", |b| {
136+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
137+
b.iter(|| {
138+
let alloc = pool.alloc(256).unwrap();
139+
pool.dealloc(alloc).unwrap();
140+
let alloc2 = pool.alloc(black_box(256)).unwrap();
141+
pool.dealloc(alloc2).unwrap();
142+
});
143+
});
144+
145+
// Without cursor benefit (FIFO-like)
146+
group.bench_function("fifo_pattern", |b| {
147+
let pool = make_pool::<256, 4096>(4 * 1024 * 1024);
148+
let mut queue = Vec::new();
149+
150+
// Pre-fill queue
151+
for _ in 0..10 {
152+
queue.push(pool.alloc(256).unwrap());
153+
}
154+
155+
b.iter(|| {
156+
// FIFO: free oldest, allocate new
157+
let old = queue.remove(0);
158+
pool.dealloc(old).unwrap();
159+
queue.push(pool.alloc(black_box(256)).unwrap());
160+
});
161+
});
162+
163+
group.finish();
164+
}
165+
166+
criterion_group!(
167+
benches,
168+
bench_alloc_single,
169+
bench_alloc_lifo,
170+
bench_alloc_fragmented,
171+
bench_realloc,
172+
bench_free,
173+
bench_last_free_run,
174+
);
175+
176+
criterion_main!(benches);

src/hyperlight_common/src/flatbuffer_wrappers/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ pub fn estimate_flatbuffer_capacity(function_name: &str, args: &[ParameterValue]
272272
estimated_capacity.next_power_of_two()
273273
}
274274

275-
#[cfg(test)]
275+
#[cfg(all(test, not(miri)))]
276276
mod tests {
277277
use alloc::string::ToString;
278278
use alloc::vec;

src/hyperlight_common/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ limitations under the License.
1818
#![cfg_attr(not(any(test, debug_assertions)), warn(clippy::expect_used))]
1919
#![cfg_attr(not(any(test, debug_assertions)), warn(clippy::unwrap_used))]
2020
// We use Arbitrary during fuzzing, which requires std
21-
#![cfg_attr(not(feature = "fuzzing"), no_std)]
21+
#![cfg_attr(not(any(feature = "fuzzing", test, miri)), no_std)]
2222

2323
extern crate alloc;
2424

@@ -41,3 +41,6 @@ pub mod func;
4141
// cbindgen:ignore
4242
#[cfg(feature = "init-paging")]
4343
pub mod vmem;
44+
45+
/// cbindgen:ignore
46+
pub mod virtq;

0 commit comments

Comments
 (0)