pub struct AlignedBump { /* private fields */ }Expand description
Bump arena exposing explicit per-allocation alignment.
Implementations§
Source§impl AlignedBump
impl AlignedBump
Sourcepub fn with_capacity(capacity: usize) -> Self
pub fn with_capacity(capacity: usize) -> Self
New arena with the given capacity. The backing buffer itself is
allocated 64-byte aligned so cache-line requests within
capacity always succeed.
Examples found in repository?
examples/sample_app.rs (line 206)
203fn aligned_price_scan() {
204 use subms_arena_allocator::AlignedBump;
205 println!("\n== aligned: cache-line scratch for a price scan ==");
206 let mut scratch = AlignedBump::with_capacity(1024);
207 let region = scratch.alloc_aligned(64, 64);
208 assert_eq!(region.as_ptr() as usize % 64, 0, "cache-line aligned");
209 for (i, b) in region.iter_mut().enumerate() {
210 *b = i as u8;
211 }
212 let checksum: u32 = region.iter().map(|&b| b as u32).sum();
213 println!(
214 " 64B aligned scratch, checksum {checksum}, used {}B",
215 scratch.used()
216 );
217 assert_eq!(checksum, (0..64u32).sum::<u32>());
218 scratch.reset();
219 assert_eq!(scratch.used(), 0);
220}More examples
examples/perf_features.rs (line 168)
52fn main() -> io::Result<()> {
53 let canon = SIZES[SIZES.len() - 1];
54
55 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
56 .join("..")
57 .join(".subms")
58 .join("features")
59 .join("rust.json");
60 let existing = std::fs::read_to_string(&path).unwrap_or_default();
61 let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
62 // Stamp the box these numbers came from. The bench runs wherever it is
63 // invoked, so an unstamped manifest is indistinguishable from a fleet
64 // capture; the renderer will not publish one it cannot attribute.
65 let (source, instance) = SubMsP99Source::from_env();
66 manifest.set_p99_source(source, instance.as_deref());
67
68 // ---------- typed: one Copy type, slot handles, reuse on free ----------
69 #[cfg(feature = "typed")]
70 {
71 use subms_arena_allocator::TypedArena;
72 let sweep: Vec<(usize, u64)> = SIZES
73 .iter()
74 .map(|&n| {
75 let mut arena: TypedArena<u64> = TypedArena::with_capacity(n);
76 let (p50, _) = run_p50_p99(n, |i| {
77 std::hint::black_box(arena.alloc(i as u64));
78 });
79 (n, p50)
80 })
81 .collect();
82 let (cat, reason) = classify_feature(&sweep, None, None);
83
84 let mut arena: TypedArena<u64> = TypedArena::with_capacity(canon);
85 let (_, alloc99) = run_p50_p99(canon, |i| {
86 std::hint::black_box(arena.alloc(i as u64));
87 });
88 // Every timed op here takes the slot the previous one freed, so the
89 // reuse path is what is measured rather than the append path.
90 let mut churn: TypedArena<u64> = TypedArena::with_capacity(2);
91 let (_, free99) = run_p50_p99(canon, |i| {
92 let slot = churn.alloc(i as u64);
93 churn.free(slot);
94 });
95 let mut p99 = BTreeMap::new();
96 p99.insert("alloc".to_string(), alloc99);
97 p99.insert("free".to_string(), free99);
98 manifest.set_feature("typed", cat, &p99, &reason);
99 }
100
101 // ---------- growable: a new chunk when the active one runs out ----------
102 #[cfg(feature = "growable")]
103 {
104 use subms_arena_allocator::GrowableBump;
105 let sweep: Vec<(usize, u64)> = SIZES
106 .iter()
107 .map(|&n| {
108 let mut a = GrowableBump::new();
109 let (p50, _) = run_p50_p99(n, |i| {
110 std::hint::black_box(a.alloc_copy(i as u64));
111 });
112 (n, p50)
113 })
114 .collect();
115 let (cat, reason) = classify_feature(&sweep, None, None);
116
117 let mut a = GrowableBump::new();
118 let (_, alloc99) = run_p50_p99(canon, |i| {
119 std::hint::black_box(a.alloc_copy(i as u64));
120 });
121 let mut filled = GrowableBump::new();
122 for i in 0..canon {
123 filled.alloc_copy(i as u64);
124 }
125 let (_, reset99) = run_p50_p99(1, |_| filled.reset());
126 let mut p99 = BTreeMap::new();
127 p99.insert("alloc".to_string(), alloc99);
128 p99.insert("reset".to_string(), reset99);
129 manifest.set_feature("growable", cat, &p99, &reason);
130 }
131
132 // ---------- stats: live counters on the alloc path ----------
133 #[cfg(feature = "stats")]
134 {
135 use subms_arena_allocator::StatsBump;
136 let sweep: Vec<(usize, u64)> = SIZES
137 .iter()
138 .map(|&n| {
139 let mut a = StatsBump::new();
140 let (p50, _) = run_p50_p99(n, |i| {
141 std::hint::black_box(a.alloc_copy(i as u64));
142 });
143 (n, p50)
144 })
145 .collect();
146 let (cat, reason) = classify_feature(&sweep, None, None);
147
148 let mut a = StatsBump::new();
149 let (_, alloc99) = run_p50_p99(canon, |i| {
150 std::hint::black_box(a.alloc_copy(i as u64));
151 });
152 let (_, snap99) = run_p50_p99(canon, |_| {
153 std::hint::black_box(a.stats());
154 });
155 let mut p99 = BTreeMap::new();
156 p99.insert("alloc".to_string(), alloc99);
157 p99.insert("stats".to_string(), snap99);
158 manifest.set_feature("stats", cat, &p99, &reason);
159 }
160
161 // ---------- aligned: explicit per-allocation alignment ----------
162 #[cfg(feature = "aligned")]
163 {
164 use subms_arena_allocator::AlignedBump;
165 let sweep: Vec<(usize, u64)> = SIZES
166 .iter()
167 .map(|&n| {
168 let mut a = AlignedBump::with_capacity(n * 16 + 4096);
169 let (p50, _) = run_p50_p99(n, |_| {
170 std::hint::black_box(a.alloc_aligned(8, 8).len());
171 });
172 (n, p50)
173 })
174 .collect();
175 let (cat, reason) = classify_feature(&sweep, None, None);
176
177 let mut a = AlignedBump::with_capacity(canon * 16 + 4096);
178 let (_, alloc99) = run_p50_p99(canon, |_| {
179 std::hint::black_box(a.alloc_aligned(8, 8).len());
180 });
181 let mut p99 = BTreeMap::new();
182 p99.insert("alloc_aligned".to_string(), alloc99);
183 manifest.set_feature("aligned", cat, &p99, &reason);
184 }
185
186 std::fs::create_dir_all(path.parent().unwrap())?;
187 std::fs::write(&path, manifest.to_json())?;
188 io::stdout().write_all(manifest.to_json().as_bytes())?;
189 Ok(())
190}Sourcepub fn alloc_aligned(&mut self, size: usize, align: usize) -> &mut [u8] ⓘ
pub fn alloc_aligned(&mut self, size: usize, align: usize) -> &mut [u8] ⓘ
Allocate size bytes aligned to align (must be a power of two).
Panics if the request doesn’t fit.
Examples found in repository?
examples/sample_app.rs (line 207)
203fn aligned_price_scan() {
204 use subms_arena_allocator::AlignedBump;
205 println!("\n== aligned: cache-line scratch for a price scan ==");
206 let mut scratch = AlignedBump::with_capacity(1024);
207 let region = scratch.alloc_aligned(64, 64);
208 assert_eq!(region.as_ptr() as usize % 64, 0, "cache-line aligned");
209 for (i, b) in region.iter_mut().enumerate() {
210 *b = i as u8;
211 }
212 let checksum: u32 = region.iter().map(|&b| b as u32).sum();
213 println!(
214 " 64B aligned scratch, checksum {checksum}, used {}B",
215 scratch.used()
216 );
217 assert_eq!(checksum, (0..64u32).sum::<u32>());
218 scratch.reset();
219 assert_eq!(scratch.used(), 0);
220}More examples
examples/perf_features.rs (line 170)
52fn main() -> io::Result<()> {
53 let canon = SIZES[SIZES.len() - 1];
54
55 let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
56 .join("..")
57 .join(".subms")
58 .join("features")
59 .join("rust.json");
60 let existing = std::fs::read_to_string(&path).unwrap_or_default();
61 let mut manifest = SubMsFeatureManifest::load_str("rust", &existing);
62 // Stamp the box these numbers came from. The bench runs wherever it is
63 // invoked, so an unstamped manifest is indistinguishable from a fleet
64 // capture; the renderer will not publish one it cannot attribute.
65 let (source, instance) = SubMsP99Source::from_env();
66 manifest.set_p99_source(source, instance.as_deref());
67
68 // ---------- typed: one Copy type, slot handles, reuse on free ----------
69 #[cfg(feature = "typed")]
70 {
71 use subms_arena_allocator::TypedArena;
72 let sweep: Vec<(usize, u64)> = SIZES
73 .iter()
74 .map(|&n| {
75 let mut arena: TypedArena<u64> = TypedArena::with_capacity(n);
76 let (p50, _) = run_p50_p99(n, |i| {
77 std::hint::black_box(arena.alloc(i as u64));
78 });
79 (n, p50)
80 })
81 .collect();
82 let (cat, reason) = classify_feature(&sweep, None, None);
83
84 let mut arena: TypedArena<u64> = TypedArena::with_capacity(canon);
85 let (_, alloc99) = run_p50_p99(canon, |i| {
86 std::hint::black_box(arena.alloc(i as u64));
87 });
88 // Every timed op here takes the slot the previous one freed, so the
89 // reuse path is what is measured rather than the append path.
90 let mut churn: TypedArena<u64> = TypedArena::with_capacity(2);
91 let (_, free99) = run_p50_p99(canon, |i| {
92 let slot = churn.alloc(i as u64);
93 churn.free(slot);
94 });
95 let mut p99 = BTreeMap::new();
96 p99.insert("alloc".to_string(), alloc99);
97 p99.insert("free".to_string(), free99);
98 manifest.set_feature("typed", cat, &p99, &reason);
99 }
100
101 // ---------- growable: a new chunk when the active one runs out ----------
102 #[cfg(feature = "growable")]
103 {
104 use subms_arena_allocator::GrowableBump;
105 let sweep: Vec<(usize, u64)> = SIZES
106 .iter()
107 .map(|&n| {
108 let mut a = GrowableBump::new();
109 let (p50, _) = run_p50_p99(n, |i| {
110 std::hint::black_box(a.alloc_copy(i as u64));
111 });
112 (n, p50)
113 })
114 .collect();
115 let (cat, reason) = classify_feature(&sweep, None, None);
116
117 let mut a = GrowableBump::new();
118 let (_, alloc99) = run_p50_p99(canon, |i| {
119 std::hint::black_box(a.alloc_copy(i as u64));
120 });
121 let mut filled = GrowableBump::new();
122 for i in 0..canon {
123 filled.alloc_copy(i as u64);
124 }
125 let (_, reset99) = run_p50_p99(1, |_| filled.reset());
126 let mut p99 = BTreeMap::new();
127 p99.insert("alloc".to_string(), alloc99);
128 p99.insert("reset".to_string(), reset99);
129 manifest.set_feature("growable", cat, &p99, &reason);
130 }
131
132 // ---------- stats: live counters on the alloc path ----------
133 #[cfg(feature = "stats")]
134 {
135 use subms_arena_allocator::StatsBump;
136 let sweep: Vec<(usize, u64)> = SIZES
137 .iter()
138 .map(|&n| {
139 let mut a = StatsBump::new();
140 let (p50, _) = run_p50_p99(n, |i| {
141 std::hint::black_box(a.alloc_copy(i as u64));
142 });
143 (n, p50)
144 })
145 .collect();
146 let (cat, reason) = classify_feature(&sweep, None, None);
147
148 let mut a = StatsBump::new();
149 let (_, alloc99) = run_p50_p99(canon, |i| {
150 std::hint::black_box(a.alloc_copy(i as u64));
151 });
152 let (_, snap99) = run_p50_p99(canon, |_| {
153 std::hint::black_box(a.stats());
154 });
155 let mut p99 = BTreeMap::new();
156 p99.insert("alloc".to_string(), alloc99);
157 p99.insert("stats".to_string(), snap99);
158 manifest.set_feature("stats", cat, &p99, &reason);
159 }
160
161 // ---------- aligned: explicit per-allocation alignment ----------
162 #[cfg(feature = "aligned")]
163 {
164 use subms_arena_allocator::AlignedBump;
165 let sweep: Vec<(usize, u64)> = SIZES
166 .iter()
167 .map(|&n| {
168 let mut a = AlignedBump::with_capacity(n * 16 + 4096);
169 let (p50, _) = run_p50_p99(n, |_| {
170 std::hint::black_box(a.alloc_aligned(8, 8).len());
171 });
172 (n, p50)
173 })
174 .collect();
175 let (cat, reason) = classify_feature(&sweep, None, None);
176
177 let mut a = AlignedBump::with_capacity(canon * 16 + 4096);
178 let (_, alloc99) = run_p50_p99(canon, |_| {
179 std::hint::black_box(a.alloc_aligned(8, 8).len());
180 });
181 let mut p99 = BTreeMap::new();
182 p99.insert("alloc_aligned".to_string(), alloc99);
183 manifest.set_feature("aligned", cat, &p99, &reason);
184 }
185
186 std::fs::create_dir_all(path.parent().unwrap())?;
187 std::fs::write(&path, manifest.to_json())?;
188 io::stdout().write_all(manifest.to_json().as_bytes())?;
189 Ok(())
190}Sourcepub fn try_alloc_aligned(
&mut self,
size: usize,
align: usize,
) -> Option<&mut [u8]>
pub fn try_alloc_aligned( &mut self, size: usize, align: usize, ) -> Option<&mut [u8]>
Fallible aligned alloc. Returns None if the request doesn’t fit.
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Rewind. Buffer retained for reuse.
Examples found in repository?
examples/sample_app.rs (line 218)
203fn aligned_price_scan() {
204 use subms_arena_allocator::AlignedBump;
205 println!("\n== aligned: cache-line scratch for a price scan ==");
206 let mut scratch = AlignedBump::with_capacity(1024);
207 let region = scratch.alloc_aligned(64, 64);
208 assert_eq!(region.as_ptr() as usize % 64, 0, "cache-line aligned");
209 for (i, b) in region.iter_mut().enumerate() {
210 *b = i as u8;
211 }
212 let checksum: u32 = region.iter().map(|&b| b as u32).sum();
213 println!(
214 " 64B aligned scratch, checksum {checksum}, used {}B",
215 scratch.used()
216 );
217 assert_eq!(checksum, (0..64u32).sum::<u32>());
218 scratch.reset();
219 assert_eq!(scratch.used(), 0);
220}Sourcepub fn used(&self) -> usize
pub fn used(&self) -> usize
Bytes used so far.
Examples found in repository?
examples/sample_app.rs (line 215)
203fn aligned_price_scan() {
204 use subms_arena_allocator::AlignedBump;
205 println!("\n== aligned: cache-line scratch for a price scan ==");
206 let mut scratch = AlignedBump::with_capacity(1024);
207 let region = scratch.alloc_aligned(64, 64);
208 assert_eq!(region.as_ptr() as usize % 64, 0, "cache-line aligned");
209 for (i, b) in region.iter_mut().enumerate() {
210 *b = i as u8;
211 }
212 let checksum: u32 = region.iter().map(|&b| b as u32).sum();
213 println!(
214 " 64B aligned scratch, checksum {checksum}, used {}B",
215 scratch.used()
216 );
217 assert_eq!(checksum, (0..64u32).sum::<u32>());
218 scratch.reset();
219 assert_eq!(scratch.used(), 0);
220}Trait Implementations§
Source§impl Drop for AlignedBump
impl Drop for AlignedBump
Auto Trait Implementations§
impl !Send for AlignedBump
impl !Sync for AlignedBump
impl Freeze for AlignedBump
impl RefUnwindSafe for AlignedBump
impl Unpin for AlignedBump
impl UnsafeUnpin for AlignedBump
impl UnwindSafe for AlignedBump
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more