Skip to content

Commit

Permalink
Make ConStack pop() correct and deallocate memory when possible
Browse files Browse the repository at this point in the history
  • Loading branch information
krl committed Oct 12, 2017
1 parent e181066 commit 1591dcd
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ documentation = "https://docs.rs/convec/"
repository = "https://github.com/krl/convec"
license = "GPL-3.0"
name = "convec"
version = "2.0.0"
version = "2.0.1"

[dependencies]
parking_lot = "0.4.8"
40 changes: 36 additions & 4 deletions src/convec.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
extern crate parking_lot;
use std::cell::UnsafeCell;
use std::ops::Index;
use std::{fmt, mem};

use parking_lot::RwLock;

Expand Down Expand Up @@ -149,14 +150,45 @@ impl<T> ConVec<T> {

pub unsafe fn pop(&self) -> Option<T> {
let mut guard = self.len.write();
let len = *guard;
if len == 0 {
if *guard == 0 {
return None;
}
*guard -= 1;

let (index, _) = self.allocation(len);
(*self.allocations[index].get()).pop()
let (index, _) = self.allocation(*guard);
let popped = (*self.allocations[index].get()).pop();
// deallocate
if (*self.allocations[index].get()).len() == 0 {
*self.allocations[index].get() = vec![];
}
popped
}

#[allow(unused)]
pub fn heap_size(&self) -> usize
where
T: ::std::fmt::Debug,
{
let mut heap_size = 0;
for i in 0..64 {
unsafe {
heap_size += (*self.allocations[i].get()).capacity() *
mem::size_of::<T>();
}
}
heap_size
}
}

impl<T: fmt::Debug> fmt::Debug for ConVec<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..64 {
let alloc = unsafe { &(*self.allocations[i].get()) };
if alloc.len() > 0 {
write!(f, "{:?} ", alloc)?;
}
}
Ok(())
}
}

Expand Down
57 changes: 49 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ mod convec;

use convec::ConVec;

#[derive(Debug)]
/// Append only concurrent vector
pub struct AoVec<T>(ConVec<T>);
#[derive(Debug)]
/// Concurrent stack
pub struct ConStack<T>(ConVec<T>);

Expand All @@ -30,6 +32,14 @@ impl<T> ConStack<T> {
pub fn pop(&self) -> Option<T> {
unsafe { self.0.pop() }
}

#[allow(unused)]
fn heap_size(&self) -> usize
where
T: ::std::fmt::Debug,
{
self.0.heap_size()
}
}

impl<T> AoVec<T> {
Expand Down Expand Up @@ -106,19 +116,49 @@ mod tests {
}

#[test]
fn constack() {
let vec = Arc::new(ConStack::new());
fn single_threaded_aovec() {
let vec = AoVec::new();
let n = 1_000_000;

for i in 0..n {
vec.push(i);
}

for i in 0..n {
assert_eq!(vec.get(i), Some(&i));
}
}

#[test]
fn single_threaded_constack() {
let stack = ConStack::new();
let n = 1_000_000;

for i in 0..n {
stack.push(i);
}

for i in 0..n {
assert_eq!(stack.pop(), Some(n - i - 1));
}
assert_eq!(stack.pop(), None);
assert_eq!(stack.heap_size(), 0);
}

#[test]
fn constack() {
let stack = Arc::new(ConStack::new());
let n = 32;

let n_threads = 16;

let mut handles = vec![];

for t in 0..n_threads {
let vec = vec.clone();
let stack = stack.clone();
handles.push(std::thread::spawn(move || for i in 0..n {
if i % n_threads == t {
vec.push(i);
stack.push(i);
}
}))
}
Expand All @@ -130,10 +170,10 @@ mod tests {
let mut handles = vec![];

for t in 0..n_threads {
let vec = vec.clone();
let stack = stack.clone();
handles.push(std::thread::spawn(move || for i in 0..n {
if i % n_threads == t {
vec.pop().is_some();
stack.pop().is_some();
}
}))
}
Expand All @@ -142,7 +182,8 @@ mod tests {
h.join().unwrap();
}

assert_eq!(vec.len(), 0);
assert_eq!(vec.pop(), None);
assert_eq!(stack.heap_size(), 0);
assert_eq!(stack.len(), 0);
assert_eq!(stack.pop(), None);
}
}

0 comments on commit 1591dcd

Please sign in to comment.