23 */ |
23 */ |
24 |
24 |
25 #ifndef SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP |
25 #ifndef SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP |
26 #define SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP |
26 #define SHARE_GC_G1_G1DIRTYCARDQUEUE_HPP |
27 |
27 |
28 #include "gc/shared/cardTable.hpp" |
28 #include "gc/g1/g1BufferNodeList.hpp" |
|
29 #include "gc/g1/g1FreeIdSet.hpp" |
29 #include "gc/shared/ptrQueue.hpp" |
30 #include "gc/shared/ptrQueue.hpp" |
30 #include "memory/allocation.hpp" |
31 #include "memory/allocation.hpp" |
31 |
32 |
32 class G1DirtyCardQueueSet; |
33 class G1DirtyCardQueueSet; |
33 class G1FreeIdSet; |
34 class G1RedirtyCardsQueueSet; |
34 class Thread; |
35 class Thread; |
35 class Monitor; |
36 class Monitor; |
36 |
|
37 // A closure class for processing card table entries. Note that we don't |
|
38 // require these closure objects to be stack-allocated. |
|
39 class G1CardTableEntryClosure: public CHeapObj<mtGC> { |
|
40 public: |
|
41 typedef CardTable::CardValue CardValue; |
|
42 |
|
43 // Process the card whose card table entry is "card_ptr". If returns |
|
44 // "false", terminate the iteration early. |
|
45 virtual bool do_card_ptr(CardValue* card_ptr, uint worker_i) = 0; |
|
46 }; |
|
47 |
37 |
48 // A ptrQueue whose elements are "oops", pointers to object heads. |
38 // A ptrQueue whose elements are "oops", pointers to object heads. |
49 class G1DirtyCardQueue: public PtrQueue { |
39 class G1DirtyCardQueue: public PtrQueue { |
50 protected: |
40 protected: |
51 virtual void handle_completed_buffer(); |
41 virtual void handle_completed_buffer(); |
74 using PtrQueue::byte_width_of_buf; |
64 using PtrQueue::byte_width_of_buf; |
75 |
65 |
76 }; |
66 }; |
77 |
67 |
78 class G1DirtyCardQueueSet: public PtrQueueSet { |
68 class G1DirtyCardQueueSet: public PtrQueueSet { |
79 // Apply the closure to the elements of "node" from it's index to |
69 Monitor* _cbl_mon; // Protects the list and count members. |
80 // buffer_size. If all closure applications return true, then |
70 BufferNode* _completed_buffers_head; |
81 // returns true. Stops processing after the first closure |
71 BufferNode* _completed_buffers_tail; |
82 // application that returns false, and returns false from this |
|
83 // function. If "consume" is true, the node's index is updated to |
|
84 // exclude the processed elements, e.g. up to the element for which |
|
85 // the closure returned false. |
|
86 bool apply_closure_to_buffer(G1CardTableEntryClosure* cl, |
|
87 BufferNode* node, |
|
88 bool consume, |
|
89 uint worker_i = 0); |
|
90 |
72 |
91 // If there are more than stop_at completed buffers, pop one, apply |
73 // Number of actual cards in the list of completed buffers. |
92 // the specified closure to its active elements, and return true. |
74 volatile size_t _num_cards; |
93 // Otherwise return false. |
75 |
94 // |
76 size_t _process_cards_threshold; |
95 // A completely processed buffer is freed. However, if a closure |
77 volatile bool _process_completed_buffers; |
96 // invocation returns false, processing is stopped and the partially |
78 |
97 // processed buffer (with its index updated to exclude the processed |
79 void abandon_completed_buffers(); |
98 // elements, e.g. up to the element for which the closure returned |
80 |
99 // false) is returned to the completed buffer set. |
81 // Refine the cards in "node" from its index to buffer_size. |
100 // |
82 // Stops processing if SuspendibleThreadSet::should_yield() is true. |
101 // If during_pause is true, stop_at must be zero, and the closure |
83 // Returns true if the entire buffer was processed, false if there |
102 // must never return false. |
84 // is a pending yield request. The node's index is updated to exclude |
103 bool apply_closure_to_completed_buffer(G1CardTableEntryClosure* cl, |
85 // the processed elements, e.g. up to the element before processing |
104 uint worker_i, |
86 // stopped, or one past the last element if the entire buffer was |
105 size_t stop_at, |
87 // processed. Increments *total_refined_cards by the number of cards |
106 bool during_pause); |
88 // processed and removed from the buffer. |
|
89 bool refine_buffer(BufferNode* node, uint worker_id, size_t* total_refined_cards); |
107 |
90 |
108 bool mut_process_buffer(BufferNode* node); |
91 bool mut_process_buffer(BufferNode* node); |
109 |
92 |
110 // If the queue contains more buffers than configured here, the |
93 // If the queue contains more cards than configured here, the |
111 // mutator must start doing some of the concurrent refinement work, |
94 // mutator must start doing some of the concurrent refinement work. |
112 size_t _max_completed_buffers; |
95 size_t _max_cards; |
113 size_t _completed_buffers_padding; |
96 size_t _max_cards_padding; |
114 static const size_t MaxCompletedBuffersUnlimited = ~size_t(0); |
97 static const size_t MaxCardsUnlimited = SIZE_MAX; |
115 |
98 |
116 G1FreeIdSet* _free_ids; |
99 G1FreeIdSet _free_ids; |
117 |
100 |
118 // The number of completed buffers processed by mutator and rs thread, |
101 // Array of cumulative dirty cards refined by mutator threads. |
119 // respectively. |
102 // Array has an entry per id in _free_ids. |
120 jint _processed_buffers_mut; |
103 size_t* _mutator_refined_cards_counters; |
121 jint _processed_buffers_rs_thread; |
|
122 |
|
123 // Current buffer node used for parallel iteration. |
|
124 BufferNode* volatile _cur_par_buffer_node; |
|
125 |
104 |
126 public: |
105 public: |
127 G1DirtyCardQueueSet(bool notify_when_complete = true); |
106 G1DirtyCardQueueSet(Monitor* cbl_mon, BufferNode::Allocator* allocator); |
128 ~G1DirtyCardQueueSet(); |
107 ~G1DirtyCardQueueSet(); |
129 |
|
130 void initialize(Monitor* cbl_mon, |
|
131 BufferNode::Allocator* allocator, |
|
132 bool init_free_ids = false); |
|
133 |
108 |
134 // The number of parallel ids that can be claimed to allow collector or |
109 // The number of parallel ids that can be claimed to allow collector or |
135 // mutator threads to do card-processing work. |
110 // mutator threads to do card-processing work. |
136 static uint num_par_ids(); |
111 static uint num_par_ids(); |
137 |
112 |
140 // Either process the entire buffer and return true, or enqueue the |
115 // Either process the entire buffer and return true, or enqueue the |
141 // buffer and return false. If the buffer is completely processed, |
116 // buffer and return false. If the buffer is completely processed, |
142 // it can be reused in place. |
117 // it can be reused in place. |
143 bool process_or_enqueue_completed_buffer(BufferNode* node); |
118 bool process_or_enqueue_completed_buffer(BufferNode* node); |
144 |
119 |
145 // Apply G1RefineCardConcurrentlyClosure to completed buffers until there are stop_at |
120 virtual void enqueue_completed_buffer(BufferNode* node); |
146 // completed buffers remaining. |
|
147 bool refine_completed_buffer_concurrently(uint worker_i, size_t stop_at); |
|
148 |
121 |
149 // Apply the given closure to all completed buffers. The given closure's do_card_ptr |
122 // If the number of completed buffers is > stop_at, then remove and |
150 // must never return false. Must only be called during GC. |
123 // return a completed buffer from the list. Otherwise, return NULL. |
151 bool apply_closure_during_gc(G1CardTableEntryClosure* cl, uint worker_i); |
124 BufferNode* get_completed_buffer(size_t stop_at = 0); |
152 |
125 |
153 void reset_for_par_iteration() { _cur_par_buffer_node = completed_buffers_head(); } |
126 // The number of cards in completed buffers. Read without synchronization. |
154 // Applies the current closure to all completed buffers, non-consumptively. |
127 size_t num_cards() const { return _num_cards; } |
155 // Can be used in parallel, all callers using the iteration state initialized |
|
156 // by reset_for_par_iteration. |
|
157 void par_apply_closure_to_all_completed_buffers(G1CardTableEntryClosure* cl); |
|
158 |
128 |
159 // If a full collection is happening, reset partial logs, and ignore |
129 // Verify that _num_cards is equal to the sum of actual cards |
|
130 // in the completed buffers. |
|
131 void verify_num_cards() const NOT_DEBUG_RETURN; |
|
132 |
|
133 bool process_completed_buffers() { return _process_completed_buffers; } |
|
134 void set_process_completed_buffers(bool x) { _process_completed_buffers = x; } |
|
135 |
|
136 // Get/Set the number of cards that triggers log processing. |
|
137 // Log processing should be done when the number of cards exceeds the |
|
138 // threshold. |
|
139 void set_process_cards_threshold(size_t sz) { |
|
140 _process_cards_threshold = sz; |
|
141 } |
|
142 size_t process_cards_threshold() const { |
|
143 return _process_cards_threshold; |
|
144 } |
|
145 static const size_t ProcessCardsThresholdNever = SIZE_MAX; |
|
146 |
|
147 // Notify the consumer if the number of buffers crossed the threshold |
|
148 void notify_if_necessary(); |
|
149 |
|
150 void merge_bufferlists(G1RedirtyCardsQueueSet* src); |
|
151 |
|
152 G1BufferNodeList take_all_completed_buffers(); |
|
153 |
|
154 // If there are more than stop_at cards in the completed buffers, pop |
|
155 // a buffer, refine its contents, and return true. Otherwise return |
|
156 // false. |
|
157 // |
|
158 // Stops processing a buffer if SuspendibleThreadSet::should_yield(), |
|
159 // returning the incompletely processed buffer to the completed buffer |
|
160 // list, for later processing of the remainder. |
|
161 // |
|
162 // Increments *total_refined_cards by the number of cards processed and |
|
163 // removed from the buffer. |
|
164 bool refine_completed_buffer_concurrently(uint worker_id, |
|
165 size_t stop_at, |
|
166 size_t* total_refined_cards); |
|
167 |
|
168 // If a full collection is happening, reset partial logs, and release |
160 // completed ones: the full collection will make them all irrelevant. |
169 // completed ones: the full collection will make them all irrelevant. |
161 void abandon_logs(); |
170 void abandon_logs(); |
162 |
171 |
163 // If any threads have partial logs, add them to the global list of logs. |
172 // If any threads have partial logs, add them to the global list of logs. |
164 void concatenate_logs(); |
173 void concatenate_logs(); |
165 |
174 |
166 void set_max_completed_buffers(size_t m) { |
175 void set_max_cards(size_t m) { |
167 _max_completed_buffers = m; |
176 _max_cards = m; |
168 } |
177 } |
169 size_t max_completed_buffers() const { |
178 size_t max_cards() const { |
170 return _max_completed_buffers; |
179 return _max_cards; |
171 } |
180 } |
172 |
181 |
173 void set_completed_buffers_padding(size_t padding) { |
182 void set_max_cards_padding(size_t padding) { |
174 _completed_buffers_padding = padding; |
183 _max_cards_padding = padding; |
175 } |
184 } |
176 size_t completed_buffers_padding() const { |
185 size_t max_cards_padding() const { |
177 return _completed_buffers_padding; |
186 return _max_cards_padding; |
178 } |
187 } |
179 |
188 |
180 jint processed_buffers_mut() { |
189 // Total dirty cards refined by mutator threads. |
181 return _processed_buffers_mut; |
190 size_t total_mutator_refined_cards() const; |
182 } |
|
183 jint processed_buffers_rs_thread() { |
|
184 return _processed_buffers_rs_thread; |
|
185 } |
|
186 |
|
187 }; |
191 }; |
188 |
192 |
189 inline G1DirtyCardQueueSet* G1DirtyCardQueue::dirty_card_qset() const { |
193 inline G1DirtyCardQueueSet* G1DirtyCardQueue::dirty_card_qset() const { |
190 return static_cast<G1DirtyCardQueueSet*>(qset()); |
194 return static_cast<G1DirtyCardQueueSet*>(qset()); |
191 } |
195 } |