1 /* 2 * Copyright (c) 2013, 2019, 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/g1BarrierSet.hpp" 27 #include "gc/g1/g1CollectedHeap.inline.hpp" 28 #include "gc/g1/g1ConcurrentRefine.hpp" 29 #include "gc/g1/g1ConcurrentRefineThread.hpp" 30 #include "gc/g1/g1DirtyCardQueue.hpp" 31 #include "gc/g1/g1RemSet.hpp" 32 #include "gc/g1/g1RemSetSummary.hpp" 33 #include "gc/g1/g1YoungRemSetSamplingThread.hpp" 34 #include "gc/g1/heapRegion.hpp" 35 #include "gc/g1/heapRegionRemSet.hpp" 36 #include "memory/allocation.inline.hpp" 37 #include "memory/iterator.hpp" 38 #include "runtime/thread.inline.hpp" 39 40 void G1RemSetSummary::update() { 41 class CollectData : public ThreadClosure { 42 G1RemSetSummary* _summary; 43 uint _counter; 44 public: 45 CollectData(G1RemSetSummary * summary) : _summary(summary), _counter(0) {} 46 virtual void do_thread(Thread* t) { 47 G1ConcurrentRefineThread* crt = static_cast<G1ConcurrentRefineThread*>(t); 48 _summary->set_rs_thread_vtime(_counter, crt->vtime_accum()); 49 _counter++; 50 _summary->_total_concurrent_refined_cards += crt->total_refined_cards(); 51 } 52 } collector(this); 53 G1CollectedHeap* g1h = G1CollectedHeap::heap(); 54 g1h->concurrent_refine()->threads_do(&collector); 55 _total_mutator_refined_cards = G1BarrierSet::dirty_card_queue_set().total_mutator_refined_cards(); 56 _num_coarsenings = HeapRegionRemSet::n_coarsenings(); 57 58 set_sampling_thread_vtime(g1h->sampling_thread()->vtime_accum()); 59 } 60 61 void G1RemSetSummary::set_rs_thread_vtime(uint thread, double value) { 62 assert(_rs_threads_vtimes != NULL, "just checking"); 63 assert(thread < _num_vtimes, "just checking"); 64 _rs_threads_vtimes[thread] = value; 65 } 66 67 double G1RemSetSummary::rs_thread_vtime(uint thread) const { 68 assert(_rs_threads_vtimes != NULL, "just checking"); 69 assert(thread < _num_vtimes, "just checking"); 70 return _rs_threads_vtimes[thread]; 71 } 72 73 G1RemSetSummary::G1RemSetSummary(bool should_update) : 74 _total_mutator_refined_cards(0), 75 _total_concurrent_refined_cards(0), 76 _num_coarsenings(0), 77 _num_vtimes(G1ConcurrentRefine::max_num_threads()), 78 _rs_threads_vtimes(NEW_C_HEAP_ARRAY(double, _num_vtimes, mtGC)), 79 _sampling_thread_vtime(0.0f) { 80 81 memset(_rs_threads_vtimes, 0, sizeof(double) * _num_vtimes); 82 83 if (should_update) { 84 update(); 85 } 86 } 87 88 G1RemSetSummary::~G1RemSetSummary() { 89 FREE_C_HEAP_ARRAY(double, _rs_threads_vtimes); 90 } 91 92 void G1RemSetSummary::set(G1RemSetSummary* other) { 93 assert(other != NULL, "just checking"); 94 assert(_num_vtimes == other->_num_vtimes, "just checking"); 95 96 _total_mutator_refined_cards = other->total_mutator_refined_cards(); 97 _total_concurrent_refined_cards = other->total_concurrent_refined_cards(); 98 99 _num_coarsenings = other->num_coarsenings(); 100 101 memcpy(_rs_threads_vtimes, other->_rs_threads_vtimes, sizeof(double) * _num_vtimes); 102 103 set_sampling_thread_vtime(other->sampling_thread_vtime()); 104 } 105 106 void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { 107 assert(other != NULL, "just checking"); 108 assert(_num_vtimes == other->_num_vtimes, "just checking"); 109 110 _total_mutator_refined_cards = other->total_mutator_refined_cards() - _total_mutator_refined_cards; 111 _total_concurrent_refined_cards = other->total_concurrent_refined_cards() - _total_concurrent_refined_cards; 112 113 _num_coarsenings = other->num_coarsenings() - _num_coarsenings; 114 115 for (uint i = 0; i < _num_vtimes; i++) { 116 set_rs_thread_vtime(i, other->rs_thread_vtime(i) - rs_thread_vtime(i)); 117 } 118 119 _sampling_thread_vtime = other->sampling_thread_vtime() - _sampling_thread_vtime; 120 } 121 122 class RegionTypeCounter { 123 private: 124 const char* _name; 125 126 size_t _rs_mem_size; 127 size_t _cards_occupied; 128 size_t _amount; 129 130 size_t _code_root_mem_size; 131 size_t _code_root_elems; 132 133 double rs_mem_size_percent_of(size_t total) { 134 return percent_of(_rs_mem_size, total); 135 } 136 137 double cards_occupied_percent_of(size_t total) { 138 return percent_of(_cards_occupied, total); 139 } 140 141 double code_root_mem_size_percent_of(size_t total) { 142 return percent_of(_code_root_mem_size, total); 143 } 144 145 double code_root_elems_percent_of(size_t total) { 146 return percent_of(_code_root_elems, total); 147 } 148 149 size_t amount() const { return _amount; } 150 151 public: 152 153 RegionTypeCounter(const char* name) : _name(name), _rs_mem_size(0), _cards_occupied(0), 154 _amount(0), _code_root_mem_size(0), _code_root_elems(0) { } 155 156 void add(size_t rs_mem_size, size_t cards_occupied, size_t code_root_mem_size, 157 size_t code_root_elems) { 158 _rs_mem_size += rs_mem_size; 159 _cards_occupied += cards_occupied; 160 _code_root_mem_size += code_root_mem_size; 161 _code_root_elems += code_root_elems; 162 _amount++; 163 } 164 165 size_t rs_mem_size() const { return _rs_mem_size; } 166 size_t cards_occupied() const { return _cards_occupied; } 167 168 size_t code_root_mem_size() const { return _code_root_mem_size; } 169 size_t code_root_elems() const { return _code_root_elems; } 170 171 void print_rs_mem_info_on(outputStream * out, size_t total) { 172 out->print_cr(" " SIZE_FORMAT_W(8) "%s (%5.1f%%) by " SIZE_FORMAT " %s regions", 173 byte_size_in_proper_unit(rs_mem_size()), 174 proper_unit_for_byte_size(rs_mem_size()), 175 rs_mem_size_percent_of(total), amount(), _name); 176 } 177 178 void print_cards_occupied_info_on(outputStream * out, size_t total) { 179 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) entries by " SIZE_FORMAT " %s regions", 180 cards_occupied(), cards_occupied_percent_of(total), amount(), _name); 181 } 182 183 void print_code_root_mem_info_on(outputStream * out, size_t total) { 184 out->print_cr(" " SIZE_FORMAT_W(8) "%s (%5.1f%%) by " SIZE_FORMAT " %s regions", 185 byte_size_in_proper_unit(code_root_mem_size()), 186 proper_unit_for_byte_size(code_root_mem_size()), 187 code_root_mem_size_percent_of(total), amount(), _name); 188 } 189 190 void print_code_root_elems_info_on(outputStream * out, size_t total) { 191 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) elements by " SIZE_FORMAT " %s regions", 192 code_root_elems(), code_root_elems_percent_of(total), amount(), _name); 193 } 194 }; 195 196 197 class HRRSStatsIter: public HeapRegionClosure { 198 private: 199 RegionTypeCounter _young; 200 RegionTypeCounter _humongous; 201 RegionTypeCounter _free; 202 RegionTypeCounter _old; 203 RegionTypeCounter _archive; 204 RegionTypeCounter _all; 205 206 size_t _max_rs_mem_sz; 207 HeapRegion* _max_rs_mem_sz_region; 208 209 size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } 210 size_t total_cards_occupied() const { return _all.cards_occupied(); } 211 212 size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } 213 HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } 214 215 size_t _max_code_root_mem_sz; 216 HeapRegion* _max_code_root_mem_sz_region; 217 218 size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } 219 size_t total_code_root_elems() const { return _all.code_root_elems(); } 220 221 size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; } 222 HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } 223 224 public: 225 HRRSStatsIter() : _young("Young"), _humongous("Humongous"), 226 _free("Free"), _old("Old"), _archive("Archive"), _all("All"), 227 _max_rs_mem_sz(0), _max_rs_mem_sz_region(NULL), 228 _max_code_root_mem_sz(0), _max_code_root_mem_sz_region(NULL) 229 {} 230 231 bool do_heap_region(HeapRegion* r) { 232 HeapRegionRemSet* hrrs = r->rem_set(); 233 234 // HeapRegionRemSet::mem_size() includes the 235 // size of the strong code roots 236 size_t rs_mem_sz = hrrs->mem_size(); 237 if (rs_mem_sz > _max_rs_mem_sz) { 238 _max_rs_mem_sz = rs_mem_sz; 239 _max_rs_mem_sz_region = r; 240 } 241 size_t occupied_cards = hrrs->occupied(); 242 size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); 243 if (code_root_mem_sz > max_code_root_mem_sz()) { 244 _max_code_root_mem_sz = code_root_mem_sz; 245 _max_code_root_mem_sz_region = r; 246 } 247 size_t code_root_elems = hrrs->strong_code_roots_list_length(); 248 249 RegionTypeCounter* current = NULL; 250 if (r->is_free()) { 251 current = &_free; 252 } else if (r->is_young()) { 253 current = &_young; 254 } else if (r->is_humongous()) { 255 current = &_humongous; 256 } else if (r->is_old()) { 257 current = &_old; 258 } else if (r->is_archive()) { 259 current = &_archive; 260 } else { 261 ShouldNotReachHere(); 262 } 263 current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); 264 _all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems); 265 266 return false; 267 } 268 269 void print_summary_on(outputStream* out) { 270 RegionTypeCounter* counters[] = { &_young, &_humongous, &_free, &_old, &_archive, NULL }; 271 272 out->print_cr(" Current rem set statistics"); 273 out->print_cr(" Total per region rem sets sizes = " SIZE_FORMAT "%s." 274 " Max = " SIZE_FORMAT "%s.", 275 byte_size_in_proper_unit(total_rs_mem_sz()), 276 proper_unit_for_byte_size(total_rs_mem_sz()), 277 byte_size_in_proper_unit(max_rs_mem_sz()), 278 proper_unit_for_byte_size(max_rs_mem_sz())); 279 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { 280 (*current)->print_rs_mem_info_on(out, total_rs_mem_sz()); 281 } 282 283 out->print_cr(" Static structures = " SIZE_FORMAT "%s," 284 " free_lists = " SIZE_FORMAT "%s.", 285 byte_size_in_proper_unit(HeapRegionRemSet::static_mem_size()), 286 proper_unit_for_byte_size(HeapRegionRemSet::static_mem_size()), 287 byte_size_in_proper_unit(HeapRegionRemSet::fl_mem_size()), 288 proper_unit_for_byte_size(HeapRegionRemSet::fl_mem_size())); 289 290 out->print_cr(" " SIZE_FORMAT " occupied cards represented.", 291 total_cards_occupied()); 292 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { 293 (*current)->print_cards_occupied_info_on(out, total_cards_occupied()); 294 } 295 296 // Largest sized rem set region statistics 297 HeapRegionRemSet* rem_set = max_rs_mem_sz_region()->rem_set(); 298 out->print_cr(" Region with largest rem set = " HR_FORMAT ", " 299 "size = " SIZE_FORMAT "%s, occupied = " SIZE_FORMAT "%s.", 300 HR_FORMAT_PARAMS(max_rs_mem_sz_region()), 301 byte_size_in_proper_unit(rem_set->mem_size()), 302 proper_unit_for_byte_size(rem_set->mem_size()), 303 byte_size_in_proper_unit(rem_set->occupied()), 304 proper_unit_for_byte_size(rem_set->occupied())); 305 // Strong code root statistics 306 HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region()->rem_set(); 307 out->print_cr(" Total heap region code root sets sizes = " SIZE_FORMAT "%s." 308 " Max = " SIZE_FORMAT "%s.", 309 byte_size_in_proper_unit(total_code_root_mem_sz()), 310 proper_unit_for_byte_size(total_code_root_mem_sz()), 311 byte_size_in_proper_unit(max_code_root_rem_set->strong_code_roots_mem_size()), 312 proper_unit_for_byte_size(max_code_root_rem_set->strong_code_roots_mem_size())); 313 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { 314 (*current)->print_code_root_mem_info_on(out, total_code_root_mem_sz()); 315 } 316 317 out->print_cr(" " SIZE_FORMAT " code roots represented.", 318 total_code_root_elems()); 319 for (RegionTypeCounter** current = &counters[0]; *current != NULL; current++) { 320 (*current)->print_code_root_elems_info_on(out, total_code_root_elems()); 321 } 322 323 out->print_cr(" Region with largest amount of code roots = " HR_FORMAT ", " 324 "size = " SIZE_FORMAT "%s, num_elems = " SIZE_FORMAT ".", 325 HR_FORMAT_PARAMS(max_code_root_mem_sz_region()), 326 byte_size_in_proper_unit(max_code_root_rem_set->strong_code_roots_mem_size()), 327 proper_unit_for_byte_size(max_code_root_rem_set->strong_code_roots_mem_size()), 328 max_code_root_rem_set->strong_code_roots_list_length()); 329 } 330 }; 331 332 void G1RemSetSummary::print_on(outputStream* out) { 333 out->print_cr(" Recent concurrent refinement statistics"); 334 out->print_cr(" Of " SIZE_FORMAT " refined cards:", total_refined_cards()); 335 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) by concurrent refinement threads.", 336 total_concurrent_refined_cards(), 337 percent_of(total_concurrent_refined_cards(), total_refined_cards())); 338 out->print_cr(" " SIZE_FORMAT_W(8) " (%5.1f%%) by mutator threads.", 339 total_mutator_refined_cards(), 340 percent_of(total_mutator_refined_cards(), total_refined_cards())); 341 out->print_cr(" Did " SIZE_FORMAT " coarsenings.", num_coarsenings()); 342 out->print_cr(" Concurrent refinement threads times (s)"); 343 out->print(" "); 344 for (uint i = 0; i < _num_vtimes; i++) { 345 out->print(" %5.2f", rs_thread_vtime(i)); 346 } 347 out->cr(); 348 out->print_cr(" Concurrent sampling threads times (s)"); 349 out->print_cr(" %5.2f", sampling_thread_vtime()); 350 351 HRRSStatsIter blk; 352 G1CollectedHeap::heap()->heap_region_iterate(&blk); 353 blk.print_summary_on(out); 354 }