Skip to content

Commit a6757ee

Browse files
committed
refactor: using_object_pool
1 parent d85a823 commit a6757ee

File tree

6 files changed

+84
-16
lines changed

6 files changed

+84
-16
lines changed

benches/bench.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ use benchmark_repetitive_react_components::{
3030
benchmark_repetitive_react_components_source,
3131
};
3232

33+
<<<<<<< Updated upstream
3334
use crate::bench_complex_replace_source::benchmark_complex_replace_source_size;
35+
=======
36+
use crate::{
37+
bench_complex_replace_source::benchmark_complex_replace_source_map_in_using_object_pool,
38+
benchmark_repetitive_react_components::benchmark_repetitive_react_components_map_in_using_object_pool,
39+
};
40+
>>>>>>> Stashed changes
3441

3542
const HELLOWORLD_JS: &str = include_str!(concat!(
3643
env!("CARGO_MANIFEST_DIR"),
@@ -161,6 +168,11 @@ fn bench_rspack_sources(criterion: &mut Criterion) {
161168
benchmark_complex_replace_source_map,
162169
);
163170

171+
group.bench_function(
172+
"complex_replace_source_map_in_using_object_pool",
173+
benchmark_complex_replace_source_map_in_using_object_pool,
174+
);
175+
164176
group.bench_function(
165177
"complex_replace_source_source",
166178
benchmark_complex_replace_source_source,
@@ -188,6 +200,11 @@ fn bench_rspack_sources(criterion: &mut Criterion) {
188200
benchmark_repetitive_react_components_map,
189201
);
190202

203+
group.bench_function(
204+
"repetitive_react_components_map_in_using_object_pool",
205+
benchmark_repetitive_react_components_map_in_using_object_pool,
206+
);
207+
191208
group.bench_function(
192209
"repetitive_react_components_source",
193210
benchmark_repetitive_react_components_source,

benches/bench_complex_replace_source.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36724,6 +36724,16 @@ static LARGE_REPLACE_SOURCE: LazyLock<BoxSource> = LazyLock::new(|| {
3672436724
pub fn benchmark_complex_replace_source_map(b: &mut Bencher) {
3672536725
let source = LARGE_REPLACE_SOURCE.clone();
3672636726

36727+
b.iter(|| {
36728+
black_box(source.map(&MapOptions::default()));
36729+
});
36730+
}
36731+
36732+
pub fn benchmark_complex_replace_source_map_in_using_object_pool(
36733+
b: &mut Bencher,
36734+
) {
36735+
let source = LARGE_REPLACE_SOURCE.clone();
36736+
3672736737
using_object_pool(|| {
3672836738
b.iter(|| {
3672936739
black_box(source.map(&MapOptions::default()));

benches/benchmark_repetitive_react_components.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3504,6 +3504,16 @@ static REPETITIVE_1K_REACT_COMPONENTS_SOURCE: LazyLock<BoxSource> =
35043504
pub fn benchmark_repetitive_react_components_map(b: &mut Bencher) {
35053505
let source = REPETITIVE_1K_REACT_COMPONENTS_SOURCE.clone();
35063506

3507+
b.iter(|| {
3508+
black_box(source.map(&MapOptions::default()));
3509+
});
3510+
}
3511+
3512+
pub fn benchmark_repetitive_react_components_map_in_using_object_pool(
3513+
b: &mut Bencher,
3514+
) {
3515+
let source = REPETITIVE_1K_REACT_COMPONENTS_SOURCE.clone();
3516+
35073517
using_object_pool(|| {
35083518
b.iter(|| {
35093519
black_box(source.map(&MapOptions::default()));

src/helpers.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111
decoder::MappingsDecoder,
1212
encoder::create_encoder,
1313
linear_map::LinearMap,
14+
object_pool::cleanup_idle_object_pool,
1415
source::{Mapping, OriginalLocation},
1516
with_indices::WithIndices,
1617
MapOptions, Rope, SourceMap,
@@ -62,8 +63,12 @@ pub fn get_map<'a, S: StreamChunks>(
6263
},
6364
);
6465
let mappings = mappings_encoder.drain();
65-
(!mappings.is_empty())
66-
.then(|| SourceMap::new(mappings, sources, sources_content, names))
66+
let source_map = (!mappings.is_empty())
67+
.then(|| SourceMap::new(mappings, sources, sources_content, names));
68+
69+
cleanup_idle_object_pool();
70+
71+
source_map
6772
}
6873

6974
/// [StreamChunks] abstraction, see [webpack-sources source.streamChunks](https://github.com/webpack/webpack-sources/blob/9f98066311d53a153fdc7c633422a1d086528027/lib/helpers/streamChunks.js#L13).

src/object_pool.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
use std::{cell::RefCell, collections::BTreeMap, rc::Rc};
1+
use std::{
2+
cell::{OnceCell, RefCell},
3+
collections::BTreeMap,
4+
rc::Rc,
5+
sync::atomic::AtomicBool,
6+
};
27

38
// Vector pooling minimum capacity threshold
49
// Recommended threshold: 64
@@ -71,6 +76,10 @@ impl<T: Poolable> ObjectPool<T> {
7176
let bucket = objects.entry(cap).or_default();
7277
bucket.push(object);
7378
}
79+
80+
pub fn clear(&self) {
81+
self.objects.borrow_mut().clear();
82+
}
7483
}
7584

7685
/// A smart pointer that holds a pooled object and automatically returns it to the pool when dropped.
@@ -130,9 +139,11 @@ impl<T: Poolable> std::ops::DerefMut for Pooled<T> {
130139
}
131140

132141
thread_local! {
133-
pub static USIZE_VEC_POOL: RefCell<Option<ObjectPool<Vec<usize>>>> = RefCell::default();
142+
pub static USIZE_VEC_POOL: OnceCell<ObjectPool<Vec<usize>>> = OnceCell::default();
134143
}
135144

145+
pub static IN_USING_OBJECT_POOL: AtomicBool = AtomicBool::new(false);
146+
136147
/// Executes a function with object pooling enabled for the current thread.
137148
///
138149
/// This function temporarily enables a thread-local object pool for `Vec<usize>` allocations,
@@ -141,21 +152,35 @@ pub fn using_object_pool<F, R>(f: F) -> R
141152
where
142153
F: FnOnce() -> R,
143154
{
155+
IN_USING_OBJECT_POOL.store(true, std::sync::atomic::Ordering::Relaxed);
144156
// Initialize the thread-local pool if needed
145-
USIZE_VEC_POOL.with(|pool| {
146-
let mut pool_ref = pool.borrow_mut();
147-
if pool_ref.is_none() {
148-
*pool_ref = Some(ObjectPool::default());
149-
}
157+
USIZE_VEC_POOL.with(|once_cell| {
158+
once_cell.get_or_init(ObjectPool::default);
150159
});
151160

152161
let result = f();
153162

154-
// Clean up the pool to prevent memory retention
155-
// This ensures no memory is held between different pooling sessions
156-
USIZE_VEC_POOL.with(|pool| {
157-
pool.borrow_mut().take();
163+
IN_USING_OBJECT_POOL.store(false, std::sync::atomic::Ordering::Relaxed);
164+
USIZE_VEC_POOL.with(|once_cell| {
165+
if let Some(pool) = once_cell.get() {
166+
pool.clear();
167+
}
158168
});
159169

160170
result
161171
}
172+
173+
/// Cleans up the object pool when not in pooling mode to prevent memory retention.
174+
///
175+
/// This function is called automatically after map operations complete to ensure
176+
/// that memory is not retained unnecessarily outside of pooling contexts.
177+
pub fn cleanup_idle_object_pool() {
178+
// Only clear if we're not in an explicit pooling context
179+
if !IN_USING_OBJECT_POOL.load(std::sync::atomic::Ordering::Relaxed) {
180+
USIZE_VEC_POOL.with(|once_cell| {
181+
if let Some(pool) = once_cell.get() {
182+
pool.clear();
183+
}
184+
});
185+
}
186+
}

src/with_indices.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{cell::OnceCell, marker::PhantomData};
22

33
use crate::{
44
helpers::SourceText,
5-
object_pool::{Pooled, USIZE_VEC_POOL},
5+
object_pool::{ObjectPool, Pooled, USIZE_VEC_POOL},
66
};
77

88
#[derive(Debug)]
@@ -36,8 +36,9 @@ where
3636
}
3737

3838
let char_byte_indices = self.char_byte_indices.get_or_init(|| {
39-
let mut vec = USIZE_VEC_POOL.with(|pool| {
40-
Pooled::new(pool.borrow().as_ref().cloned(), self.line.len())
39+
let mut vec = USIZE_VEC_POOL.with(|once_cell| {
40+
let pool = once_cell.get_or_init(ObjectPool::default);
41+
Pooled::new(Some(pool.clone()), self.line.len())
4142
});
4243
vec.extend(self.line.char_indices().map(|(i, _)| i));
4344
vec

0 commit comments

Comments
 (0)