Skip to content

Commit 3199de9

Browse files
authored
Merge pull request #21 from mtak-/commit-refactor
Commit refactor
2 parents e2089cb + 6d994dd commit 3199de9

File tree

10 files changed

+268
-225
lines changed

10 files changed

+268
-225
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ nightly = [
2323
"crossbeam-utils/nightly",
2424
"lock_api/nightly",
2525
"parking_lot/nightly",
26+
"parking_lot_core/nightly",
2627
]
2728
rtm = ["swym-htm/rtm"]
2829
stats = []
2930

3031
[dependencies]
31-
cfg-if = "0.1.7"
32+
cfg-if = "0.1.9"
3233
crossbeam-utils = "0.6.5"
3334
lazy_static = "1.3.0"
3435
lock_api = "0.2.0"

benches/single_threaded_scaling.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ extern crate test;
66
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
77

88
mod single_threaded_scaling {
9-
use std::sync::{
10-
atomic::{AtomicUsize, Ordering::Relaxed},
11-
Mutex,
12-
};
9+
use parking_lot::Mutex;
10+
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
1311
use swym::{tcell::TCell, thread_key, tx::Ordering};
1412
use test::Bencher;
1513

@@ -45,7 +43,7 @@ mod single_threaded_scaling {
4543
}
4644
b.iter(|| {
4745
for i in 0..COUNT {
48-
let mut x_i = x[i].lock().unwrap();
46+
let mut x_i = x[i].lock();
4947
*x_i += 1;
5048
}
5149
})

src/internal/alloc/dyn_vec.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ macro_rules! dyn_vec_decl {
6161
}
6262

6363
#[allow(unused)]
64-
impl $name<'_> {
64+
impl<'a> $name<'a> {
6565
#[inline]
6666
$vis fn new() -> Self {
6767
$name {
@@ -93,6 +93,18 @@ macro_rules! dyn_vec_decl {
9393
self.data.len()
9494
}
9595

96+
#[inline]
97+
$vis unsafe fn word_index_unchecked(&self, word_index: usize) -> &(dyn $trait + 'a) {
98+
let raw = $crate::internal::alloc::dyn_vec::TraitObject::from_flat(self.data.get_unchecked(word_index).into());
99+
&*raw.cast().as_ptr()
100+
}
101+
102+
#[inline]
103+
$vis unsafe fn word_index_unchecked_mut(&mut self, word_index: usize) -> $crate::internal::alloc::dyn_vec::DynElemMut<'_, dyn $trait + 'a> {
104+
let raw = $crate::internal::alloc::dyn_vec::TraitObject::from_flat(self.data.get_unchecked_mut(word_index).into());
105+
$crate::internal::alloc::dyn_vec::DynElemMut::from_raw(&mut *raw.cast().as_ptr())
106+
}
107+
96108
#[inline]
97109
$vis fn next_push_allocates<U: $trait>(&self) -> bool {
98110
assert!(
@@ -218,6 +230,12 @@ pub struct DynElemMut<'a, T: ?Sized> {
218230
value: &'a mut T,
219231
}
220232

233+
impl<'a, T: ?Sized> DynElemMut<'a, T> {
234+
pub unsafe fn from_raw(value: &'a mut T) -> Self {
235+
DynElemMut { value }
236+
}
237+
}
238+
221239
impl<'a, T: ?Sized> Deref for DynElemMut<'a, T> {
222240
type Target = T;
223241

src/internal/alloc/fvec.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ impl<T> FVec<T> {
5353
#[inline]
5454
pub unsafe fn push_unchecked(&mut self, t: T) {
5555
if !self.next_push_allocates() {
56-
self.push(t)
56+
let len = self.len();
57+
self.set_len(len + 1);
58+
core::ptr::write(self.get_unchecked_mut(len), t);
5759
} else if cfg!(debug_assertions) {
5860
panic!("`push_unchecked` called when an allocation is required")
5961
} else {
@@ -64,7 +66,9 @@ impl<T> FVec<T> {
6466
#[inline]
6567
pub unsafe fn pop_unchecked(&mut self) -> T {
6668
if !self.is_empty() {
67-
self.pop().unwrap()
69+
let len = self.len() - 1;
70+
self.set_len(len);
71+
core::ptr::read(self.get_unchecked_mut(len))
6872
} else if cfg!(debug_assertions) {
6973
panic!("`FVec::pop_unchecked` called on an empty FVec")
7074
} else {

src/internal/commit.rs

Lines changed: 113 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,97 @@
11
use crate::{
22
internal::{
3-
epoch::{EpochLock, ParkStatus, EPOCH_CLOCK},
4-
thread::PinRw,
3+
epoch::{EpochLock, ParkStatus, QuiesceEpoch, EPOCH_CLOCK},
4+
thread::{Logs, PinRw},
5+
write_log::{WriteEntry, WriteLog},
56
},
67
stats,
78
};
8-
use core::ptr;
9-
use swym_htm::HardwareTx;
9+
use core::{
10+
mem,
11+
ptr::{self, NonNull},
12+
sync::atomic::{self, Ordering::Release},
13+
};
14+
use swym_htm::{BoundedHtxErr, HardwareTx};
15+
16+
const MAX_HTX_RETRIES: u8 = 3;
17+
18+
impl<'tcell> Logs<'tcell> {
19+
#[inline]
20+
pub unsafe fn remove_writes_from_reads(&mut self) {
21+
#[allow(unused_mut)]
22+
let mut count = 0;
23+
24+
let write_log = &mut self.write_log;
25+
self.read_log.filter_in_place(|src| {
26+
if write_log.find(src).is_none() {
27+
true
28+
} else {
29+
count += 1;
30+
false
31+
}
32+
});
33+
stats::write_after_logged_read(count)
34+
}
35+
}
36+
37+
impl<'tcell> dyn WriteEntry + 'tcell {
38+
#[inline]
39+
fn try_lock_htm(&self, htx: &HardwareTx, pin_epoch: QuiesceEpoch) -> ParkStatus {
40+
match self.tcell() {
41+
Some(tcell) => tcell.current_epoch.try_lock_htm(htx, pin_epoch),
42+
None => ParkStatus::NoParked,
43+
}
44+
}
45+
46+
#[inline]
47+
unsafe fn perform_write(&self) {
48+
match self.tcell() {
49+
Some(tcell) => {
50+
let size = mem::size_of_val(self);
51+
assume!(
52+
size % mem::size_of::<usize>() == 0,
53+
"buggy alignment on `WriteEntry`"
54+
);
55+
let len = size / mem::size_of::<usize>() - 1;
56+
assume!(
57+
len > 0,
58+
"`WriteEntry` performing a write of size 0 unexpectedly"
59+
);
60+
self.pending().as_ptr().copy_to_nonoverlapping(
61+
NonNull::from(*tcell).cast::<usize>().as_ptr().sub(len),
62+
len,
63+
);
64+
}
65+
None => {}
66+
}
67+
}
68+
}
69+
70+
impl<'tcell> WriteLog<'tcell> {
71+
#[inline]
72+
unsafe fn publish(&self, sync_epoch: QuiesceEpoch) {
73+
self.epoch_locks()
74+
.for_each(|epoch_lock| epoch_lock.unlock_publish(sync_epoch))
75+
}
1076

11-
const MAX_HTX_RETRIES: usize = 3;
77+
#[inline]
78+
fn write_and_lock_htm(&self, htx: &HardwareTx, pin_epoch: QuiesceEpoch) -> ParkStatus {
79+
let mut status = ParkStatus::NoParked;
80+
for entry in self.write_entries() {
81+
unsafe { entry.perform_write() };
82+
status = status.merge(entry.try_lock_htm(htx, pin_epoch));
83+
}
84+
status
85+
}
86+
87+
#[inline]
88+
unsafe fn perform_writes(&self) {
89+
atomic::fence(Release);
90+
for entry in self.write_entries() {
91+
entry.perform_write();
92+
}
93+
}
94+
}
1295

1396
impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
1497
/// The commit algorithm, called after user code has finished running without returning an
@@ -42,42 +125,32 @@ impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
42125
}
43126

44127
#[inline]
45-
fn commit_slow(self) -> bool {
128+
fn start_htx(&self, retry_count: &mut u8) -> Result<HardwareTx, BoundedHtxErr> {
46129
if swym_htm::htm_supported() && self.logs().write_log.word_len() >= 9 {
47-
enum HtxRetry {
48-
SoftwareFallback,
49-
FullRetry,
130+
HardwareTx::bounded(retry_count, MAX_HTX_RETRIES)
131+
} else {
132+
Err(BoundedHtxErr::SoftwareFallback)
133+
}
134+
}
135+
136+
#[inline]
137+
fn commit_slow(self) -> bool {
138+
let mut retry_count = 0;
139+
match self.start_htx(&mut retry_count) {
140+
Ok(htx) => {
141+
let success = self.commit_hard(htx);
142+
stats::htm_conflicts(retry_count as _);
143+
success
50144
}
51-
let mut retry_count = 0;
52-
let htx = unsafe {
53-
let retry_count = &mut retry_count;
54-
HardwareTx::new(move |code| {
55-
if code.is_explicit_abort() || code.is_conflict() && !code.is_retry() {
56-
Err(HtxRetry::FullRetry)
57-
} else if code.is_retry() && *retry_count < MAX_HTX_RETRIES {
58-
*retry_count += 1;
59-
Ok(())
60-
} else {
61-
Err(HtxRetry::SoftwareFallback)
62-
}
63-
})
64-
};
65-
match htx {
66-
Ok(htx) => {
67-
let success = self.commit_hard(htx);
68-
stats::htm_conflicts(retry_count);
69-
return success;
70-
}
71-
Err(HtxRetry::SoftwareFallback) => {
72-
stats::htm_conflicts(retry_count);
73-
}
74-
Err(HtxRetry::FullRetry) => {
75-
stats::htm_conflicts(retry_count);
76-
return false;
77-
}
145+
Err(BoundedHtxErr::SoftwareFallback) => {
146+
stats::htm_conflicts(retry_count as _);
147+
self.commit_soft()
148+
}
149+
Err(BoundedHtxErr::AbortOrConflict) => {
150+
stats::htm_conflicts(retry_count as _);
151+
false
78152
}
79153
}
80-
self.commit_soft()
81154
}
82155

83156
#[inline(never)]
@@ -91,11 +164,7 @@ impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
91164
drop(htx);
92165

93166
let sync_epoch = EPOCH_CLOCK.fetch_and_tick();
94-
95-
// publish
96-
logs.write_log
97-
.epoch_locks()
98-
.for_each(|epoch_lock| epoch_lock.unlock_publish(sync_epoch.next()));
167+
logs.write_log.publish(sync_epoch.next());
99168

100169
logs.read_log.clear();
101170
logs.write_log.clear_no_drop();
@@ -178,9 +247,8 @@ impl<'tx, 'tcell> PinRw<'tx, 'tcell> {
178247
);
179248

180249
// unlocks everything in the write lock and sets the TCell epochs to sync_epoch.next()
181-
logs.write_log
182-
.epoch_locks()
183-
.for_each(|epoch_lock| epoch_lock.unlock_publish(sync_epoch.next()));
250+
logs.write_log.publish(sync_epoch.next());
251+
184252
logs.read_log.clear();
185253
logs.write_log.clear_no_drop();
186254
if unlikely!(park_status == ParkStatus::HasParked) {

0 commit comments

Comments
 (0)