diff --git a/src/nasal_gc.cpp b/src/nasal_gc.cpp index 00975b9..311289d 100644 --- a/src/nasal_gc.cpp +++ b/src/nasal_gc.cpp @@ -6,10 +6,21 @@ namespace nasal { void gc::do_mark_sweep() { using clk = std::chrono::high_resolution_clock; auto begin = clk::now(); - mark(); + if (!in_sweep_stage) { + mark(); + in_sweep_stage = true; + current_sweep_index = memory.size() - 1; + } auto mark_end = clk::now(); sweep(); auto sweep_end = clk::now(); + if (!in_sweep_stage) { + for (auto i : memory) { + if (i->mark == nas_val::gc_status::found) { + i->mark = nas_val::gc_status::uncollected; + } + } + } auto total_time = (sweep_end-begin).count(); auto mark_time = (mark_end-begin).count(); @@ -74,15 +85,15 @@ void gc::concurrent_mark(std::vector& vec, usize begin, usize end) { void gc::mark_context_root(std::vector& bfs_queue) { // scan global - for(usize i = 0; ivm_type::vm_num) { + if (val.type > vm_type::vm_num) { bfs_queue.push_back(val); } } // scan now running context, this context maybe related to coroutine or main - for(var* i = running_context->stack; i<=running_context->top; ++i) { - if (i->type>vm_type::vm_num) { + for(var* i = running_context->stack; i <= running_context->top; ++i) { + if (i->type > vm_type::vm_num) { bfs_queue.push_back(*i); } } @@ -95,8 +106,8 @@ void gc::mark_context_root(std::vector& bfs_queue) { } // coroutine is running, so scan main process stack from mctx - for(var* i = main_context.stack; i<=main_context.top; ++i) { - if (i->type>vm_type::vm_num) { + for(var* i = main_context.stack; i <= main_context.top; ++i) { + if (i->type > vm_type::vm_num) { bfs_queue.push_back(*i); } } @@ -120,7 +131,7 @@ void gc::mark_var(std::vector& bfs_queue, var& value) { void gc::mark_vec(std::vector& bfs_queue, nas_vec& vec) { for(auto& i : vec.elems) { - if (i.type>vm_type::vm_num) { + if (i.type > vm_type::vm_num) { bfs_queue.push_back(i); } } @@ -128,7 +139,7 @@ void gc::mark_vec(std::vector& bfs_queue, nas_vec& vec) { void gc::mark_hash(std::vector& bfs_queue, nas_hash& hash) { for(auto& i : hash.elems) { - if (i.second.type>vm_type::vm_num) { + if (i.second.type > vm_type::vm_num) { bfs_queue.push_back(i.second); } } @@ -136,7 +147,7 @@ void gc::mark_hash(std::vector& bfs_queue, nas_hash& hash) { void gc::mark_func(std::vector& bfs_queue, nas_func& function) { for(auto& i : function.local) { - if (i.type>vm_type::vm_num) { + if (i.type > vm_type::vm_num) { bfs_queue.push_back(i); } } @@ -147,7 +158,7 @@ void gc::mark_func(std::vector& bfs_queue, nas_func& function) { void gc::mark_upval(std::vector& bfs_queue, nas_upval& upval) { for(auto& i : upval.elems) { - if (i.type>vm_type::vm_num) { + if (i.type > vm_type::vm_num) { bfs_queue.push_back(i); } } @@ -164,7 +175,7 @@ void gc::mark_co(std::vector& bfs_queue, nas_co& co) { bfs_queue.push_back(co.ctx.funcr); bfs_queue.push_back(co.ctx.upvalr); for(var* i = co.ctx.stack; i<=co.ctx.top; ++i) { - if (i->type>vm_type::vm_num) { + if (i->type > vm_type::vm_num) { bfs_queue.push_back(*i); } } @@ -172,65 +183,36 @@ void gc::mark_co(std::vector& bfs_queue, nas_co& co) { void gc::mark_map(std::vector& bfs_queue, nas_map& mp) { for(const auto& i : mp.mapper) { - if (i.second->type>vm_type::vm_num) { + if (i.second->type > vm_type::vm_num) { bfs_queue.push_back(*i.second); } } } void gc::sweep() { - if (memory.size() > gc::concurrent_threshold()) { - flag_concurrent_mark_triggered = true; - usize size = memory.size(); - std::vector 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) { - unused[j].insert( - unused[j].end(), - std::make_move_iterator(i[j].begin()), - std::make_move_iterator(i[j].end()) - ); - } + const i64 threshold = 65536 / 4; + for (i64 it = 0; it < threshold; ++it) { + if (current_sweep_index - it < 0) { + break; } - return; - } - - for(auto i : memory) { + auto i = memory[current_sweep_index - it]; if (i->mark==nas_val::gc_status::uncollected) { - i->clear(); unused[static_cast(i->type)-static_cast(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::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(i->type)-static_cast(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; - } + current_sweep_index -= threshold; + if (current_sweep_index < 0) { + in_sweep_stage = false; + current_sweep_index = 0; } } void gc::extend(const vm_type type) { const u8 index = static_cast(type)-static_cast(vm_type::vm_str); - size[index] += incr[index]; + object_size[index] += incr[index]; for(u64 i = 0; i& constant_strings, // initialize counters worktime = 0; for(u8 i = 0; i(gcnt[i]); + total += static_cast(gc_count[i]); std::clog << "│ " << left << setw(indent) << setfill(' ') << name[i]; - std::clog << " │ " << left << setw(indent) << setfill(' ') << gcnt[i]; - std::clog << " │ " << left << setw(indent) << setfill(' ') << acnt[i]; - std::clog << " │ " << left << setw(indent) << setfill(' ') << size[i]; + std::clog << " │ " << left << setw(indent) << setfill(' ') << gc_count[i]; + std::clog << " │ " << left << setw(indent) << setfill(' ') << alloc_count[i]; + std::clog << " │ " << left << setw(indent) << setfill(' ') << object_size[i]; std::clog << " │\n"; } std::clog << mid_line << "\n"; @@ -460,17 +442,23 @@ void gc::info() const { } var gc::alloc(const vm_type type) { - const u8 index = static_cast(type)-static_cast(vm_type::vm_str); - ++acnt[index]; + const u32 index = static_cast(type)-static_cast(vm_type::vm_str); + ++alloc_count[index]; if (unused[index].empty()) { - ++gcnt[index]; + ++gc_count[index]; + do_mark_sweep(); + } + while (unused[index].empty() && in_sweep_stage) { do_mark_sweep(); } if (unused[index].empty()) { extend(type); } var ret = var::gcobj(unused[index].back()); - ret.val.gcobj->mark = nas_val::gc_status::uncollected; + ret.val.gcobj->clear(); + ret.val.gcobj->mark = in_sweep_stage + ? nas_val::gc_status::found + : nas_val::gc_status::uncollected; unused[index].pop_back(); return ret; } diff --git a/src/nasal_gc.h b/src/nasal_gc.h index 36adead..82bdecf 100644 --- a/src/nasal_gc.h +++ b/src/nasal_gc.h @@ -52,8 +52,8 @@ struct gc { /* heap increase size */ u64 incr[gc_type_size] = { 256, // vm_str - 512, // vm_vec - 512, // vm_hash + 256, // vm_vec + 256, // vm_hash 256, // vm_func 256, // vm_upval 4, // vm_obj @@ -65,15 +65,18 @@ struct gc { u64 total_object_count = 0; /* values for analysis */ - u64 size[gc_type_size]; - u64 gcnt[gc_type_size]; - u64 acnt[gc_type_size]; + u64 object_size[gc_type_size]; + u64 gc_count[gc_type_size]; + u64 alloc_count[gc_type_size]; i64 worktime = 0; i64 max_time = 0; i64 max_mark_time = 0; i64 max_sweep_time = 0; bool flag_concurrent_mark_triggered = false; + bool in_sweep_stage = false; + i64 current_sweep_index = 0; + void set(context* _ctx, var* _global, usize _size) { running_context = _ctx; main_context_global = _global; @@ -95,7 +98,6 @@ private: void mark_co(std::vector&, nas_co&); void mark_map(std::vector&, nas_map&); void sweep(); - void concurrent_sweep(free_list&, usize, usize); static const auto concurrent_threshold() { return UINT16_MAX * 16; diff --git a/src/natives/builtin.cpp b/src/natives/builtin.cpp index 30c526b..bc9602b 100644 --- a/src/natives/builtin.cpp +++ b/src/natives/builtin.cpp @@ -728,7 +728,7 @@ var builtin_gcinfo(context* ctx, gc* ngc) { f64 total = 0; for(u32 i = 0; i(ngc->gcnt[i]); + total += ngc->gc_count[i]; } diff --git a/test/gc_test.nas b/test/gc_test.nas index 6f72d76..7cc002a 100644 --- a/test/gc_test.nas +++ b/test/gc_test.nas @@ -6,30 +6,24 @@ var test_func = func(test_processes...) { test_process_total.stamp(); var time_stamp = maketimestamp(); - var info = runtime.gc.info(); - var gc_total = info.total; - var duration = 0; - foreach (var t; test_processes) { - var name = t[0]; - var f = t[1]; - print("[", os.time(), "] testing ", name, " : "); - time_stamp.stamp(); + var begin_info = runtime.gc.info(); + var gc_total_begin = begin_info.total; + + foreach (var f; test_processes) { f(); - duration = time_stamp.elapsedMSec(); - info = runtime.gc.info(); - println(duration, " ms,\tgc ", - (info.total-gc_total)*100/duration, "%,\t", - 1000/duration, " loop/sec" - ); - gc_total = info.total; + print("."); } - println("[", os.time(), "] test time: ", - test_process_total.elapsedMSec(), " ms"); - - info = runtime.gc.info(); + var end_info = runtime.gc.info(); + var gc_total_end = end_info.total; + var duration = time_stamp.elapsedMSec(); + println(" ", duration, " ms,\tgc ", + int((gc_total_end-gc_total_begin)*100/duration), "%,\t", + int(1000/(duration/size(test_processes))*10)/10, " test(s)/sec" + ); + + var info = runtime.gc.info(); println("+##-gc-----------------"); - println("| total : ", info.total, " ms"); println("| average : ", info.average, " ms"); println("| max gc : ", info.max_gc, " ms"); println("| max mark : ", info.max_mark, " ms"); @@ -37,7 +31,7 @@ var test_func = func(test_processes...) { println("+----------------------"); } -var MAX_ITER_NUM = 2e5; +var MAX_ITER_NUM = 5e4; var append_vec = func { var res = []; @@ -72,7 +66,7 @@ var append_vec_in_vec = func { var append_hash_in_vec = func { var res = []; for(var i=0; i ", append_vec_in_vec], - ["vec ", append_hash_in_vec], - ["hash ", append_vec_in_hash], - ["hash", append_hash_in_hash] + append_vec, + append_hash, + append_func, + append_vec_in_vec, + append_hash_in_vec, + append_vec_in_hash, + append_hash_in_hash, + + append_vec, + append_hash, + append_func, + append_vec_in_vec, + append_hash_in_vec, + append_vec_in_hash, + append_hash_in_hash, + + append_hash_vec_hash, + append_hash_vec_hash, + append_hash_vec_hash, + + append_tree, + append_tree, + append_tree, + + append_hash_vec_hash, + append_hash_vec_hash, + append_hash_vec_hash, + + append_tree, + append_tree, + append_tree ); } \ No newline at end of file