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