Commit deda25ca authored by qinsoon's avatar qinsoon

Merge branch 'develop' into swapstack

parents 9072c4b6 2ad245a8
stages:
- build
- test
- mubench
- rustfmt
before_script:
......@@ -14,7 +15,7 @@ build:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --release --no-run --color=always
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test -j6 --release --no-run --color=always
artifacts:
paths:
- target/release/libmu.so
......@@ -136,6 +137,24 @@ testjit:som:
- cd $CI_PROJECT_DIR/tests/test_jit
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=./emit RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy:RPySOM/src RPYSOM=RPySOM pytest test_som.py -v --color=yes
mubench:
stage: mubench
script:
- deactivate
- git clone https://gitlab.anu.edu.au/mu/mu-perf-benchmarks.git
- git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git
- cd mu-client-pypy; git apply pypy.patch; git apply clang_opt_flag.patch; cd $CI_PROJECT_DIR
- git clone https://github.com/microvm/RPySOM.git
- cd RPySOM; git submodule init; git submodule update; cd $CI_PROJECT_DIR
- export RPYSOM=RPySOM
- export PYPY=mu-client-pypy
- virtualenv -p python3 mubench_venv
- source mubench_venv/bin/activate
- pip install -Ue ./mu-perf-benchmarks
- mkdir example
- mubench local ./mu-perf-benchmarks/example/mu-impl-fast.yml --dump /home/gitlab-runner/results/$(git log -1 --pretty="%h_%at") --pipeline ""
- rsync -a /home/gitlab-runner/results/* squirrel:~/mu-impl-fast/angus
rustfmt:
stage: rustfmt
script:
......
// Copyright 2017 The Australian National University
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate gc;
extern crate utils;
extern crate mu_gc as gc;
extern crate mu_utils as utils;
extern crate simple_logger;
extern crate log;
......@@ -26,42 +26,42 @@ use std::sync::atomic::Ordering;
pub fn start_logging() {
match simple_logger::init_with_level(LogLevel::Trace) {
Ok(_) => {},
Ok(_) => {}
Err(_) => {}
}
}
const OBJECT_SIZE : usize = 24;
const OBJECT_SIZE: usize = 24;
const OBJECT_ALIGN: usize = 8;
const WORK_LOAD : usize = 10000;
const WORK_LOAD: usize = 10000;
#[allow(dead_code)]
const SPACIOUS_SPACE_SIZE : usize = 500 << 20; // 500mb
const SPACIOUS_SPACE_SIZE: usize = 500 << 20; // 500mb
#[allow(dead_code)]
const LIMITED_SPACE_SIZE : usize = 20 << 20; // 20mb
const LIMITED_SPACE_SIZE: usize = 20 << 20; // 20mb
#[allow(dead_code)]
const SMALL_SPACE_SIZE : usize = 1 << 19; // 512kb
const SMALL_SPACE_SIZE: usize = 1 << 19; // 512kb
#[allow(dead_code)]
const IMMIX_SPACE_SIZE : usize = SPACIOUS_SPACE_SIZE;
const IMMIX_SPACE_SIZE: usize = SPACIOUS_SPACE_SIZE;
#[allow(dead_code)]
const LO_SPACE_SIZE : usize = SPACIOUS_SPACE_SIZE;
const LO_SPACE_SIZE: usize = SPACIOUS_SPACE_SIZE;
#[cfg(feature = "use-sidemap")]
const FIXSIZE_NOREF_ENCODE : u64 = 0b1100_0000u64;
const FIXSIZE_NOREF_ENCODE: u64 = 0b1100_0000u64;
#[cfg(not(feature = "use-sidemap"))]
const FIXSIZE_NOREF_ENCODE : u64 = 0xb000000000000000u64;
const FIXSIZE_NOREF_ENCODE: u64 = 0xb000000000000000u64;
#[cfg(feature = "use-sidemap")]
const FIXSIZE_REFx2_ENCODE : u64 = 0b1100_0011u64;
const FIXSIZE_REFx2_ENCODE: u64 = 0b1100_0011u64;
#[cfg(not(feature = "use-sidemap"))]
const FIXSIZE_REFx2_ENCODE : u64 = 0xb000000000000003u64;
const FIXSIZE_REFx2_ENCODE: u64 = 0xb000000000000003u64;
#[cfg(feature = "use-sidemap")]
const FIXSIZE_REFx1_ENCODE : u64 = 0b1100_0001u64;
const FIXSIZE_REFx1_ENCODE: u64 = 0b1100_0001u64;
#[cfg(not(feature = "use-sidemap"))]
const FIXSIZE_REFx1_ENCODE : u64 = 0xb000000000000001u64;
const FIXSIZE_REFx1_ENCODE: u64 = 0xb000000000000001u64;
#[test]
......@@ -69,10 +69,23 @@ pub fn test_exhaust_alloc() {
gc::gc_init(IMMIX_SPACE_SIZE, LO_SPACE_SIZE, 8, false);
let mut mutator = gc::new_mutator();
println!("Trying to allocate {} objects of (size {}, align {}). ", WORK_LOAD, OBJECT_SIZE, OBJECT_ALIGN);
const ACTUAL_OBJECT_SIZE : usize = OBJECT_SIZE;
println!("Considering header size of {}, an object should be {}. ", 0, ACTUAL_OBJECT_SIZE);
println!("This would take {} bytes of {} bytes heap", WORK_LOAD * ACTUAL_OBJECT_SIZE, heap::IMMIX_SPACE_SIZE.load(Ordering::SeqCst));
println!(
"Trying to allocate {} objects of (size {}, align {}). ",
WORK_LOAD,
OBJECT_SIZE,
OBJECT_ALIGN
);
const ACTUAL_OBJECT_SIZE: usize = OBJECT_SIZE;
println!(
"Considering header size of {}, an object should be {}. ",
0,
ACTUAL_OBJECT_SIZE
);
println!(
"This would take {} bytes of {} bytes heap",
WORK_LOAD * ACTUAL_OBJECT_SIZE,
heap::IMMIX_SPACE_SIZE.load(Ordering::SeqCst)
);
for _ in 0..WORK_LOAD {
mutator.yieldpoint();
......@@ -84,7 +97,7 @@ pub fn test_exhaust_alloc() {
mutator.destroy();
}
const LARGE_OBJECT_SIZE : usize = 256;
const LARGE_OBJECT_SIZE: usize = 256;
#[test]
#[allow(unused_variables)]
......@@ -107,8 +120,8 @@ fn test_exhaust_alloc_large() {
#[test]
#[allow(unused_variables)]
fn test_alloc_large_lo_trigger_gc() {
const KEEP_N_ROOTS : usize = 1;
let mut roots : usize = 0;
const KEEP_N_ROOTS: usize = 1;
let mut roots: usize = 0;
gc::gc_init(SMALL_SPACE_SIZE, 4096 * 10, 8, true);
let mut mutator = gc::new_mutator();
......@@ -167,17 +180,29 @@ fn test_alloc_mark() {
gc::gc_init(IMMIX_SPACE_SIZE, LO_SPACE_SIZE, 8, false);
let mut mutator = gc::new_mutator();
println!("Trying to allocate 1 object of (size {}, align {}). ", OBJECT_SIZE, OBJECT_ALIGN);
const ACTUAL_OBJECT_SIZE : usize = OBJECT_SIZE;
println!("Considering header size of {}, an object should be {}. ", 0, ACTUAL_OBJECT_SIZE);
println!("Trying to allocate {} objects, which will take roughly {} bytes", WORK_LOAD, WORK_LOAD * ACTUAL_OBJECT_SIZE);
println!(
"Trying to allocate 1 object of (size {}, align {}). ",
OBJECT_SIZE,
OBJECT_ALIGN
);
const ACTUAL_OBJECT_SIZE: usize = OBJECT_SIZE;
println!(
"Considering header size of {}, an object should be {}. ",
0,
ACTUAL_OBJECT_SIZE
);
println!(
"Trying to allocate {} objects, which will take roughly {} bytes",
WORK_LOAD,
WORK_LOAD * ACTUAL_OBJECT_SIZE
);
let mut objs = vec![];
for _ in 0..WORK_LOAD {
let res = mutator.alloc(ACTUAL_OBJECT_SIZE, OBJECT_ALIGN);
mutator.init_object(res, FIXSIZE_REFx2_ENCODE);
objs.push(unsafe {res.to_object_reference()});
objs.push(unsafe { res.to_object_reference() });
}
let (shared_space, _) = gc::get_spaces();
......@@ -191,7 +216,7 @@ fn test_alloc_mark() {
let trace_map = shared_space.trace_map.ptr;
for i in 0..objs.len() {
let obj = unsafe {*objs.get_unchecked(i)};
let obj = unsafe { *objs.get_unchecked(i) };
// mark the object as traced
objectmodel::mark_as_traced(trace_map, space_start, obj, mark_state);
......@@ -211,17 +236,29 @@ fn test_alloc_mark() {
gc::gc_init(IMMIX_SPACE_SIZE, LO_SPACE_SIZE, 8, false);
let mut mutator = gc::new_mutator();
println!("Trying to allocate 1 object of (size {}, align {}). ", OBJECT_SIZE, OBJECT_ALIGN);
const ACTUAL_OBJECT_SIZE : usize = OBJECT_SIZE;
println!("Considering header size of {}, an object should be {}. ", 0, ACTUAL_OBJECT_SIZE);
println!("Trying to allocate {} objects, which will take roughly {} bytes", WORK_LOAD, WORK_LOAD * ACTUAL_OBJECT_SIZE);
println!(
"Trying to allocate 1 object of (size {}, align {}). ",
OBJECT_SIZE,
OBJECT_ALIGN
);
const ACTUAL_OBJECT_SIZE: usize = OBJECT_SIZE;
println!(
"Considering header size of {}, an object should be {}. ",
0,
ACTUAL_OBJECT_SIZE
);
println!(
"Trying to allocate {} objects, which will take roughly {} bytes",
WORK_LOAD,
WORK_LOAD * ACTUAL_OBJECT_SIZE
);
let mut objs = vec![];
for _ in 0..WORK_LOAD {
let res = mutator.alloc(ACTUAL_OBJECT_SIZE, OBJECT_ALIGN);
mutator.init_object(res, FIXSIZE_REFx2_ENCODE);
objs.push(unsafe {res.to_object_reference()});
objs.push(unsafe { res.to_object_reference() });
}
let (shared_space, _) = gc::get_spaces();
......@@ -235,7 +272,7 @@ fn test_alloc_mark() {
let trace_map = shared_space.trace_map.ptr;
for i in 0..objs.len() {
let obj = unsafe {*objs.get_unchecked(i)};
let obj = unsafe { *objs.get_unchecked(i) };
// mark the object as traced
objectmodel::mark_as_traced(obj, mark_state);
......@@ -251,10 +288,10 @@ fn test_alloc_mark() {
#[allow(dead_code)]
struct Node<'a> {
hdr : u64,
next : &'a Node<'a>,
unused_ptr : usize,
unused_int : i32,
hdr: u64,
next: &'a Node<'a>,
unused_ptr: usize,
unused_int: i32,
unused_int2: i32
}
......@@ -264,11 +301,23 @@ fn test_alloc_trace() {
let mut mutator = gc::new_mutator();
let (shared_space, lo_space) = gc::get_spaces();
println!("Trying to allocate 1 object of (size {}, align {}). ", OBJECT_SIZE, OBJECT_ALIGN);
const ACTUAL_OBJECT_SIZE : usize = OBJECT_SIZE;
println!("Considering header size of {}, an object should be {}. ", 0, ACTUAL_OBJECT_SIZE);
println!("Trying to allocate {} objects, which will take roughly {} bytes", WORK_LOAD, WORK_LOAD * ACTUAL_OBJECT_SIZE);
println!(
"Trying to allocate 1 object of (size {}, align {}). ",
OBJECT_SIZE,
OBJECT_ALIGN
);
const ACTUAL_OBJECT_SIZE: usize = OBJECT_SIZE;
println!(
"Considering header size of {}, an object should be {}. ",
0,
ACTUAL_OBJECT_SIZE
);
println!(
"Trying to allocate {} objects, which will take roughly {} bytes",
WORK_LOAD,
WORK_LOAD * ACTUAL_OBJECT_SIZE
);
let root = mutator.alloc(ACTUAL_OBJECT_SIZE, OBJECT_ALIGN);
mutator.init_object(root, FIXSIZE_REFx1_ENCODE);
......@@ -278,13 +327,13 @@ fn test_alloc_trace() {
mutator.init_object(res, FIXSIZE_REFx1_ENCODE);
// set prev's 1st field (offset 0) to this object
unsafe {prev.store::<Address>(res)};
unsafe { prev.store::<Address>(res) };
prev = res;
}
println!("Start tracing");
let mut roots = vec![unsafe {root.to_object_reference()}];
let mut roots = vec![unsafe { root.to_object_reference() }];
heap::gc::start_trace(&mut roots, shared_space, lo_space);
......
// Copyright 2017 The Australian National University
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern crate gc;
extern crate utils;
extern crate mu_gc as gc;
extern crate mu_utils as utils;
use std::ptr;
extern crate simple_logger;
......@@ -24,31 +24,31 @@ use std::fmt;
pub fn start_logging() {
match simple_logger::init_with_level(LogLevel::Trace) {
Ok(_) => {},
Ok(_) => {}
Err(_) => {}
}
}
#[derive(Copy, Clone)]
struct Node {
next : *mut Node,
next: *mut Node,
payload: usize
}
struct LinkedList<'a> {
head: *mut Node,
tail: *mut Node,
len : usize,
len: usize,
allocator: &'a mut ImmixMutatorLocal
}
impl <'a> LinkedList<'a> {
impl<'a> LinkedList<'a> {
fn new(allocator: &mut ImmixMutatorLocal) -> LinkedList {
LinkedList {
head: ptr::null_mut(),
tail: ptr::null_mut(),
len : 0,
len: 0,
allocator: allocator
}
......@@ -60,7 +60,7 @@ impl <'a> LinkedList<'a> {
self.head = node;
self.tail = node;
self.len = 1;
self.len = 1;
} else {
let node = Node::new(self.allocator, val);
......@@ -74,7 +74,11 @@ impl <'a> LinkedList<'a> {
fn verify(&self, expect: Vec<usize>) {
if self.len != expect.len() {
panic!("Linked List length: {}, expected length: {}", self.len, expect.len());
panic!(
"Linked List length: {}, expected length: {}",
self.len,
expect.len()
);
}
let mut i = 0;
......@@ -82,32 +86,38 @@ impl <'a> LinkedList<'a> {
while cursor != self.tail {
println!("-verifying {:?}-", cursor);
println!("{:?}", unsafe {*cursor});
println!("{:?}", unsafe { *cursor });
let val = unsafe {(*cursor).payload};
let val = unsafe { (*cursor).payload };
let expect_val = expect[i];
if val != expect_val {
panic!("Linked List[{}] = {}, expect[{}] = {}", i, val, i, expect_val);
panic!(
"Linked List[{}] = {}, expect[{}] = {}",
i,
val,
i,
expect_val
);
}
cursor = unsafe {(*cursor).next};
cursor = unsafe { (*cursor).next };
i += 1;
}
}
}
impl <'a> fmt::Debug for LinkedList<'a> {
impl<'a> fmt::Debug for LinkedList<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut cursor = self.head;
// non-tail
while cursor != self.tail {
write!(f, "{:?}, ", unsafe {*cursor}).unwrap();
cursor = unsafe{*cursor}.next;
write!(f, "{:?}, ", unsafe { *cursor }).unwrap();
cursor = unsafe { *cursor }.next;
}
write!(f, "{:?}", unsafe {*cursor}).unwrap();
write!(f, "{:?}", unsafe { *cursor }).unwrap();
Ok(())
}
......@@ -123,9 +133,9 @@ use self::utils::{ObjectReference, Address};
use std::mem::size_of;
#[cfg(feature = "use-sidemap")]
const NODE_ENCODE : u64 = 0b1100_0001u64;
const NODE_ENCODE: u64 = 0b1100_0001u64;
#[cfg(not(feature = "use-sidemap"))]
const NODE_ENCODE : u64 = 0xb000000000000001u64;
const NODE_ENCODE: u64 = 0xb000000000000001u64;
impl Node {
fn new(mutator: &mut ImmixMutatorLocal, val: usize) -> *mut Node {
......@@ -142,7 +152,7 @@ impl Node {
unsafe {
(*ptr).payload = val;
}
println!("result: {:?}", unsafe {*ptr});
println!("result: {:?}", unsafe { *ptr });
ptr
}
......@@ -154,12 +164,14 @@ impl fmt::Debug for Node {
}
}
const IMMIX_SPACE_SIZE : usize = 40 << 20;
const LO_SPACE_SIZE : usize = 0 << 20;
const IMMIX_SPACE_SIZE: usize = 40 << 20;
const LO_SPACE_SIZE: usize = 0 << 20;
#[test]
fn create_linked_list() {
unsafe {heap::gc::set_low_water_mark();}
unsafe {
heap::gc::set_low_water_mark();
}
start_logging();
......@@ -187,7 +199,9 @@ fn create_linked_list() {
#[test]
fn linked_list_heap_dump() {
unsafe {heap::gc::set_low_water_mark();}
unsafe {
heap::gc::set_low_water_mark();
}
start_logging();
......@@ -224,7 +238,9 @@ fn linked_list_heap_dump() {
#[ignore]
// disable this test because it will cause gcbench fail for unknown reason
fn linked_list_survive_gc() {
unsafe {heap::gc::set_low_water_mark();}
unsafe {
heap::gc::set_low_water_mark();
}
start_logging();
......
// Copyright 2017 The Australian National University
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
......@@ -19,9 +19,9 @@
#![allow(dead_code)]
#![allow(unused_imports)]
extern crate gc;
extern crate mu_gc as gc;
extern crate mu_utils as utils;
extern crate time;
extern crate utils;
use self::gc::heap;
use self::gc::heap::immix::ImmixMutatorLocal;
......@@ -39,29 +39,29 @@ use self::log::LogLevel;
pub fn start_logging() {
match simple_logger::init_with_level(LogLevel::Trace) {
Ok(_) => {},
Ok(_) => {}
Err(_) => {}
}
}
const IMMIX_SPACE_SIZE : usize = 40 << 20;
const LO_SPACE_SIZE : usize = 40 << 20;
const IMMIX_SPACE_SIZE: usize = 40 << 20;
const LO_SPACE_SIZE: usize = 40 << 20;
const kStretchTreeDepth : i32 = 18;
const kLongLivedTreeDepth : i32 = 16;
const kArraySize : i32 = 500000;
const kMinTreeDepth : i32 = 4;
const kMaxTreeDepth : i32 = 16;
const kStretchTreeDepth: i32 = 18;
const kLongLivedTreeDepth: i32 = 16;
const kArraySize: i32 = 500000;
const kMinTreeDepth: i32 = 4;
const kMaxTreeDepth: i32 = 16;
struct Node {
left : *mut Node,
right : *mut Node,
i : i32,
j : i32
left: *mut Node,
right: *mut Node,
i: i32,
j: i32
}
struct Array {
value : [f64; kArraySize as usize]
value: [f64; kArraySize as usize]
}
fn init_Node(me: *mut Node, l: *mut Node, r: *mut Node) {
......@@ -71,7 +71,7 @@ fn init_Node(me: *mut Node, l: *mut Node, r: *mut Node) {
}
}
fn TreeSize(i: i32) -> i32{
fn TreeSize(i: i32) -> i32 {
(1 << (i + 1)) - 1
}
......@@ -105,9 +105,7 @@ fn MakeTree(iDepth: i32, mutator: &mut ImmixMutatorLocal) -> *mut Node {
}
}
fn PrintDiagnostics() {
}
fn PrintDiagnostics() {}
fn TimeConstruction(depth: i32, mutator: &mut ImmixMutatorLocal) {
let iNumIters = NumIters(depth);
......@@ -121,20 +119,26 @@ fn TimeConstruction(depth: i32, mutator: &mut ImmixMutatorLocal) {
// destroy tempTree
}
let tFinish = time::now_utc();
println!("\tTop down construction took {} msec", (tFinish - tStart).num_milliseconds());
println!(
"\tTop down construction took {} msec",
(tFinish - tStart).num_milliseconds()
);
let tStart = time::now_utc();
for _ in 0..iNumIters {
let tempTree = MakeTree(depth, mutator);
}
let tFinish = time::now_utc();
println!("\tButtom up construction took {} msec", (tFinish - tStart).num_milliseconds());
println!(
"\tButtom up construction took {} msec",
(tFinish - tStart).num_milliseconds()
);
}
#[cfg(feature = "use-sidemap")]
const FIXSIZE_REFx2_ENCODE : u64 = 0b1100_0011u64;
const FIXSIZE_REFx2_ENCODE: u64 = 0b1100_0011u64;
#[cfg(not(feature = "use-sidemap"))]
const FIXSIZE_REFx2_ENCODE : u64 = 0xb000000000000003u64;
const FIXSIZE_REFx2_ENCODE: u64 = 0xb000000000000003u64;
#[inline(always)]
#[cfg(feature = "use-sidemap")]
......@@ -163,7 +167,9 @@ fn alloc(mutator: &mut ImmixMutatorLocal) -> *mut Node {
#[test]
fn start() {
unsafe {heap::gc::set_low_water_mark();}
unsafe {
heap::gc::set_low_water_mark();
}
start_logging();
......@@ -174,11 +180,16 @@ fn start() {
println!("Garbage Collector Test");
println!(" Node size = {}", size_of::<Node>());
println!(" Live storage will peak at {} bytes.\n",
2 * (size_of::<Node>() as i32) * TreeSize(kLongLivedTreeDepth) +
(size_of::<Array>() as i32));
println!(" Stretching memory with a binary tree or depth {}", kStretchTreeDepth);
println!(
" Live storage will peak at {} bytes.\n",
2 * (size_of::<Node>() as i32) * TreeSize(kLongLivedTreeDepth) +
(size_of::<Array>() as i32)
);
println!(
" Stretching memory with a binary tree or depth {}",
kStretchTreeDepth
);
PrintDiagnostics();
let tStart = time::now_utc();
......@@ -187,10 +198,15 @@ fn start() {
// destroy tree
// Create a long lived object
println!(" Creating a long-lived binary tree of depth {}", kLongLivedTreeDepth);
println!(
" Creating a long-lived binary tree of depth {}",
kLongLivedTreeDepth
);
let longLivedTree = alloc(&mut mutator);
Populate(kLongLivedTreeDepth, longLivedTree, &mut mutator);
gc::add_to_root(unsafe{Address::from_mut_ptr(longLivedTree).to_object_reference()});
gc::add_to_root(unsafe {
Address::from_mut_ptr(longLivedTree).to_object_reference()
});
println!(" Creating a long-lived array of {} doubles", kArraySize);
// mm::alloc_large(&mut mutator, size_of::<Array>(), 8);
......@@ -216,7 +232,10 @@ fn start() {
PrintDiagnostics();
println!("Completed in {} msec", tElapsed);
println!("Finished with {} collections", heap::gc::GC_COUNT.load(Ordering::SeqCst));
println!(
"Finished with {} collections",
heap::gc::GC_COUNT.load(Ordering::SeqCst)
);
mutator.destroy();
}
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