|
1 /* |
|
2 * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 * |
|
23 */ |
|
24 |
|
25 #include "precompiled.hpp" |
|
26 #include "gc/g1/concurrentG1Refine.hpp" |
|
27 #include "gc/g1/concurrentG1RefineThread.hpp" |
|
28 #include "gc/g1/g1CollectedHeap.inline.hpp" |
|
29 #include "gc/g1/g1RemSet.inline.hpp" |
|
30 #include "gc/g1/g1RemSetSummary.hpp" |
|
31 #include "gc/g1/g1YoungRemSetSamplingThread.hpp" |
|
32 #include "gc/g1/heapRegion.hpp" |
|
33 #include "gc/g1/heapRegionRemSet.hpp" |
|
34 #include "memory/allocation.inline.hpp" |
|
35 #include "runtime/thread.inline.hpp" |
|
36 |
|
37 class GetRSThreadVTimeClosure : public ThreadClosure { |
|
38 private: |
|
39 G1RemSetSummary* _summary; |
|
40 uint _counter; |
|
41 |
|
42 public: |
|
43 GetRSThreadVTimeClosure(G1RemSetSummary * summary) : ThreadClosure(), _summary(summary), _counter(0) { |
|
44 assert(_summary != NULL, "just checking"); |
|
45 } |
|
46 |
|
47 virtual void do_thread(Thread* t) { |
|
48 ConcurrentG1RefineThread* crt = (ConcurrentG1RefineThread*) t; |
|
49 _summary->set_rs_thread_vtime(_counter, crt->vtime_accum()); |
|
50 _counter++; |
|
51 } |
|
52 }; |
|
53 |
|
54 void G1RemSetSummary::update() { |
|
55 _num_conc_refined_cards = _rem_set->num_conc_refined_cards(); |
|
56 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); |
|
57 _num_processed_buf_mutator = dcqs.processed_buffers_mut(); |
|
58 _num_processed_buf_rs_threads = dcqs.processed_buffers_rs_thread(); |
|
59 |
|
60 _num_coarsenings = HeapRegionRemSet::n_coarsenings(); |
|
61 |
|
62 ConcurrentG1Refine * cg1r = G1CollectedHeap::heap()->concurrent_g1_refine(); |
|
63 if (_rs_threads_vtimes != NULL) { |
|
64 GetRSThreadVTimeClosure p(this); |
|
65 cg1r->worker_threads_do(&p); |
|
66 } |
|
67 set_sampling_thread_vtime(cg1r->sampling_thread()->vtime_accum()); |
|
68 } |
|
69 |
|
70 void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) { |
|
71 assert(_rs_threads_vtimes != NULL, "just checking"); |
|
72 assert(thread < _num_vtimes, "just checking"); |
|
73 _rs_threads_vtimes[thread] = value; |
|
74 } |
|
75 |
|
76 double G1RemSetSummary::rs_thread_vtime(uint thread) const { |
|
77 assert(_rs_threads_vtimes != NULL, "just checking"); |
|
78 assert(thread < _num_vtimes, "just checking"); |
|
79 return _rs_threads_vtimes[thread]; |
|
80 } |
|
81 |
|
82 G1RemSetSummary::G1RemSetSummary() : |
|
83 _rem_set(NULL), |
|
84 _num_conc_refined_cards(0), |
|
85 _num_processed_buf_mutator(0), |
|
86 _num_processed_buf_rs_threads(0), |
|
87 _num_coarsenings(0), |
|
88 _num_vtimes(ConcurrentG1Refine::thread_num()), |
|
89 _rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)), |
|
90 _sampling_thread_vtime(0.0f) { |
|
91 |
|
92 memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes); |
|
93 } |
|
94 |
|
95 G1RemSetSummary::G1RemSetSummary(G1RemSet* rem_set) : |
|
96 _rem_set(rem_set), |
|
97 _num_conc_refined_cards(0), |
|
98 _num_processed_buf_mutator(0), |
|
99 _num_processed_buf_rs_threads(0), |
|
100 _num_coarsenings(0), |
|
101 _num_vtimes(ConcurrentG1Refine::thread_num()), |
|
102 _rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)), |
|
103 _sampling_thread_vtime(0.0f) { |
|
104 update(); |
|
105 } |
|
106 |
|
107 G1RemSetSummary::~G1RemSetSummary() { |
|
108 if (_rs_threads_vtimes) { |
|
109 FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes); |
|
110 } |
|
111 } |
|
112 |
|
113 void G1RemSetSummary::set(G1RemSetSummary* other) { |
|
114 assert(other != NULL, "just checking"); |
|
115 assert(_num_vtimes == other->_num_vtimes, "just checking"); |
|
116 |
|
117 _num_conc_refined_cards = other->num_conc_refined_cards(); |
|
118 |
|
119 _num_processed_buf_mutator = other->num_processed_buf_mutator(); |
|
120 _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads(); |
|
121 |
|
122 _num_coarsenings = other->_num_coarsenings; |
|
123 |
|
124 memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes); |
|
125 |
|
126 set_sampling_thread_vtime(other->sampling_thread_vtime()); |
|
127 } |
|
128 |
|
129 void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { |
|
130 assert(other != NULL, "just checking"); |
|
131 assert(_num_vtimes == other->_num_vtimes, "just checking"); |
|
132 |
|
133 _num_conc_refined_cards = other->num_conc_refined_cards() - _num_conc_refined_cards; |
|
134 |
|
135 _num_processed_buf_mutator = other->num_processed_buf_mutator() - _num_processed_buf_mutator; |
|
136 _num_processed_buf_rs_threads = other->num_processed_buf_rs_threads() - _num_processed_buf_rs_threads; |
|
137 |
|
138 _num_coarsenings = other->num_coarsenings() - _num_coarsenings; |
|
139 |
|
140 for (uint i = 0; i < _num_vtimes; i++) { |
|
141 set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i)); |
|
142 } |
|
143 |
|
144 _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; |
|
145 } |
|
146 |
|
147 class RegionTypeCounter VALUE_OBJ_CLASS_SPEC { |
|
148 private: |
|
149 const char* _name; |
|
150 |
|
151 size_t _rs_mem_size; |
|
152 size_t _cards_occupied; |
|
153 size_t _amount; |
|
154 |
|
155 size_t _code_root_mem_size; |
|
156 size_t _code_root_elems; |
|
157 |
|
158 double rs_mem_size_percent_of(size_t total) { |
|
159 return percent_of(_rs_mem_size, total); |
|
160 } |
|
161 |
|
162 double cards_occupied_percent_of(size_t total) { |
|
163 return percent_of(_cards_occupied, total); |
|
164 } |
|
165 |
|
166 double code_root_mem_size_percent_of(size_t total) { |
|
167 return percent_of(_code_root_mem_size, total); |
|
168 } |
|
169 |
|
170 double code_root_elems_percent_of(size_t total) { |
|
171 return percent_of(_code_root_elems, total); |
|
172 } |
|
173 |
|
174 size_t amount() const { return _amount; } |
|
175 |
|
176 public: |
|
177 |
|
178 RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0), |
|
179 _amount(0), _code_root_mem_size(0), _code_root_elems(0) { } |
|
180 |
|
181 void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size, |
|
182 size_t code_root_elems) { |
|
183 _rs_mem_size += rs_mem_size; |
|
184 _cards_occupied += cards_occupied; |
|
185 _code_root_mem_size += code_root_mem_size; |
|
186 _code_root_elems += code_root_elems; |
|
187 _amount++; |
|
188 } |
|
189 |
|
190 size_t rs_mem_size() const { return _rs_mem_size; } |
|
191 size_t cards_occupied() const { return _cards_occupied; } |
|
192 |
|
193 size_t code_root_mem_size() const { return _code_root_mem_size; } |
|
194 size_t code_root_elems() const { return _code_root_elems; } |
|
195 |
|
196 void print_rs_mem_info_on(outputStream * out, size_t total) { |
|
197 out->print_cr(" " SIZE_FORMAT_W(8) "%s (%5.1f%%) by " SIZE_FORMAT " %s regions", |
|
198 byte_size_in_proper_unit(rs_mem_size()), |
|
199 proper_unit_for_byte_size(rs_mem_size()), |
|
200 rs_mem_size_percent_of(total), amount(), _name); |
|
201 } |
|
202 |
|
203 void print_cards_occupied_info_on(outputStream * out, size_t total) { |
|
204 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) entries by " SIZE_FORMAT " %s regions", |
|
205 cards_occupied(), cards_occupied_percent_of(total), amount(), _name); |
|
206 } |
|
207 |
|
208 void print_code_root_mem_info_on(outputStream * out, size_t total) { |
|
209 out->print_cr(" " SIZE_FORMAT_W(8) "%s (%5.1f%%) by " SIZE_FORMAT " %s regions", |
|
210 byte_size_in_proper_unit(code_root_mem_size()), |
|
211 proper_unit_for_byte_size(code_root_mem_size()), |
|
212 code_root_mem_size_percent_of(total), amount(), _name); |
|
213 } |
|
214 |
|
215 void print_code_root_elems_info_on(outputStream * out, size_t total) { |
|
216 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) elements by " SIZE_FORMAT " %s regions", |
|
217 code_root_elems(), code_root_elems_percent_of(total), amount(), _name); |
|
218 } |
|
219 }; |
|
220 |
|
221 |
|
222 class HRRSStatsIter: public HeapRegionClosure { |
|
223 private: |
|
224 RegionTypeCounter _young; |
|
225 RegionTypeCounter _humongous; |
|
226 RegionTypeCounter _free; |
|
227 RegionTypeCounter _old; |
|
228 RegionTypeCounter _all; |
|
229 |
|
230 size_t _max_rs_mem_sz; |
|
231 HeapRegion* _max_rs_mem_sz_region; |
|
232 |
|
233 size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } |
|
234 size_t total_cards_occupied() const { return _all.cards_occupied(); } |
|
235 |
|
236 size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } |
|
237 HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } |
|
238 |
|
239 size_t _max_code_root_mem_sz; |
|
240 HeapRegion* _max_code_root_mem_sz_region; |
|
241 |
|
242 size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } |
|
243 size_t total_code_root_elems() const { return _all.code_root_elems(); } |
|
244 |
|
245 size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; } |
|
246 HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } |
|
247 |
|
248 public: |
|
249 HRRSStatsIter() : _all("All"), _young("Young"), _humongous("Humongous"), |
|
250 _free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL), |
|
251 _max_rs_mem_sz(0), _max_code_root_mem_sz(0) |
|
252 {} |
|
253 |
|
254 bool doHeapRegion(HeapRegion* r) { |
|
255 HeapRegionRemSet* hrrs = r->rem_set(); |
|
256 |
|
257 // HeapRegionRemSet::mem_size() includes the |
|
258 // size of the strong code roots |
|
259 size_t rs_mem_sz = hrrs->mem_size(); |
|
260 if (rs_mem_sz > _max_rs_mem_sz) { |
|
261 _max_rs_mem_sz = rs_mem_sz; |
|
262 _max_rs_mem_sz_region = r; |
|
263 } |
|
264 size_t occupied_cards = hrrs->occupied(); |
|
265 size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); |
|
266 if (code_root_mem_sz > max_code_root_mem_sz()) { |
|
267 _max_code_root_mem_sz = code_root_mem_sz; |
|
268 _max_code_root_mem_sz_region = r; |
|
269 } |
|
270 size_t code_root_elems = hrrs->strong_code_roots_list_length(); |
|
271 |
|
272 RegionTypeCounter* current = NULL; |
|
273 if (r->is_free()) { |
|
274 current = &_free; |
|
275 } else if (r->is_young()) { |
|
276 current = &_young; |
|
277 } else if (r->is_humongous()) { |
|
278 current = &_humongous; |
|
279 } else if (r->is_old()) { |
|
280 current = &_old; |
|
281 } else { |
|
282 ShouldNotReachHere(); |
|
283 } |
|
284 current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); |
|
285 _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); |
|
286 |
|
287 return false; |
|
288 } |
|
289 |
|
290 void print_summary_on(outputStream* out) { |
|
291 RegionTypeCounter* counters[] = { &_young, &_humongous, &_free, &_old, NULL }; |
|
292 |
|
293 out->print_cr(" Current rem set statistics"); |
|
294 out->print_cr(" Total per region rem sets sizes = " SIZE_FORMAT "%s." |
|
295 " Max = " SIZE_FORMAT "%s.", |
|
296 byte_size_in_proper_unit(total_rs_mem_sz()), |
|
297 proper_unit_for_byte_size(total_rs_mem_sz()), |
|
298 byte_size_in_proper_unit(max_rs_mem_sz()), |
|
299 proper_unit_for_byte_size(max_rs_mem_sz())); |
|
300 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { |
|
301 (*current)->print_rs_mem_info_on(out, total_rs_mem_sz()); |
|
302 } |
|
303 |
|
304 out->print_cr(" Static structures = " SIZE_FORMAT "%s," |
|
305 " free_lists = " SIZE_FORMAT "%s.", |
|
306 byte_size_in_proper_unit(HeapRegionRemSet::static_mem_size()), |
|
307 proper_unit_for_byte_size(HeapRegionRemSet::static_mem_size()), |
|
308 byte_size_in_proper_unit(HeapRegionRemSet::fl_mem_size()), |
|
309 proper_unit_for_byte_size(HeapRegionRemSet::fl_mem_size())); |
|
310 |
|
311 out->print_cr(" " SIZE_FORMAT " occupied cards represented.", |
|
312 total_cards_occupied()); |
|
313 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { |
|
314 (*current)->print_cards_occupied_info_on(out, total_cards_occupied()); |
|
315 } |
|
316 |
|
317 // Largest sized rem set region statistics |
|
318 HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); |
|
319 out->print_cr(" Region with largest rem set = " HR_FORMAT ", " |
|
320 "size = " SIZE_FORMAT "%s, occupied = " SIZE_FORMAT "%s.", |
|
321 HR_FORMAT_PARAMS(max_rs_mem_sz_region()), |
|
322 byte_size_in_proper_unit(rem_set->mem_size()), |
|
323 proper_unit_for_byte_size(rem_set->mem_size()), |
|
324 byte_size_in_proper_unit(rem_set->occupied()), |
|
325 proper_unit_for_byte_size(rem_set->occupied())); |
|
326 // Strong code root statistics |
|
327 HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); |
|
328 out->print_cr(" Total heap region code root sets sizes = " SIZE_FORMAT "%s." |
|
329 " Max = " SIZE_FORMAT "%s.", |
|
330 byte_size_in_proper_unit(total_code_root_mem_sz()), |
|
331 proper_unit_for_byte_size(total_code_root_mem_sz()), |
|
332 byte_size_in_proper_unit(max_code_root_rem_set->strong_code_roots_mem_size()), |
|
333 proper_unit_for_byte_size(max_code_root_rem_set->strong_code_roots_mem_size())); |
|
334 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { |
|
335 (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz()); |
|
336 } |
|
337 |
|
338 out->print_cr(" " SIZE_FORMAT " code roots represented.", |
|
339 total_code_root_elems()); |
|
340 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { |
|
341 (*current)->print_code_root_elems_info_on(out, total_code_root_elems()); |
|
342 } |
|
343 |
|
344 out->print_cr(" Region with largest amount of code roots = " HR_FORMAT ", " |
|
345 "size = " SIZE_FORMAT "%s, num_elems = " SIZE_FORMAT ".", |
|
346 HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), |
|
347 byte_size_in_proper_unit(max_code_root_rem_set->strong_code_roots_mem_size()), |
|
348 proper_unit_for_byte_size(max_code_root_rem_set->strong_code_roots_mem_size()), |
|
349 max_code_root_rem_set->strong_code_roots_list_length()); |
|
350 } |
|
351 }; |
|
352 |
|
353 void G1RemSetSummary::print_on(outputStream* out) { |
|
354 out->print_cr(" Recent concurrent refinement statistics"); |
|
355 out->print_cr(" Processed " SIZE_FORMAT " cards concurrently", num_conc_refined_cards()); |
|
356 out->print_cr(" Of " SIZE_FORMAT " completed buffers:", num_processed_buf_total()); |
|
357 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) by concurrent RS threads.", |
|
358 num_processed_buf_total(), |
|
359 percent_of(num_processed_buf_rs_threads(), num_processed_buf_total())); |
|
360 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) by mutator threads.", |
|
361 num_processed_buf_mutator(), |
|
362 percent_of(num_processed_buf_mutator(), num_processed_buf_total())); |
|
363 out->print_cr(" Did " SIZE_FORMAT " coarsenings.", num_coarsenings()); |
|
364 out->print_cr(" Concurrent RS threads times (s)"); |
|
365 out->print(" "); |
|
366 for (uint i = 0; i < _num_vtimes; i++) { |
|
367 out->print(" %5.2f", rs_thread_vtime(i)); |
|
368 } |
|
369 out->cr(); |
|
370 out->print_cr(" Concurrent sampling threads times (s)"); |
|
371 out->print_cr(" %5.2f", sampling_thread_vtime()); |
|
372 |
|
373 HRRSStatsIter blk; |
|
374 G1CollectedHeap::heap()->heap_region_iterate(&blk); |
|
375 blk.print_summary_on(out); |
|
376 } |