History

Minor perf improvements in GC ~ 5%

Changed allocation collection to a singly linked list - std::forward_list. Moved mark context from stack allocation to heap. - This permits reuse of the allocated memory between mark phases.

arr committed 9 years ago

Commit 4697a6a1 parent 2519a932 files · +59 −58Browse files

Unified · Split

2 files
  1. src/vm/garbage_collector.cpp +56 −56
  2. src/vm/garbage_collector.h +3 −2
src/vm/garbage_collector.cpp+56−56
@@ -61,19 +61,6 @@ std::unique_ptr<vm_garbage_collector_t> disvm::runtime::create_no_op_gc(vm_t &) · 60 unmodified lines
61 return std::make_unique<no_op_gc>();61 return std::make_unique<no_op_gc>();
62}62}
63 63
64default_garbage_collector_t::default_garbage_collector_t(vm_t &vm)
65 : _collection_epoch{ 0 }
66 , _vm{ vm }
67{
68}
69
70default_garbage_collector_t::~default_garbage_collector_t()
71{
72 std::lock_guard<std::mutex> lock{ _tracking_allocs_lock };
73 for (auto a : _tracking_allocs)
74 dec_ref_count_and_free(a);
75}
76
77namespace64namespace
78{65{
79 enum class gc_colour_t66 enum class gc_colour_t
@@ -105,6 +92,42 @@ namespace · 25 unmodified lines
105 {92 {
106 a->gc_reserved = reinterpret_cast<pointer_t>(c);93 a->gc_reserved = reinterpret_cast<pointer_t>(c);
107 }94 }
95
96 class mark_cxt_t final : public std::stack<vm_alloc_t *, std::vector<vm_alloc_t *>>
97 {
98 public:
99 mark_cxt_t()
100 : string_type{ intrinsic_type_desc::type<vm_string_t>().get() } // Using raw pointer since it is a built-in type and has unlimited lifetime
101 , curr_colour{ gc_colour_t::white }
102 { }
103
104 const type_descriptor_t *string_type;
105 gc_colour_t curr_colour;
106
107 vm_alloc_t *pop()
108 {
109 auto a = top();
110 std::stack<vm_alloc_t *, std::vector<vm_alloc_t *>>::pop();
111 return a;
112 }
113 };
114}
115
116default_garbage_collector_t::default_garbage_collector_t(vm_t &vm)
117 : _collection_epoch{ 0 }
118 , _mark_cxt{ new mark_cxt_t{} }
119 , _vm{ vm }
120{
121}
122
123default_garbage_collector_t::~default_garbage_collector_t()
124{
125 std::lock_guard<std::mutex> lock{ _tracking_allocs_lock };
126 for (auto a : _tracking_allocs)
127 dec_ref_count_and_free(a);
128
129 auto cxt = static_cast<mark_cxt_t *>(_mark_cxt);
130 delete cxt;
108}131}
109 132
110vm_memory_allocator_t default_garbage_collector_t::get_allocator() const133vm_memory_allocator_t default_garbage_collector_t::get_allocator() const
@@ -123,7 +146,7 @@ void default_garbage_collector_t::track_allocation(vm_alloc_t *alloc) · 12 unmodified lines
123 set_gc_colour(alloc, get_current_colour(_collection_epoch));146 set_gc_colour(alloc, get_current_colour(_collection_epoch));
124 147
125 std::lock_guard<std::mutex> lock{ _tracking_allocs_lock };148 std::lock_guard<std::mutex> lock{ _tracking_allocs_lock };
126 _tracking_allocs.push_back(alloc);149 _tracking_allocs.emplace_front(alloc);
127}150}
128 151
129void default_garbage_collector_t::enum_tracked_allocations(vm_alloc_callback_t callback) const152void default_garbage_collector_t::enum_tracked_allocations(vm_alloc_callback_t callback) const
@@ -138,38 +161,20 @@ void default_garbage_collector_t::enum_tracked_allocations(vm_alloc_callback_t c · 8 unmodified lines
138 161
139namespace162namespace
140{163{
141 struct mark_cxt_t final : public std::stack<vm_alloc_t *, std::vector<vm_alloc_t *>>
142 {
143 mark_cxt_t(const type_descriptor_t *string_type, const gc_colour_t curr_colour)
144 : std::stack<vm_alloc_t *, std::vector<vm_alloc_t *>>{}
145 , string_type{ string_type }
146 , curr_colour{ curr_colour }
147 { }
148
149 const type_descriptor_t *string_type;
150 const gc_colour_t curr_colour;
151 };
152
153 void mark_pointers(pointer_t p, void *cxt)164 void mark_pointers(pointer_t p, void *cxt)
154 {165 {
155 auto a = vm_alloc_t::from_allocation(p);166 auto a = vm_alloc_t::from_allocation(p);
156 167
157 assert(cxt != nullptr);168 assert(cxt != nullptr);
158 auto c = reinterpret_cast<mark_cxt_t *>(cxt);169 auto c = static_cast<mark_cxt_t *>(cxt);
159 170
160 // Don't examine vm strings or allocations with the current colour171 // Don't examine vm strings or allocations with the current colour
161 if (c->curr_colour != get_gc_colour(a) && a->alloc_type.get() != c->string_type)172 if (c->curr_colour != get_gc_colour(a) && a->alloc_type.get() != c->string_type)
162 c->push(a);173 c->push(a);
163 }174 }
164 175
165 void mark(const std::vector<std::shared_ptr<const vm_thread_t>> &threads, const gc_colour_t curr_colour)176 void mark(std::vector<std::shared_ptr<const vm_thread_t>> threads, mark_cxt_t &mark_cxt)
166 {177 {
167 mark_cxt_t mark_cxt
168 {
169 intrinsic_type_desc::type<vm_string_t>().get(), // Using raw pointer since it is a built-in type and has unlimited lifetime
170 curr_colour
171 };
172
173 // Get roots from threads178 // Get roots from threads
174 for (auto &t : threads)179 for (auto &t : threads)
175 {180 {
@@ -193,42 +198,32 @@ namespace · 17 unmodified lines
193 }198 }
194 }199 }
195 200
196 const auto log_enabled = disvm::debug::is_component_tracing_enabled<component_trace_t::garbage_collector>();201 if (disvm::debug::is_component_tracing_enabled<component_trace_t::garbage_collector>())
197 if (log_enabled)
198 disvm::debug::log_msg(component_trace_t::garbage_collector, log_level_t::debug, "gc: roots found: %" PRIuPTR, mark_cxt.size());202 disvm::debug::log_msg(component_trace_t::garbage_collector, log_level_t::debug, "gc: roots found: %" PRIuPTR, mark_cxt.size());
199 203
200 // Traverse the graph204 // Traverse the graph
201 while (!mark_cxt.empty())205 while (!mark_cxt.empty())
202 {206 {
203 auto curr = mark_cxt.top();207 auto curr = mark_cxt.pop();
204 mark_cxt.pop();208 set_gc_colour(curr, mark_cxt.curr_colour);
205
206 if (log_enabled)
207 disvm::debug::log_msg(component_trace_t::garbage_collector, log_level_t::debug, "gc: mark: alloc: %#" PRIxPTR, curr);
208 209
209 if (curr->alloc_type->map_in_bytes > 0)210 if (curr->alloc_type->map_in_bytes > 0)
210 enum_pointer_fields(*curr->alloc_type, curr->get_allocation(), mark_pointers, &mark_cxt);211 enum_pointer_fields(*curr->alloc_type, curr->get_allocation(), mark_pointers, &mark_cxt);
211
212 set_gc_colour(curr, curr_colour);
213 }212 }
214 }213 }
215 214
216 void sweep(std::deque<vm_alloc_t *> &tracking_allocs, const gc_colour_t sweeper_colour)215 void sweep(std::forward_list<vm_alloc_t *> &tracking_allocs, const gc_colour_t sweeper_colour)
217 {216 {
218 auto allocs_local = std::move(tracking_allocs);217 // Remove sweeper colour allocations.
219 218 tracking_allocs.remove_if([sweeper_colour](vm_alloc_t *a)
220 const auto starting_size = allocs_local.size();
221 for (auto a : allocs_local)
222 {219 {
223 const auto colour = get_gc_colour(a);220 const auto colour = get_gc_colour(a);
224 if (colour == sweeper_colour)221 const auto remove = (colour == sweeper_colour);
222 if (remove)
225 dec_ref_count_and_free(a);223 dec_ref_count_and_free(a);
226 else
227 tracking_allocs.push_back(a);
228 }
229 224
230 if (disvm::debug::is_component_tracing_enabled<component_trace_t::garbage_collector>())225 return remove;
231 disvm::debug::log_msg(component_trace_t::garbage_collector, log_level_t::debug, "gc: sweep: %u", starting_size - tracking_allocs.size());226 });
232 }227 }
233}228}
234 229
@@ -249,8 +244,13 @@ bool default_garbage_collector_t::collect(std::vector<std::shared_ptr<const vm_t · 14 unmodified lines
249 disvm::debug::log_msg(component_trace_t::duration, log_level_t::debug, "gc: begin: collect");244 disvm::debug::log_msg(component_trace_t::duration, log_level_t::debug, "gc: begin: collect");
250 }245 }
251 246
252 const auto curr_colour = get_current_colour(_collection_epoch);247 auto mark_cxt = static_cast<mark_cxt_t *>(_mark_cxt);
253 mark(threads, curr_colour);248 assert(mark_cxt != nullptr);
249 mark_cxt->curr_colour = get_current_colour(_collection_epoch);
250
251 assert(mark_cxt->empty() && "Marking context should be empty before mark phase");
252 mark(std::move(threads), *mark_cxt);
253 assert(mark_cxt->empty() && "Marking context should be empty after mark phase");
254 254
255 const auto sweeper_colour = get_sweeper_colour(_collection_epoch);255 const auto sweeper_colour = get_sweeper_colour(_collection_epoch);
256 sweep(_tracking_allocs, sweeper_colour);256 sweep(_tracking_allocs, sweeper_colour);
src/vm/garbage_collector.h+3−2
@@ -9,7 +9,7 @@ · 8 unmodified lines
9 9
10#include <cstdint>10#include <cstdint>
11#include <mutex>11#include <mutex>
12#include <deque>12#include <forward_list>
13#include <vector>13#include <vector>
14#include <disvm.h>14#include <disvm.h>
15 15
@@ -37,9 +37,10 @@ namespace disvm · 21 unmodified lines
37 private:37 private:
38 vm_t &_vm;38 vm_t &_vm;
39 39
40 void *_mark_cxt;
40 std::size_t _collection_epoch;41 std::size_t _collection_epoch;
41 mutable std::mutex _tracking_allocs_lock;42 mutable std::mutex _tracking_allocs_lock;
42 std::deque<vm_alloc_t *> _tracking_allocs;43 std::forward_list<vm_alloc_t *> _tracking_allocs;
43 };44 };
44 }45 }
45}46}