Compare commits
2 Commits
a7a2a0a369
...
705df8dc1d
Author | SHA1 | Date |
---|---|---|
|
705df8dc1d | |
|
eeb126ab65 |
|
@ -25,7 +25,7 @@ void gc::mark() {
|
||||||
mark_context_root(bfs);
|
mark_context_root(bfs);
|
||||||
|
|
||||||
// concurrent mark, experimental
|
// concurrent mark, experimental
|
||||||
if (memory.size()>UINT16_MAX && bfs.size()>32) {
|
if (memory.size() > gc::concurrent_threshold() && bfs.size() > 16) {
|
||||||
flag_concurrent_mark_triggered = true;
|
flag_concurrent_mark_triggered = true;
|
||||||
usize size = bfs.size();
|
usize size = bfs.size();
|
||||||
std::thread t0(&gc::concurrent_mark, this, std::ref(bfs), 0, size/4);
|
std::thread t0(&gc::concurrent_mark, this, std::ref(bfs), 0, size/4);
|
||||||
|
@ -179,6 +179,29 @@ void gc::mark_map(std::vector<var>& bfs_queue, nas_map& mp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc::sweep() {
|
void gc::sweep() {
|
||||||
|
if (memory.size() > gc::concurrent_threshold()) {
|
||||||
|
flag_concurrent_mark_triggered = true;
|
||||||
|
usize size = memory.size();
|
||||||
|
std::vector<free_list> collect = {{}, {}, {}, {}};
|
||||||
|
std::thread t0(&gc::concurrent_sweep, this, std::ref(collect[0]), 0, size/4);
|
||||||
|
std::thread t1(&gc::concurrent_sweep, this, std::ref(collect[1]), size/4, size/2);
|
||||||
|
std::thread t2(&gc::concurrent_sweep, this, std::ref(collect[2]), size/2, size/4*3);
|
||||||
|
std::thread t3(&gc::concurrent_sweep, this, std::ref(collect[3]), size/4*3, size);
|
||||||
|
t0.join();
|
||||||
|
t1.join();
|
||||||
|
t2.join();
|
||||||
|
t3.join();
|
||||||
|
|
||||||
|
for (auto& i : collect) {
|
||||||
|
for (int j = 0; j < gc_type_size; ++j) {
|
||||||
|
for (auto ptr : i[j]) {
|
||||||
|
unused[j].push_back(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for(auto i : memory) {
|
for(auto i : memory) {
|
||||||
if (i->mark==nas_val::gc_status::uncollected) {
|
if (i->mark==nas_val::gc_status::uncollected) {
|
||||||
i->clear();
|
i->clear();
|
||||||
|
@ -190,6 +213,19 @@ void gc::sweep() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gc::concurrent_sweep(free_list& collect, usize begin, usize end) {
|
||||||
|
for (usize iter = begin; iter < end; ++ iter) {
|
||||||
|
auto i = memory[iter];
|
||||||
|
if (i->mark==nas_val::gc_status::uncollected) {
|
||||||
|
i->clear();
|
||||||
|
collect[static_cast<u8>(i->type)-static_cast<u8>(vm_type::vm_str)].push_back(i);
|
||||||
|
i->mark = nas_val::gc_status::collected;
|
||||||
|
} else if (i->mark==nas_val::gc_status::found) {
|
||||||
|
i->mark = nas_val::gc_status::uncollected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void gc::extend(const vm_type type) {
|
void gc::extend(const vm_type type) {
|
||||||
const u8 index = static_cast<u8>(type)-static_cast<u8>(vm_type::vm_str);
|
const u8 index = static_cast<u8>(type)-static_cast<u8>(vm_type::vm_str);
|
||||||
size[index] += incr[index];
|
size[index] += incr[index];
|
||||||
|
@ -223,7 +259,7 @@ void gc::extend(const vm_type type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if incr[index] = 1, this will always be 1
|
// if incr[index] = 1, this will always be 1
|
||||||
incr[index] = incr[index] + incr[index]/2;
|
incr[index] = incr[index] + incr[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void gc::init(const std::vector<std::string>& constant_strings,
|
void gc::init(const std::vector<std::string>& constant_strings,
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
|
|
||||||
namespace nasal {
|
namespace nasal {
|
||||||
|
|
||||||
|
struct free_list {
|
||||||
|
std::vector<nas_val*> elem[gc_type_size];
|
||||||
|
|
||||||
|
auto& operator[](i64 index) {
|
||||||
|
return elem[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct gc {
|
struct gc {
|
||||||
/* main context temporary storage */
|
/* main context temporary storage */
|
||||||
context main_context;
|
context main_context;
|
||||||
|
@ -39,18 +47,18 @@ struct gc {
|
||||||
std::vector<var> strs = {}; // reserved address for const vm_str
|
std::vector<var> strs = {}; // reserved address for const vm_str
|
||||||
std::vector<var> env_argv = {}; // command line arguments
|
std::vector<var> env_argv = {}; // command line arguments
|
||||||
std::vector<nas_val*> memory; // gc memory
|
std::vector<nas_val*> memory; // gc memory
|
||||||
std::vector<nas_val*> unused[gc_type_size]; // gc free list
|
free_list unused; // gc free list
|
||||||
|
|
||||||
/* heap increase size */
|
/* heap increase size */
|
||||||
u64 incr[gc_type_size] = {
|
u64 incr[gc_type_size] = {
|
||||||
128, // vm_str
|
256, // vm_str
|
||||||
128, // vm_vec
|
512, // vm_vec
|
||||||
64, // vm_hash
|
512, // vm_hash
|
||||||
256, // vm_func
|
256, // vm_func
|
||||||
256, // vm_upval
|
256, // vm_upval
|
||||||
16, // vm_obj
|
4, // vm_obj
|
||||||
16, // vm_co
|
4, // vm_co
|
||||||
2, // vm_map
|
1, // vm_map
|
||||||
};
|
};
|
||||||
// total memory usage, not very accurate
|
// total memory usage, not very accurate
|
||||||
u64 total_memory_usage = 0;
|
u64 total_memory_usage = 0;
|
||||||
|
@ -86,6 +94,11 @@ private:
|
||||||
void mark_co(std::vector<var>&, nas_co&);
|
void mark_co(std::vector<var>&, nas_co&);
|
||||||
void mark_map(std::vector<var>&, nas_map&);
|
void mark_map(std::vector<var>&, nas_map&);
|
||||||
void sweep();
|
void sweep();
|
||||||
|
void concurrent_sweep(free_list&, usize, usize);
|
||||||
|
|
||||||
|
static const auto concurrent_threshold() {
|
||||||
|
return UINT16_MAX * 16;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void extend(const vm_type);
|
void extend(const vm_type);
|
||||||
|
|
|
@ -225,12 +225,24 @@ void vm::function_call_trace() {
|
||||||
std::stack<const nas_func*> functions;
|
std::stack<const nas_func*> functions;
|
||||||
std::stack<u64> callsite;
|
std::stack<u64> callsite;
|
||||||
|
|
||||||
// load call trace
|
// load call trace, from bottom to top
|
||||||
for(var* i = bottom; i <= top; ++i) {
|
for(var* i = bottom; i <= top; ++i) {
|
||||||
// i-1 is the callsite program counter of this function
|
// i-1 is the callsite program counter of this function
|
||||||
if (i->is_addr() && i+2<=top &&
|
// +-------+----------------+
|
||||||
(i+1)->is_ret() && (i+1)->ret()>0 &&
|
// | func | func() {..} | <-- i + 2
|
||||||
(i+2)->is_func()) {
|
// +-------+----------------+
|
||||||
|
// | ret | 0x3bf | <-- i + 1 (value should not be 0x0)
|
||||||
|
// +-------+----------------+
|
||||||
|
// | addr | 0x7ff5f61ae020 | <-- i
|
||||||
|
// +-------+----------------+
|
||||||
|
// TODO: op_cnt may destroy the order, so maybe this need refact
|
||||||
|
if (i + 2 > top) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!i->is_addr()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ((i+1)->is_ret() && (i+1)->ret()>0 && (i+2)->is_func()) {
|
||||||
functions.push(&(i+2)->func());
|
functions.push(&(i+2)->func());
|
||||||
callsite.push((i+1)->ret());
|
callsite.push((i+1)->ret());
|
||||||
}
|
}
|
||||||
|
@ -239,10 +251,18 @@ void vm::function_call_trace() {
|
||||||
// another condition may exist
|
// another condition may exist
|
||||||
// have ret pc on stack, but no function at the top of the ret pc
|
// have ret pc on stack, but no function at the top of the ret pc
|
||||||
for(var * i = top; i >= bottom; --i) {
|
for(var * i = top; i >= bottom; --i) {
|
||||||
|
// +-------+----------------+
|
||||||
|
// | xxxx | xxxx | <-- i + 2 (not function or not exist)
|
||||||
|
// +-------+----------------+
|
||||||
|
// | ret | 0x3bf | <-- i + 1 (value should not be 0x0)
|
||||||
|
// +-------+----------------+
|
||||||
|
// | addr | 0x7ff5f61ae020 | <-- i
|
||||||
|
// +-------+----------------+
|
||||||
if ((i->is_addr() && i+2<=top && (i+1)->is_ret() && !(i+2)->is_func()) ||
|
if ((i->is_addr() && i+2<=top && (i+1)->is_ret() && !(i+2)->is_func()) ||
|
||||||
(i->is_addr() && i+1<=top && i+2>top && (i+1)->is_ret())) {
|
(i->is_addr() && i+1<=top && i+2>top && (i+1)->is_ret())) {
|
||||||
functions.push(&ctx.funcr.func());
|
functions.push(&ctx.funcr.func());
|
||||||
callsite.push((i+1)->ret());
|
callsite.push((i+1)->ret());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +390,7 @@ void vm::global_state() {
|
||||||
<< reinterpret_cast<u64>(global) << ")\n" << std::dec;
|
<< reinterpret_cast<u64>(global) << ")\n" << std::dec;
|
||||||
for(usize i = 0; i<global_size; ++i) {
|
for(usize i = 0; i<global_size; ++i) {
|
||||||
std::clog << " 0x" << std::hex << std::setw(8)
|
std::clog << " 0x" << std::hex << std::setw(8)
|
||||||
<< std::setfill('0') << i << std::dec
|
<< std::setfill('0') << static_cast<u64>(i) << std::dec
|
||||||
<< " ";
|
<< " ";
|
||||||
auto name = global_symbol_name[i];
|
auto name = global_symbol_name[i];
|
||||||
if (name.length()>=10) {
|
if (name.length()>=10) {
|
||||||
|
@ -379,7 +399,8 @@ void vm::global_state() {
|
||||||
|
|
||||||
}
|
}
|
||||||
std::clog << "| " << std::left << std::setw(10)
|
std::clog << "| " << std::left << std::setw(10)
|
||||||
<< std::setfill(' ') << name << " ";
|
<< std::setfill(' ') << name << " "
|
||||||
|
<< std::internal;
|
||||||
value_info(global[i]);
|
value_info(global[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,18 @@ var test_func = func(test_processes...) {
|
||||||
var info = runtime.gc.info();
|
var info = runtime.gc.info();
|
||||||
var gc_total = info.total;
|
var gc_total = info.total;
|
||||||
var duration = 0;
|
var duration = 0;
|
||||||
foreach(var f; test_processes) {
|
foreach (var t; test_processes) {
|
||||||
println("[", os.time(), "] testing ", id(f));
|
var name = t[0];
|
||||||
|
var f = t[1];
|
||||||
|
print("[", os.time(), "] testing ", name, " : ");
|
||||||
time_stamp.stamp();
|
time_stamp.stamp();
|
||||||
f();
|
f();
|
||||||
duration = time_stamp.elapsedMSec();
|
duration = time_stamp.elapsedMSec();
|
||||||
info = runtime.gc.info();
|
info = runtime.gc.info();
|
||||||
println("[", os.time(), "] ", duration, " ms, gc ",
|
println(duration, " ms,\tgc ",
|
||||||
(info.total-gc_total)*100/duration, "%, ",
|
(info.total-gc_total)*100/duration, "%,\t",
|
||||||
1000/duration, " cps");
|
1000/duration, " loop/sec"
|
||||||
|
);
|
||||||
gc_total = info.total;
|
gc_total = info.total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,32 +28,34 @@ var test_func = func(test_processes...) {
|
||||||
test_process_total.elapsedMSec(), " ms");
|
test_process_total.elapsedMSec(), " ms");
|
||||||
|
|
||||||
info = runtime.gc.info();
|
info = runtime.gc.info();
|
||||||
println("##-gc----------------");
|
println("+##-gc-----------------");
|
||||||
println("total : ", info.total, " ms");
|
println("| total : ", info.total, " ms");
|
||||||
println("average : ", info.average, " ms");
|
println("| average : ", info.average, " ms");
|
||||||
println("max gc : ", info.max_gc, " ms");
|
println("| max gc : ", info.max_gc, " ms");
|
||||||
println("max mark : ", info.max_mark, " ms");
|
println("| max mark : ", info.max_mark, " ms");
|
||||||
println("max sweep: ", info.max_sweep, " ms");
|
println("| max sweep: ", info.max_sweep, " ms");
|
||||||
println("---------------------");
|
println("+----------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var MAX_ITER_NUM = 2e5;
|
||||||
|
|
||||||
var append_vec = func {
|
var append_vec = func {
|
||||||
var res = [];
|
var res = [];
|
||||||
for(var i=0; i<1e6; i+=1) {
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
append(res, [1]);
|
append(res, [1, 2, 3, 4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var append_hash = func {
|
var append_hash = func {
|
||||||
var res = [];
|
var res = [];
|
||||||
for(var i=0; i<1e6; i+=1) {
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
append(res, {a:1, b:2});
|
append(res, {a:1, b:2, c:3, d:4});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var append_func = func {
|
var append_func = func {
|
||||||
var res = [];
|
var res = [];
|
||||||
for(var i=0; i<1e6; i+=1) {
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
append(res, func {
|
append(res, func {
|
||||||
println(arg);
|
println(arg);
|
||||||
});
|
});
|
||||||
|
@ -59,23 +64,40 @@ var append_func = func {
|
||||||
|
|
||||||
var append_vec_in_vec = func {
|
var append_vec_in_vec = func {
|
||||||
var res = [];
|
var res = [];
|
||||||
for(var i=0; i<1e6; i+=1) {
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
append(res, [[]]);
|
append(res, [[], [], [], []]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var append_hash_in_vec = func {
|
||||||
|
var res = [];
|
||||||
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
|
append(res, {a:{}, b:{}, c:{}, d:{}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var append_vec_in_hash = func {
|
var append_vec_in_hash = func {
|
||||||
for(var i=0; i<1e6; i+=1) {
|
var res = [];
|
||||||
append([], {a:[], b:[]});
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
|
append(res, {a:[], b:[], c:[], d:[]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(var i=0; i<10; i+=1) {
|
var append_hash_in_hash = func {
|
||||||
|
var res = [];
|
||||||
|
for(var i=0; i<MAX_ITER_NUM; i+=1) {
|
||||||
|
append(res, {a:{}, b:{}, c:{}, d:{}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < 10; i += 1) {
|
||||||
test_func(
|
test_func(
|
||||||
append_vec,
|
["vec ", append_vec],
|
||||||
append_hash,
|
["hash ", append_hash],
|
||||||
append_func,
|
["func ", append_func],
|
||||||
append_vec_in_vec,
|
["vec<vec> ", append_vec_in_vec],
|
||||||
append_vec_in_hash
|
["vec<hash> ", append_hash_in_vec],
|
||||||
|
["hash<str, vec> ", append_vec_in_hash],
|
||||||
|
["hash<str, hash>", append_hash_in_hash]
|
||||||
);
|
);
|
||||||
}
|
}
|
Loading…
Reference in New Issue