Commit ea493917 authored by qinsoon's avatar qinsoon

use doubly linked list for from/to_space of treadmill

parent 996e71a2
......@@ -18,4 +18,5 @@ lazy_static = "0.1.15"
log = "0.3.5"
simple_logger = "0.4.0"
aligned_alloc = "0.1.2"
crossbeam = "0.2.8"
\ No newline at end of file
crossbeam = "0.2.8"
doubly = "1.1.1"
\ No newline at end of file
#![allow(dead_code)]
extern crate doubly;
use utils::Address;
use utils::mem::memmap;
use utils::LOG_POINTER_SIZE;
......@@ -12,6 +14,8 @@ use std::sync::Arc;
use std::fmt;
use std::sync::Mutex;
use self::doubly::DoublyLinkedList;
const SPACE_ALIGN : usize = 1 << 19;
const BLOCK_SIZE : usize = 1 << 12; // 4kb
......@@ -75,6 +79,10 @@ impl FreeListSpace {
trace!("requiring {} bytes ({} blocks)", size, blocks_needed);
let res = {
if blocks_needed > 1 {
unimplemented!()
}
let mut treadmill = self.treadmill.lock().unwrap();
treadmill.alloc_blocks(blocks_needed)
};
......@@ -104,83 +112,58 @@ impl FreeListSpace {
let mut alive_nodes_scanned = 0;
let mut treadmill = self.treadmill.lock().unwrap();
let trace_map = self.trace_map();
let mark_state = objectmodel::load_mark_state();
let mut resnapped_any = false;
loop {
trace!("scanning {}", unsafe { &*treadmill.scan });
let addr = unsafe{&*treadmill.scan}.payload;
nodes_scanned += 1;
if objectmodel::is_traced(trace_map, self.start, unsafe { addr.to_object_reference() }, mark_state) && unsafe{&*treadmill.scan}.color == objectmodel::flip(mark_state) {
// the object is alive, do not need to 'move' its node
alive_nodes_scanned += 1;
// but they will be alive, we will set them to opposite mark color
// (meaning they are not available after flip)
unsafe{&mut *treadmill.scan}.color = objectmodel::flip(mark_state);
trace!("is alive, set color to {}", objectmodel::flip(mark_state));
{
let trace_map = self.trace_map();
let mark_state = objectmodel::load_mark_state();
// advance cur backwards
treadmill.scan = unsafe{&*treadmill.scan}.prev();
} else {
// this object is dead
// we do not need to set their color
let from = treadmill.from;
let to = treadmill.to;
free_nodes_scanned += 1;
let total_nodes = treadmill.spaces[from].len();
let mut i = 0;
while nodes_scanned < total_nodes {
trace!("scanning {}", treadmill.spaces[from][i]);
let addr = treadmill.spaces[from][i].payload;
// we resnap it after current 'free' pointer
if treadmill.scan != treadmill.free {
// since we are going to move current node (scan), we get its prev first
let prev = unsafe{&*treadmill.scan}.prev();
trace!("get scan's prev before resnapping it: {}", unsafe { &*prev });
nodes_scanned += 1;
let alive_node = unsafe { &mut *treadmill.scan }.remove();
if objectmodel::is_traced(trace_map, self.start, unsafe { addr.to_object_reference() }, mark_state) {
// this object is alive
alive_nodes_scanned += 1;
trace!("is dead, take it out of treadmill");
if TRACE_TREADMILL {
trace!("treadmill: {}", &treadmill as &Treadmill);
}
// move to tospace
let node = treadmill.spaces[from].remove(i);
treadmill.spaces[to].push_front(node);
// insert alive node after free
unsafe{&mut *treadmill.free}.insert_after(alive_node);
trace!("is alive");
trace!("insert after free");
if TRACE_TREADMILL {
trace!("treadmill: {}", &treadmill as &Treadmill);
}
// if this is the first object inserted, it is the 'bottom'
// then 1) all resnapped objects will be between 'free' and 'bottom'
// 2) the traversal can stop when scan meets bottom
if !resnapped_any {
treadmill.b = treadmill.scan;
resnapped_any = true;
}
treadmill.scan = prev;
// do not increment i
} else {
trace!("is dead and it is free pointer, do not move it");
treadmill.scan = unsafe{&*treadmill.scan}.prev();
free_nodes_scanned += 1;
i += 1;
}
}
// check if we can stop
if resnapped_any && treadmill.scan == treadmill.b {
break;
}
if !resnapped_any && treadmill.scan == treadmill.free {
// we never set bottom (meaning everything is alive)
// check if we have any free nodes
if free_nodes_scanned == 0 && treadmill.spaces[treadmill.to].len() == 0 {
println!("didnt free up any memory in treadmill space");
panic!("we ran out of memory in large object space")
}
}
// next allocation in to_space will starts from alive_nodes_scanned
treadmill.from_space_next = alive_nodes_scanned;
// flip
if treadmill.from == 0 {
treadmill.from = 1;
treadmill.to = 0;
} else {
treadmill.from = 0;
treadmill.to = 1;
}
if cfg!(debug_assertions) {
debug!("---tread mill space---");
debug!("total nodes scanned: {}", nodes_scanned);
......@@ -228,202 +211,84 @@ impl fmt::Display for FreeListSpace {
}
struct Treadmill{
free: *mut TreadmillNode,
scan: *mut TreadmillNode,
b : *mut TreadmillNode
from_space_next : usize, // next available node in from_space
from: usize,
to : usize,
spaces : [DoublyLinkedList<TreadmillNode>; 2]
}
impl Treadmill {
fn new(start: Address, end: Address) -> Treadmill {
let mut addr = start;
let half_space = start.plus(end.diff(start) / 2);
let free = TreadmillNode::singleton(addr);
addr = addr.plus(BLOCK_SIZE);
let mut from_space = DoublyLinkedList::new();
let mut to_space = DoublyLinkedList::new();
let mut tail = free;
let mut addr = start;
while addr < half_space {
from_space.push_back(TreadmillNode::new(addr));
addr = addr.plus(BLOCK_SIZE);
}
while addr < end {
tail = unsafe {(&mut *tail)}.init_insert_after(addr);
to_space.push_back(TreadmillNode::new(addr));
addr = addr.plus(BLOCK_SIZE);
}
Treadmill {
free: free,
scan: free,
b: free
from_space_next: 0,
from: 0,
to : 1,
spaces: [from_space, to_space]
}
}
fn alloc_blocks(&mut self, n_blocks: usize) -> Address {
let unavailable_color = objectmodel::load_mark_state();
// check if we have n_blocks available
let mut cur = self.free;
for _ in 0..n_blocks {
if unsafe{&*cur}.color == unavailable_color {
trace!("next block color is {}, no available blocks, return zero", unavailable_color);
return unsafe {Address::zero()};
}
let ref from_space = self.spaces[self.from];
if self.from_space_next + n_blocks <= from_space.len() {
let ret = from_space[self.from_space_next].payload;
self.from_space_next += n_blocks;
cur = unsafe {&*cur}.next;
}
// we make sure that n_blocks are available, mark them as black
let mut cur2 = self.free;
for _ in 0..n_blocks {
unsafe{&mut *cur2}.color = unavailable_color;
cur2 = unsafe {&*cur2}.next
ret
} else {
unsafe {Address::zero()}
}
debug_assert!(cur == cur2);
let ret = self.free;
self.free = cur;
trace!("set free to {}", unsafe {&*cur});
unsafe{&*ret}.payload
}
}
impl fmt::Display for Treadmill {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut cursor = self.free;
write!(f, "next: {}", self.from_space_next);
write!(f, "from:").unwrap();
for i in 0..self.spaces[self.from].len() {
write!(f, "{}->", self.spaces[self.from][i]).unwrap();
}
write!(f, "\n").unwrap();
loop {
write!(f, "{}", unsafe{&*cursor}).unwrap();
if cursor == self.free {
write!(f, "(free)").unwrap();
}
if cursor == self.scan {
write!(f, "(scan)").unwrap();
}
if cursor == self.b {
write!(f, "(bottom)").unwrap();
}
if unsafe{&*cursor}.next() == self.free {
break;
} else {
write!(f, "\n->").unwrap();
cursor = unsafe{&*cursor}.next();
}
write!(f, "to:").unwrap();
for i in 0..self.spaces[self.to].len() {
write!(f, "{}->", self.spaces[self.to][i]).unwrap();
}
Ok(())
write!(f, "\n")
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum TreadmillNodeColor {
Offwhite,
White,
Grey,
Black
}
struct TreadmillNode {
payload: Address,
color: u8,
prev: *mut TreadmillNode,
next: *mut TreadmillNode
}
impl fmt::Display for TreadmillNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}-{:?}]", self.payload, self.color)
}
payload: Address
}
impl TreadmillNode {
fn singleton(addr: Address) -> *mut TreadmillNode {
let mut ptr = Box::into_raw(Box::new(TreadmillNode {
payload: addr,
// starts as 0 (1, i.e. mark_state, means allocated/alive)
color: objectmodel::flip(objectmodel::load_mark_state()),
prev: ptr::null_mut(),
next: ptr::null_mut(),
}));
// first node in the cyclic doubly linked list
unsafe {
(*ptr).prev = ptr;
(*ptr).next = ptr;
}
ptr
}
/// returns the inserted node
fn init_insert_after(&mut self, addr: Address) -> *mut TreadmillNode {
unsafe {
// node <- ptr -> node.next
let mut ptr = Box::into_raw(Box::new(TreadmillNode {
payload: addr,
color: objectmodel::flip(objectmodel::load_mark_state()),
// inserted between node and node.next
prev: self as *mut TreadmillNode,
next: self.next
}));
// ptr <- node.next
unsafe{(&mut *self.next)}.prev = ptr;
// node -> ptr
self.next = ptr;
ptr
}
}
fn insert_after(&mut self, node: *mut TreadmillNode) {
unsafe {
// self <- node -> self.next
(&mut *node).next = self.next;
(&mut *node).prev = self as *mut TreadmillNode;
// self.next -> node
self.next = node;
// node <- node.next.prev
(&mut *(&mut *node).next).prev = node;
}
}
/// remove current node from treadmill, and returns the node
fn remove(&mut self) -> *mut TreadmillNode {
if self.next == self as *mut TreadmillNode && self.prev == self as *mut TreadmillNode {
// if this is the only node, return itself
self as *mut TreadmillNode
} else {
// we need to take it out from the list
unsafe {
use std::ptr;
// its prev node's next will be its next node
(&mut *self.prev).next = self.next as *mut TreadmillNode;
// its next node' prev will be its prev node
(&mut *self.next).prev = self.prev as *mut TreadmillNode;
// clear current node prev and next
self.prev = ptr::null_mut();
self.next = ptr::null_mut();
}
// then return it
self as *mut TreadmillNode
fn new(addr: Address) -> TreadmillNode {
TreadmillNode {
payload: addr
}
}
}
fn next(&self) -> *mut TreadmillNode {
self.next
}
fn prev(&self) -> *mut TreadmillNode {
self.prev
impl fmt::Display for TreadmillNode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.payload)
}
}
......@@ -450,6 +315,7 @@ mod tests {
}
#[test]
#[ignore]
fn test_treadmill_alloc_spanblock() {
let mut space = FreeListSpace::new(BLOCK_SIZE * 10);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment