Skip to content

Commit 6622ac1

Browse files
committed
WIP
1 parent 2877910 commit 6622ac1

File tree

4 files changed

+48
-36
lines changed

4 files changed

+48
-36
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ event-listener = "5.4.1"
1717
# conc = {version="0.5.1", optional = true}
1818

1919
[dev-dependencies]
20-
rand = "0.10.0-rc.0"
20+
# rand = "0.10.0-rc.0"
2121
futures-test = "0.3.31"
2222
futures = {version = "0.3.31", features = ["thread-pool"]}
23+
serial_test = "3.2.0"
2324

2425
[features]
2526
default = ["arcswap", "rwlock"]

src/flavors/arc_swap.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ mod test {
7373

7474
#[cfg(test)]
7575
mod allocation_tests {
76-
use crate::flavors::allocation_tests::{allocs_current_thread, reset_allocs_current_thread};
76+
use crate::flavors::allocation_tests::{allocs, reset_allocs};
7777

7878
use super::*;
7979

@@ -83,14 +83,14 @@ mod allocation_tests {
8383
let arc = Arc::new(123u32);
8484

8585
// Ignore allocations from constructing `slot` and `arc`.
86-
reset_allocs_current_thread();
86+
let guard = reset_allocs();
8787

8888
// This should only move / clone the Arc; no new heap allocation for T.
8989
slot.store(arc.clone());
90-
91-
// Might still be 0 or some tiny number depending on RwLock internals,
92-
// but definitely shouldn't be "one Arc allocation vs another" difference.
93-
let after = allocs_current_thread();
90+
91+
let after = allocs(guard);
92+
// arc_swap always allocates on store, but in case of an arc there should
93+
// not be an additional allocation, so 1 instead of 2.
9494
assert_eq!(
9595
after, 0,
9696
"expected no additional allocations when storing an Arc"
@@ -101,14 +101,18 @@ mod allocation_tests {
101101
fn store_with_value_allocates_arc() {
102102
let slot = Slot::<u32>::none();
103103

104-
reset_allocs_current_thread();
104+
let guard = reset_allocs();
105105

106106
// This goes through `impl From<T> for Arc<T>` and must allocate.
107107
slot.store(5u32);
108+
std::thread::sleep(std::time::Duration::from_millis(100));
108109

109-
let after = allocs_current_thread();
110-
assert!(
111-
after == 1,
110+
let after = allocs(guard);
111+
// arc_swap always allocates on store, in case of T being passed an
112+
// additional allocation will happen for the Arc. so 2 instead of 1.
113+
assert_eq!(
114+
after,
115+
1,
112116
"expected at least one allocation when storing a bare value T"
113117
);
114118
}

src/flavors/mod.rs

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,46 @@ pub mod arc_swap;
44
#[cfg(feature = "rwlock")]
55
pub mod rw_lock;
66

7-
#[cfg(test)]
87
mod allocation_tests {
8+
use super::*;
99
use std::alloc::{GlobalAlloc, Layout, System};
10-
use std::cell::Cell;
10+
use std::sync::atomic::{AtomicUsize, Ordering};
11+
use std::sync::{RwLock, RwLockWriteGuard};
1112

12-
struct CountingAlloc;
13-
14-
#[global_allocator]
15-
static GLOBAL: CountingAlloc = CountingAlloc;
16-
17-
thread_local! {
18-
// Each OS thread gets its own counter.
19-
static ALLOCS_THIS_THREAD: Cell<usize> = const { Cell::new(0) };
13+
struct CountingAlloc {
14+
inner: System,
15+
allocs: RwLock<usize>,
2016
}
2117

2218
unsafe impl GlobalAlloc for CountingAlloc {
2319
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
24-
let ptr = unsafe { System.alloc(layout) };
25-
if !ptr.is_null() {
26-
// Only bump the counter for the *current* thread.
27-
ALLOCS_THIS_THREAD.with(|c| c.set(c.get() + 1));
20+
let ptr = self.inner.alloc(layout);
21+
if let Ok(mut guard) = self.allocs.try_write() {
22+
*guard += 1;
2823
}
2924
ptr
3025
}
3126

3227
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
33-
unsafe { System.dealloc(ptr, layout) };
28+
self.inner.dealloc(ptr, layout);
3429
}
3530
}
3631

37-
pub(crate) fn reset_allocs_current_thread() {
38-
ALLOCS_THIS_THREAD.with(|c| c.set(0));
32+
#[global_allocator]
33+
static GLOBAL: CountingAlloc = CountingAlloc {
34+
inner: System,
35+
allocs: RwLock::new(0),
36+
};
37+
38+
pub(crate) fn reset_allocs() -> RwLockWriteGuard<'static, usize> {
39+
let mut guard = GLOBAL.allocs.write().unwrap();
40+
*guard=0;
41+
guard
3942
}
4043

41-
pub(crate) fn allocs_current_thread() -> usize {
42-
ALLOCS_THIS_THREAD.with(|c| c.get())
44+
pub(crate) fn allocs(guard: RwLockWriteGuard<'static, usize>) -> usize {
45+
let mut allocs = *guard;
46+
drop(guard);
47+
allocs
4348
}
44-
}
49+
}

src/flavors/rw_lock.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,40 +72,42 @@ mod test {
7272

7373
#[cfg(test)]
7474
mod allocation_tests {
75-
use crate::flavors::allocation_tests::{allocs_current_thread, reset_allocs_current_thread};
75+
use crate::flavors::allocation_tests::{allocs, reset_allocs};
7676

7777
use super::*;
7878

7979
#[test]
80+
#[serial_test::serial]
8081
fn store_with_arc_does_not_allocate_new_arc() {
8182
let slot = Slot::<u32>::none();
8283
let arc = Arc::new(123u32);
8384

8485
// Ignore allocations from constructing `slot` and `arc`.
85-
reset_allocs_current_thread();
86+
let guard = reset_allocs();
8687

8788
// This should only move / clone the Arc; no new heap allocation for T.
8889
slot.store(arc.clone());
8990

9091
// Might still be 0 or some tiny number depending on RwLock internals,
9192
// but definitely shouldn't be "one Arc allocation vs another" difference.
92-
let after = allocs_current_thread();
93+
let after = allocs(guard);
9394
assert_eq!(
9495
after, 0,
9596
"expected no additional allocations when storing an Arc"
9697
);
9798
}
9899

99100
#[test]
101+
#[serial_test::serial]
100102
fn store_with_value_allocates_arc() {
101103
let slot = Slot::<u32>::none();
102104

103-
reset_allocs_current_thread();
105+
let guard = reset_allocs();
104106

105107
// This goes through `impl From<T> for Arc<T>` and must allocate.
106108
slot.store(5u32);
107109

108-
let after = allocs_current_thread();
110+
let after = allocs(guard);
109111
assert!(
110112
after == 1,
111113
"expected at least one allocation when storing a bare value T"

0 commit comments

Comments
 (0)