1 /* 2 * Copyright (c) 2015, 2020, 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 #include "precompiled.hpp" 25 #include "gc/z/zCollectedHeap.hpp" 26 #include "gc/z/zCPU.inline.hpp" 27 #include "gc/z/zGlobals.hpp" 28 #include "gc/z/zHeap.inline.hpp" 29 #include "gc/z/zLargePages.inline.hpp" 30 #include "gc/z/zNMethodTable.hpp" 31 #include "gc/z/zNUMA.hpp" 32 #include "gc/z/zRelocationSetSelector.inline.hpp" 33 #include "gc/z/zStat.hpp" 34 #include "gc/z/zTracer.inline.hpp" 35 #include "gc/z/zUtils.hpp" 36 #include "memory/resourceArea.hpp" 37 #include "runtime/atomic.hpp" 38 #include "runtime/os.hpp" 39 #include "runtime/timer.hpp" 40 #include "utilities/align.hpp" 41 #include "utilities/compilerWarnings.hpp" 42 #include "utilities/debug.hpp" 43 #include "utilities/ticks.hpp" 44 45 #define ZSIZE_FMT SIZE_FORMAT "M(%.0f%%)" 46 #define ZSIZE_ARGS_WITH_MAX(size, max) ((size) / M), (percent_of(size, max)) 47 #define ZSIZE_ARGS(size) ZSIZE_ARGS_WITH_MAX(size, ZStatHeap::max_capacity()) 48 49 #define ZTABLE_ARGS_NA "%9s", "-" 50 #define ZTABLE_ARGS(size) SIZE_FORMAT_W(8) "M (%.0f%%)", \ 51 ((size) / M), (percent_of(size, ZStatHeap::max_capacity())) 52 53 // 54 // Stat sampler/counter data 55 // 56 struct ZStatSamplerData { 57 uint64_t _nsamples; 58 uint64_t _sum; 59 uint64_t _max; 60 61 ZStatSamplerData() : 62 _nsamples(0), 63 _sum(0), 64 _max(0) {} 65 66 void add(const ZStatSamplerData& new_sample) { 67 _nsamples += new_sample._nsamples; 68 _sum += new_sample._sum; 69 _max = MAX2(_max, new_sample._max); 70 } 71 }; 72 73 struct ZStatCounterData { 74 uint64_t _counter; 75 76 ZStatCounterData() : 77 _counter(0) {} 78 }; 79 80 // 81 // Stat sampler history 82 // 83 template <size_t size> 84 class ZStatSamplerHistoryInterval { 85 private: 86 size_t _next; 87 ZStatSamplerData _samples[size]; 88 ZStatSamplerData _accumulated; 89 ZStatSamplerData _total; 90 91 public: 92 ZStatSamplerHistoryInterval() : 93 _next(0), 94 _samples(), 95 _accumulated(), 96 _total() {} 97 98 bool add(const ZStatSamplerData& new_sample) { 99 // Insert sample 100 const ZStatSamplerData old_sample = _samples[_next]; 101 _samples[_next] = new_sample; 102 103 // Adjust accumulated 104 _accumulated._nsamples += new_sample._nsamples; 105 _accumulated._sum += new_sample._sum; 106 _accumulated._max = MAX2(_accumulated._max, new_sample._max); 107 108 // Adjust total 109 _total._nsamples -= old_sample._nsamples; 110 _total._sum -= old_sample._sum; 111 _total._nsamples += new_sample._nsamples; 112 _total._sum += new_sample._sum; 113 if (_total._max < new_sample._max) { 114 // Found new max 115 _total._max = new_sample._max; 116 } else if (_total._max == old_sample._max) { 117 // Removed old max, reset and find new max 118 _total._max = 0; 119 for (size_t i = 0; i < size; i++) { 120 if (_total._max < _samples[i]._max) { 121 _total._max = _samples[i]._max; 122 } 123 } 124 } 125 126 // Adjust next 127 if (++_next == size) { 128 _next = 0; 129 130 // Clear accumulated 131 const ZStatSamplerData zero; 132 _accumulated = zero; 133 134 // Became full 135 return true; 136 } 137 138 // Not yet full 139 return false; 140 } 141 142 const ZStatSamplerData& total() const { 143 return _total; 144 } 145 146 const ZStatSamplerData& accumulated() const { 147 return _accumulated; 148 } 149 }; 150 151 class ZStatSamplerHistory : public CHeapObj<mtGC> { 152 private: 153 ZStatSamplerHistoryInterval<10> _10seconds; 154 ZStatSamplerHistoryInterval<60> _10minutes; 155 ZStatSamplerHistoryInterval<60> _10hours; 156 ZStatSamplerData _total; 157 158 uint64_t avg(uint64_t sum, uint64_t nsamples) const { 159 return (nsamples > 0) ? sum / nsamples : 0; 160 } 161 162 public: 163 ZStatSamplerHistory() : 164 _10seconds(), 165 _10minutes(), 166 _10hours(), 167 _total() {} 168 169 void add(const ZStatSamplerData& new_sample) { 170 if (_10seconds.add(new_sample)) { 171 if (_10minutes.add(_10seconds.total())) { 172 if (_10hours.add(_10minutes.total())) { 173 _total.add(_10hours.total()); 174 } 175 } 176 } 177 } 178 179 uint64_t avg_10_seconds() const { 180 const uint64_t sum = _10seconds.total()._sum; 181 const uint64_t nsamples = _10seconds.total()._nsamples; 182 return avg(sum, nsamples); 183 } 184 185 uint64_t avg_10_minutes() const { 186 const uint64_t sum = _10seconds.accumulated()._sum + 187 _10minutes.total()._sum; 188 const uint64_t nsamples = _10seconds.accumulated()._nsamples + 189 _10minutes.total()._nsamples; 190 return avg(sum, nsamples); 191 } 192 193 uint64_t avg_10_hours() const { 194 const uint64_t sum = _10seconds.accumulated()._sum + 195 _10minutes.accumulated()._sum + 196 _10hours.total()._sum; 197 const uint64_t nsamples = _10seconds.accumulated()._nsamples + 198 _10minutes.accumulated()._nsamples + 199 _10hours.total()._nsamples; 200 return avg(sum, nsamples); 201 } 202 203 uint64_t avg_total() const { 204 const uint64_t sum = _10seconds.accumulated()._sum + 205 _10minutes.accumulated()._sum + 206 _10hours.accumulated()._sum + 207 _total._sum; 208 const uint64_t nsamples = _10seconds.accumulated()._nsamples + 209 _10minutes.accumulated()._nsamples + 210 _10hours.accumulated()._nsamples + 211 _total._nsamples; 212 return avg(sum, nsamples); 213 } 214 215 uint64_t max_10_seconds() const { 216 return _10seconds.total()._max; 217 } 218 219 uint64_t max_10_minutes() const { 220 return MAX2(_10seconds.accumulated()._max, 221 _10minutes.total()._max); 222 } 223 224 uint64_t max_10_hours() const { 225 return MAX3(_10seconds.accumulated()._max, 226 _10minutes.accumulated()._max, 227 _10hours.total()._max); 228 } 229 230 uint64_t max_total() const { 231 return MAX4(_10seconds.accumulated()._max, 232 _10minutes.accumulated()._max, 233 _10hours.accumulated()._max, 234 _total._max); 235 } 236 }; 237 238 // 239 // Stat unit printers 240 // 241 void ZStatUnitTime(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) { 242 log.print(" %10s: %-41s " 243 "%9.3f / %-9.3f " 244 "%9.3f / %-9.3f " 245 "%9.3f / %-9.3f " 246 "%9.3f / %-9.3f ms", 247 sampler.group(), 248 sampler.name(), 249 TimeHelper::counter_to_millis(history.avg_10_seconds()), 250 TimeHelper::counter_to_millis(history.max_10_seconds()), 251 TimeHelper::counter_to_millis(history.avg_10_minutes()), 252 TimeHelper::counter_to_millis(history.max_10_minutes()), 253 TimeHelper::counter_to_millis(history.avg_10_hours()), 254 TimeHelper::counter_to_millis(history.max_10_hours()), 255 TimeHelper::counter_to_millis(history.avg_total()), 256 TimeHelper::counter_to_millis(history.max_total())); 257 } 258 259 void ZStatUnitBytes(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) { 260 log.print(" %10s: %-41s " 261 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 262 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 263 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 264 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " MB", 265 sampler.group(), 266 sampler.name(), 267 history.avg_10_seconds() / M, 268 history.max_10_seconds() / M, 269 history.avg_10_minutes() / M, 270 history.max_10_minutes() / M, 271 history.avg_10_hours() / M, 272 history.max_10_hours() / M, 273 history.avg_total() / M, 274 history.max_total() / M); 275 } 276 277 void ZStatUnitThreads(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) { 278 log.print(" %10s: %-41s " 279 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 280 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 281 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 282 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " threads", 283 sampler.group(), 284 sampler.name(), 285 history.avg_10_seconds(), 286 history.max_10_seconds(), 287 history.avg_10_minutes(), 288 history.max_10_minutes(), 289 history.avg_10_hours(), 290 history.max_10_hours(), 291 history.avg_total(), 292 history.max_total()); 293 } 294 295 void ZStatUnitBytesPerSecond(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) { 296 log.print(" %10s: %-41s " 297 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 298 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 299 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 300 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " MB/s", 301 sampler.group(), 302 sampler.name(), 303 history.avg_10_seconds() / M, 304 history.max_10_seconds() / M, 305 history.avg_10_minutes() / M, 306 history.max_10_minutes() / M, 307 history.avg_10_hours() / M, 308 history.max_10_hours() / M, 309 history.avg_total() / M, 310 history.max_total() / M); 311 } 312 313 void ZStatUnitOpsPerSecond(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) { 314 log.print(" %10s: %-41s " 315 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 316 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 317 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " " 318 UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " ops/s", 319 sampler.group(), 320 sampler.name(), 321 history.avg_10_seconds(), 322 history.max_10_seconds(), 323 history.avg_10_minutes(), 324 history.max_10_minutes(), 325 history.avg_10_hours(), 326 history.max_10_hours(), 327 history.avg_total(), 328 history.max_total()); 329 } 330 331 // 332 // Stat value 333 // 334 uintptr_t ZStatValue::_base = 0; 335 uint32_t ZStatValue::_cpu_offset = 0; 336 337 ZStatValue::ZStatValue(const char* group, 338 const char* name, 339 uint32_t id, 340 uint32_t size) : 341 _group(group), 342 _name(name), 343 _id(id), 344 _offset(_cpu_offset) { 345 assert(_base == 0, "Already initialized"); 346 _cpu_offset += size; 347 } 348 349 template <typename T> 350 T* ZStatValue::get_cpu_local(uint32_t cpu) const { 351 assert(_base != 0, "Not initialized"); 352 const uintptr_t cpu_base = _base + (_cpu_offset * cpu); 353 const uintptr_t value_addr = cpu_base + _offset; 354 return (T*)value_addr; 355 } 356 357 void ZStatValue::initialize() { 358 // Finalize and align CPU offset 359 _cpu_offset = align_up(_cpu_offset, (uint32_t)ZCacheLineSize); 360 361 // Allocation aligned memory 362 const size_t size = _cpu_offset * ZCPU::count(); 363 _base = ZUtils::alloc_aligned(ZCacheLineSize, size); 364 } 365 366 const char* ZStatValue::group() const { 367 return _group; 368 } 369 370 const char* ZStatValue::name() const { 371 return _name; 372 } 373 374 uint32_t ZStatValue::id() const { 375 return _id; 376 } 377 378 // 379 // Stat iterable value 380 // 381 template <typename T> uint32_t ZStatIterableValue<T>::_count = 0; 382 template <typename T> T* ZStatIterableValue<T>::_first = NULL; 383 384 template <typename T> 385 ZStatIterableValue<T>::ZStatIterableValue(const char* group, 386 const char* name, 387 uint32_t size) : 388 ZStatValue(group, name, _count++, size), 389 _next(insert()) {} 390 391 template <typename T> 392 T* ZStatIterableValue<T>::insert() const { 393 T** current = &_first; 394 395 while (*current != NULL) { 396 // First sort by group, then by name 397 const int group_cmp = strcmp((*current)->group(), group()); 398 const int name_cmp = strcmp((*current)->name(), name()); 399 if ((group_cmp > 0) || (group_cmp == 0 && name_cmp > 0)) { 400 break; 401 } 402 403 current = &(*current)->_next; 404 } 405 406 T* const next = *current; 407 *current = (T*)this; 408 return next; 409 } 410 411 // 412 // Stat sampler 413 // 414 ZStatSampler::ZStatSampler(const char* group, const char* name, ZStatUnitPrinter printer) : 415 ZStatIterableValue<ZStatSampler>(group, name, sizeof(ZStatSamplerData)), 416 _printer(printer) {} 417 418 ZStatSamplerData* ZStatSampler::get() const { 419 return get_cpu_local<ZStatSamplerData>(ZCPU::id()); 420 } 421 422 ZStatSamplerData ZStatSampler::collect_and_reset() const { 423 ZStatSamplerData all; 424 425 const uint32_t ncpus = ZCPU::count(); 426 for (uint32_t i = 0; i < ncpus; i++) { 427 ZStatSamplerData* const cpu_data = get_cpu_local<ZStatSamplerData>(i); 428 if (cpu_data->_nsamples > 0) { 429 const uint64_t nsamples = Atomic::xchg(&cpu_data->_nsamples, (uint64_t)0); 430 const uint64_t sum = Atomic::xchg(&cpu_data->_sum, (uint64_t)0); 431 const uint64_t max = Atomic::xchg(&cpu_data->_max, (uint64_t)0); 432 all._nsamples += nsamples; 433 all._sum += sum; 434 if (all._max < max) { 435 all._max = max; 436 } 437 } 438 } 439 440 return all; 441 } 442 443 ZStatUnitPrinter ZStatSampler::printer() const { 444 return _printer; 445 } 446 447 // 448 // Stat counter 449 // 450 ZStatCounter::ZStatCounter(const char* group, const char* name, ZStatUnitPrinter printer) : 451 ZStatIterableValue<ZStatCounter>(group, name, sizeof(ZStatCounterData)), 452 _sampler(group, name, printer) {} 453 454 ZStatCounterData* ZStatCounter::get() const { 455 return get_cpu_local<ZStatCounterData>(ZCPU::id()); 456 } 457 458 void ZStatCounter::sample_and_reset() const { 459 uint64_t counter = 0; 460 461 const uint32_t ncpus = ZCPU::count(); 462 for (uint32_t i = 0; i < ncpus; i++) { 463 ZStatCounterData* const cpu_data = get_cpu_local<ZStatCounterData>(i); 464 counter += Atomic::xchg(&cpu_data->_counter, (uint64_t)0); 465 } 466 467 ZStatSample(_sampler, counter); 468 } 469 470 // 471 // Stat unsampled counter 472 // 473 ZStatUnsampledCounter::ZStatUnsampledCounter(const char* name) : 474 ZStatIterableValue<ZStatUnsampledCounter>("Unsampled", name, sizeof(ZStatCounterData)) {} 475 476 ZStatCounterData* ZStatUnsampledCounter::get() const { 477 return get_cpu_local<ZStatCounterData>(ZCPU::id()); 478 } 479 480 ZStatCounterData ZStatUnsampledCounter::collect_and_reset() const { 481 ZStatCounterData all; 482 483 const uint32_t ncpus = ZCPU::count(); 484 for (uint32_t i = 0; i < ncpus; i++) { 485 ZStatCounterData* const cpu_data = get_cpu_local<ZStatCounterData>(i); 486 all._counter += Atomic::xchg(&cpu_data->_counter, (uint64_t)0); 487 } 488 489 return all; 490 } 491 492 // 493 // Stat MMU (Minimum Mutator Utilization) 494 // 495 ZStatMMUPause::ZStatMMUPause() : 496 _start(0.0), 497 _end(0.0) {} 498 499 ZStatMMUPause::ZStatMMUPause(const Ticks& start, const Ticks& end) : 500 _start(TimeHelper::counter_to_millis(start.value())), 501 _end(TimeHelper::counter_to_millis(end.value())) {} 502 503 double ZStatMMUPause::end() const { 504 return _end; 505 } 506 507 double ZStatMMUPause::overlap(double start, double end) const { 508 const double start_max = MAX2(start, _start); 509 const double end_min = MIN2(end, _end); 510 511 if (end_min > start_max) { 512 // Overlap found 513 return end_min - start_max; 514 } 515 516 // No overlap 517 return 0.0; 518 } 519 520 size_t ZStatMMU::_next = 0; 521 size_t ZStatMMU::_npauses = 0; 522 ZStatMMUPause ZStatMMU::_pauses[200]; 523 double ZStatMMU::_mmu_2ms = 100.0; 524 double ZStatMMU::_mmu_5ms = 100.0; 525 double ZStatMMU::_mmu_10ms = 100.0; 526 double ZStatMMU::_mmu_20ms = 100.0; 527 double ZStatMMU::_mmu_50ms = 100.0; 528 double ZStatMMU::_mmu_100ms = 100.0; 529 530 const ZStatMMUPause& ZStatMMU::pause(size_t index) { 531 return _pauses[(_next - index - 1) % ARRAY_SIZE(_pauses)]; 532 } 533 534 double ZStatMMU::calculate_mmu(double time_slice) { 535 const double end = pause(0).end(); 536 const double start = end - time_slice; 537 double time_paused = 0.0; 538 539 // Find all overlapping pauses 540 for (size_t i = 0; i < _npauses; i++) { 541 const double overlap = pause(i).overlap(start, end); 542 if (overlap == 0.0) { 543 // No overlap 544 break; 545 } 546 547 time_paused += overlap; 548 } 549 550 // Calculate MMU 551 const double time_mutator = time_slice - time_paused; 552 return percent_of(time_mutator, time_slice); 553 } 554 555 void ZStatMMU::register_pause(const Ticks& start, const Ticks& end) { 556 // Add pause 557 const size_t index = _next++ % ARRAY_SIZE(_pauses); 558 _pauses[index] = ZStatMMUPause(start, end); 559 _npauses = MIN2(_npauses + 1, ARRAY_SIZE(_pauses)); 560 561 // Recalculate MMUs 562 _mmu_2ms = MIN2(_mmu_2ms, calculate_mmu(2)); 563 _mmu_5ms = MIN2(_mmu_5ms, calculate_mmu(5)); 564 _mmu_10ms = MIN2(_mmu_10ms, calculate_mmu(10)); 565 _mmu_20ms = MIN2(_mmu_20ms, calculate_mmu(20)); 566 _mmu_50ms = MIN2(_mmu_50ms, calculate_mmu(50)); 567 _mmu_100ms = MIN2(_mmu_100ms, calculate_mmu(100)); 568 } 569 570 void ZStatMMU::print() { 571 log_info(gc, mmu)("MMU: 2ms/%.1f%%, 5ms/%.1f%%, 10ms/%.1f%%, 20ms/%.1f%%, 50ms/%.1f%%, 100ms/%.1f%%", 572 _mmu_2ms, _mmu_5ms, _mmu_10ms, _mmu_20ms, _mmu_50ms, _mmu_100ms); 573 } 574 575 // 576 // Stat phases 577 // 578 ConcurrentGCTimer ZStatPhase::_timer; 579 580 ZStatPhase::ZStatPhase(const char* group, const char* name) : 581 _sampler(group, name, ZStatUnitTime) {} 582 583 void ZStatPhase::log_start(LogTargetHandle log, bool thread) const { 584 if (!log.is_enabled()) { 585 return; 586 } 587 588 if (thread) { 589 ResourceMark rm; 590 log.print("%s (%s)", name(), Thread::current()->name()); 591 } else { 592 log.print("%s", name()); 593 } 594 } 595 596 void ZStatPhase::log_end(LogTargetHandle log, const Tickspan& duration, bool thread) const { 597 if (!log.is_enabled()) { 598 return; 599 } 600 601 if (thread) { 602 ResourceMark rm; 603 log.print("%s (%s) %.3fms", name(), Thread::current()->name(), TimeHelper::counter_to_millis(duration.value())); 604 } else { 605 log.print("%s %.3fms", name(), TimeHelper::counter_to_millis(duration.value())); 606 } 607 } 608 609 ConcurrentGCTimer* ZStatPhase::timer() { 610 return &_timer; 611 } 612 613 const char* ZStatPhase::name() const { 614 return _sampler.name(); 615 } 616 617 ZStatPhaseCycle::ZStatPhaseCycle(const char* name) : 618 ZStatPhase("Collector", name) {} 619 620 void ZStatPhaseCycle::register_start(const Ticks& start) const { 621 timer()->register_gc_start(start); 622 623 ZTracer::tracer()->report_gc_start(ZCollectedHeap::heap()->gc_cause(), start); 624 625 ZCollectedHeap::heap()->print_heap_before_gc(); 626 ZCollectedHeap::heap()->trace_heap_before_gc(ZTracer::tracer()); 627 628 log_info(gc, start)("Garbage Collection (%s)", 629 GCCause::to_string(ZCollectedHeap::heap()->gc_cause())); 630 } 631 632 void ZStatPhaseCycle::register_end(const Ticks& start, const Ticks& end) const { 633 timer()->register_gc_end(end); 634 635 ZCollectedHeap::heap()->print_heap_after_gc(); 636 ZCollectedHeap::heap()->trace_heap_after_gc(ZTracer::tracer()); 637 638 ZTracer::tracer()->report_gc_end(end, timer()->time_partitions()); 639 640 const Tickspan duration = end - start; 641 ZStatSample(_sampler, duration.value()); 642 643 ZStatLoad::print(); 644 ZStatMMU::print(); 645 ZStatMark::print(); 646 ZStatNMethods::print(); 647 ZStatMetaspace::print(); 648 ZStatReferences::print(); 649 ZStatRelocation::print(); 650 ZStatHeap::print(); 651 652 log_info(gc)("Garbage Collection (%s) " ZSIZE_FMT "->" ZSIZE_FMT, 653 GCCause::to_string(ZCollectedHeap::heap()->gc_cause()), 654 ZSIZE_ARGS(ZStatHeap::used_at_mark_start()), 655 ZSIZE_ARGS(ZStatHeap::used_at_relocate_end())); 656 } 657 658 Tickspan ZStatPhasePause::_max; 659 660 ZStatPhasePause::ZStatPhasePause(const char* name) : 661 ZStatPhase("Phase", name) {} 662 663 const Tickspan& ZStatPhasePause::max() { 664 return _max; 665 } 666 667 void ZStatPhasePause::register_start(const Ticks& start) const { 668 timer()->register_gc_pause_start(name(), start); 669 670 LogTarget(Debug, gc, phases, start) log; 671 log_start(log); 672 } 673 674 void ZStatPhasePause::register_end(const Ticks& start, const Ticks& end) const { 675 timer()->register_gc_pause_end(end); 676 677 const Tickspan duration = end - start; 678 ZStatSample(_sampler, duration.value()); 679 680 // Track max pause time 681 if (_max < duration) { 682 _max = duration; 683 } 684 685 // Track minimum mutator utilization 686 ZStatMMU::register_pause(start, end); 687 688 LogTarget(Info, gc, phases) log; 689 log_end(log, duration); 690 } 691 692 ZStatPhaseConcurrent::ZStatPhaseConcurrent(const char* name) : 693 ZStatPhase("Phase", name) {} 694 695 void ZStatPhaseConcurrent::register_start(const Ticks& start) const { 696 timer()->register_gc_concurrent_start(name(), start); 697 698 LogTarget(Debug, gc, phases, start) log; 699 log_start(log); 700 } 701 702 void ZStatPhaseConcurrent::register_end(const Ticks& start, const Ticks& end) const { 703 timer()->register_gc_concurrent_end(end); 704 705 const Tickspan duration = end - start; 706 ZStatSample(_sampler, duration.value()); 707 708 LogTarget(Info, gc, phases) log; 709 log_end(log, duration); 710 } 711 712 ZStatSubPhase::ZStatSubPhase(const char* name) : 713 ZStatPhase("Subphase", name) {} 714 715 void ZStatSubPhase::register_start(const Ticks& start) const { 716 LogTarget(Debug, gc, phases, start) log; 717 log_start(log, true /* thread */); 718 } 719 720 void ZStatSubPhase::register_end(const Ticks& start, const Ticks& end) const { 721 ZTracer::tracer()->report_thread_phase(name(), start, end); 722 723 const Tickspan duration = end - start; 724 ZStatSample(_sampler, duration.value()); 725 726 LogTarget(Debug, gc, phases) log; 727 log_end(log, duration, true /* thread */); 728 } 729 730 ZStatCriticalPhase::ZStatCriticalPhase(const char* name, bool verbose) : 731 ZStatPhase("Critical", name), 732 _counter("Critical", name, ZStatUnitOpsPerSecond), 733 _verbose(verbose) {} 734 735 void ZStatCriticalPhase::register_start(const Ticks& start) const { 736 LogTarget(Debug, gc, start) log; 737 log_start(log, true /* thread */); 738 } 739 740 void ZStatCriticalPhase::register_end(const Ticks& start, const Ticks& end) const { 741 ZTracer::tracer()->report_thread_phase(name(), start, end); 742 743 const Tickspan duration = end - start; 744 ZStatSample(_sampler, duration.value()); 745 ZStatInc(_counter); 746 747 if (_verbose) { 748 LogTarget(Info, gc) log; 749 log_end(log, duration, true /* thread */); 750 } else { 751 LogTarget(Debug, gc) log; 752 log_end(log, duration, true /* thread */); 753 } 754 } 755 756 // 757 // Stat timer 758 // 759 THREAD_LOCAL uint32_t ZStatTimerDisable::_active = 0; 760 761 // 762 // Stat sample/inc 763 // 764 void ZStatSample(const ZStatSampler& sampler, uint64_t value) { 765 ZStatSamplerData* const cpu_data = sampler.get(); 766 Atomic::add(&cpu_data->_nsamples, 1u); 767 Atomic::add(&cpu_data->_sum, value); 768 769 uint64_t max = cpu_data->_max; 770 for (;;) { 771 if (max >= value) { 772 // Not max 773 break; 774 } 775 776 const uint64_t new_max = value; 777 const uint64_t prev_max = Atomic::cmpxchg(&cpu_data->_max, max, new_max); 778 if (prev_max == max) { 779 // Success 780 break; 781 } 782 783 // Retry 784 max = prev_max; 785 } 786 787 ZTracer::tracer()->report_stat_sampler(sampler, value); 788 } 789 790 void ZStatInc(const ZStatCounter& counter, uint64_t increment) { 791 ZStatCounterData* const cpu_data = counter.get(); 792 const uint64_t value = Atomic::add(&cpu_data->_counter, increment); 793 794 ZTracer::tracer()->report_stat_counter(counter, increment, value); 795 } 796 797 void ZStatInc(const ZStatUnsampledCounter& counter, uint64_t increment) { 798 ZStatCounterData* const cpu_data = counter.get(); 799 Atomic::add(&cpu_data->_counter, increment); 800 } 801 802 // 803 // Stat allocation rate 804 // 805 const ZStatUnsampledCounter ZStatAllocRate::_counter("Allocation Rate"); 806 TruncatedSeq ZStatAllocRate::_rate(ZStatAllocRate::sample_window_sec * ZStatAllocRate::sample_hz); 807 TruncatedSeq ZStatAllocRate::_rate_avg(ZStatAllocRate::sample_window_sec * ZStatAllocRate::sample_hz); 808 809 const ZStatUnsampledCounter& ZStatAllocRate::counter() { 810 return _counter; 811 } 812 813 uint64_t ZStatAllocRate::sample_and_reset() { 814 const ZStatCounterData bytes_per_sample = _counter.collect_and_reset(); 815 const uint64_t bytes_per_second = bytes_per_sample._counter * sample_hz; 816 817 _rate.add(bytes_per_second); 818 _rate_avg.add(_rate.avg()); 819 820 return bytes_per_second; 821 } 822 823 double ZStatAllocRate::avg() { 824 return _rate.avg(); 825 } 826 827 double ZStatAllocRate::avg_sd() { 828 return _rate_avg.sd(); 829 } 830 831 // 832 // Stat thread 833 // 834 ZStat::ZStat() : 835 _metronome(sample_hz) { 836 set_name("ZStat"); 837 create_and_start(); 838 } 839 840 void ZStat::sample_and_collect(ZStatSamplerHistory* history) const { 841 // Sample counters 842 for (const ZStatCounter* counter = ZStatCounter::first(); counter != NULL; counter = counter->next()) { 843 counter->sample_and_reset(); 844 } 845 846 // Collect samples 847 for (const ZStatSampler* sampler = ZStatSampler::first(); sampler != NULL; sampler = sampler->next()) { 848 ZStatSamplerHistory& sampler_history = history[sampler->id()]; 849 sampler_history.add(sampler->collect_and_reset()); 850 } 851 } 852 853 bool ZStat::should_print(LogTargetHandle log) const { 854 static uint64_t print_at = ZStatisticsInterval; 855 const uint64_t now = os::elapsedTime(); 856 857 if (now < print_at) { 858 return false; 859 } 860 861 print_at = ((now / ZStatisticsInterval) * ZStatisticsInterval) + ZStatisticsInterval; 862 863 return log.is_enabled(); 864 } 865 866 void ZStat::print(LogTargetHandle log, const ZStatSamplerHistory* history) const { 867 // Print 868 log.print("=== Garbage Collection Statistics ======================================================================================================================="); 869 log.print(" Last 10s Last 10m Last 10h Total"); 870 log.print(" Avg / Max Avg / Max Avg / Max Avg / Max"); 871 872 for (const ZStatSampler* sampler = ZStatSampler::first(); sampler != NULL; sampler = sampler->next()) { 873 const ZStatSamplerHistory& sampler_history = history[sampler->id()]; 874 const ZStatUnitPrinter printer = sampler->printer(); 875 printer(log, *sampler, sampler_history); 876 } 877 878 log.print("========================================================================================================================================================="); 879 } 880 881 void ZStat::run_service() { 882 ZStatSamplerHistory* const history = new ZStatSamplerHistory[ZStatSampler::count()]; 883 LogTarget(Info, gc, stats) log; 884 885 // Main loop 886 while (_metronome.wait_for_tick()) { 887 sample_and_collect(history); 888 if (should_print(log)) { 889 print(log, history); 890 } 891 } 892 893 delete [] history; 894 } 895 896 void ZStat::stop_service() { 897 _metronome.stop(); 898 } 899 900 // 901 // Stat table 902 // 903 class ZStatTablePrinter { 904 private: 905 static const size_t _buffer_size = 256; 906 907 const size_t _column0_width; 908 const size_t _columnN_width; 909 char _buffer[_buffer_size]; 910 911 public: 912 class ZColumn { 913 private: 914 char* const _buffer; 915 const size_t _position; 916 const size_t _width; 917 const size_t _width_next; 918 919 ZColumn next() const { 920 // Insert space between columns 921 _buffer[_position + _width] = ' '; 922 return ZColumn(_buffer, _position + _width + 1, _width_next, _width_next); 923 } 924 925 size_t print(size_t position, const char* fmt, va_list va) { 926 const int res = jio_vsnprintf(_buffer + position, _buffer_size - position, fmt, va); 927 if (res < 0) { 928 return 0; 929 } 930 931 return (size_t)res; 932 } 933 934 public: 935 ZColumn(char* buffer, size_t position, size_t width, size_t width_next) : 936 _buffer(buffer), 937 _position(position), 938 _width(width), 939 _width_next(width_next) {} 940 941 ZColumn left(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { 942 va_list va; 943 944 va_start(va, fmt); 945 const size_t written = print(_position, fmt, va); 946 va_end(va); 947 948 if (written < _width) { 949 // Fill empty space 950 memset(_buffer + _position + written, ' ', _width - written); 951 } 952 953 return next(); 954 } 955 956 ZColumn right(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { 957 va_list va; 958 959 va_start(va, fmt); 960 const size_t written = print(_position, fmt, va); 961 va_end(va); 962 963 if (written > _width) { 964 // Line too long 965 return fill('?'); 966 } 967 968 if (written < _width) { 969 // Short line, move all to right 970 memmove(_buffer + _position + _width - written, _buffer + _position, written); 971 972 // Fill empty space 973 memset(_buffer + _position, ' ', _width - written); 974 } 975 976 return next(); 977 } 978 979 ZColumn center(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { 980 va_list va; 981 982 va_start(va, fmt); 983 const size_t written = print(_position, fmt, va); 984 va_end(va); 985 986 if (written > _width) { 987 // Line too long 988 return fill('?'); 989 } 990 991 if (written < _width) { 992 // Short line, move all to center 993 const size_t start_space = (_width - written) / 2; 994 const size_t end_space = _width - written - start_space; 995 memmove(_buffer + _position + start_space, _buffer + _position, written); 996 997 // Fill empty spaces 998 memset(_buffer + _position, ' ', start_space); 999 memset(_buffer + _position + start_space + written, ' ', end_space); 1000 } 1001 1002 return next(); 1003 } 1004 1005 ZColumn fill(char filler = ' ') { 1006 memset(_buffer + _position, filler, _width); 1007 return next(); 1008 } 1009 1010 const char* end() { 1011 _buffer[_position] = '\0'; 1012 return _buffer; 1013 } 1014 }; 1015 1016 public: 1017 ZStatTablePrinter(size_t column0_width, size_t columnN_width) : 1018 _column0_width(column0_width), 1019 _columnN_width(columnN_width) {} 1020 1021 ZColumn operator()() { 1022 return ZColumn(_buffer, 0, _column0_width, _columnN_width); 1023 } 1024 }; 1025 1026 // 1027 // Stat cycle 1028 // 1029 uint64_t ZStatCycle::_nwarmup_cycles = 0; 1030 Ticks ZStatCycle::_start_of_last; 1031 Ticks ZStatCycle::_end_of_last; 1032 NumberSeq ZStatCycle::_normalized_duration(0.3 /* alpha */); 1033 1034 void ZStatCycle::at_start() { 1035 _start_of_last = Ticks::now(); 1036 } 1037 1038 void ZStatCycle::at_end(GCCause::Cause cause, double boost_factor) { 1039 _end_of_last = Ticks::now(); 1040 1041 if (cause == GCCause::_z_warmup) { 1042 _nwarmup_cycles++; 1043 } 1044 1045 // Calculate normalized cycle duration. The measured duration is 1046 // normalized using the boost factor to avoid artificial deflation 1047 // of the duration when boost mode is enabled. 1048 const double duration = (_end_of_last - _start_of_last).seconds(); 1049 const double normalized_duration = duration * boost_factor; 1050 _normalized_duration.add(normalized_duration); 1051 } 1052 1053 bool ZStatCycle::is_warm() { 1054 return _nwarmup_cycles >= 3; 1055 } 1056 1057 uint64_t ZStatCycle::nwarmup_cycles() { 1058 return _nwarmup_cycles; 1059 } 1060 1061 bool ZStatCycle::is_normalized_duration_trustable() { 1062 // The normalized duration is considered trustable if we have 1063 // completed at least one warmup cycle 1064 return _nwarmup_cycles > 0; 1065 } 1066 1067 const AbsSeq& ZStatCycle::normalized_duration() { 1068 return _normalized_duration; 1069 } 1070 1071 double ZStatCycle::time_since_last() { 1072 if (_end_of_last.value() == 0) { 1073 // No end recorded yet, return time since VM start 1074 return os::elapsedTime(); 1075 } 1076 1077 const Ticks now = Ticks::now(); 1078 const Tickspan time_since_last = now - _end_of_last; 1079 return time_since_last.seconds(); 1080 } 1081 1082 // 1083 // Stat load 1084 // 1085 void ZStatLoad::print() { 1086 double loadavg[3] = {}; 1087 os::loadavg(loadavg, ARRAY_SIZE(loadavg)); 1088 log_info(gc, load)("Load: %.2f/%.2f/%.2f", loadavg[0], loadavg[1], loadavg[2]); 1089 } 1090 1091 // 1092 // Stat mark 1093 // 1094 size_t ZStatMark::_nstripes; 1095 size_t ZStatMark::_nproactiveflush; 1096 size_t ZStatMark::_nterminateflush; 1097 size_t ZStatMark::_ntrycomplete; 1098 size_t ZStatMark::_ncontinue; 1099 1100 void ZStatMark::set_at_mark_start(size_t nstripes) { 1101 _nstripes = nstripes; 1102 } 1103 1104 void ZStatMark::set_at_mark_end(size_t nproactiveflush, 1105 size_t nterminateflush, 1106 size_t ntrycomplete, 1107 size_t ncontinue) { 1108 _nproactiveflush = nproactiveflush; 1109 _nterminateflush = nterminateflush; 1110 _ntrycomplete = ntrycomplete; 1111 _ncontinue = ncontinue; 1112 } 1113 1114 void ZStatMark::print() { 1115 log_info(gc, marking)("Mark: " 1116 SIZE_FORMAT " stripe(s), " 1117 SIZE_FORMAT " proactive flush(es), " 1118 SIZE_FORMAT " terminate flush(es), " 1119 SIZE_FORMAT " completion(s), " 1120 SIZE_FORMAT " continuation(s) ", 1121 _nstripes, 1122 _nproactiveflush, 1123 _nterminateflush, 1124 _ntrycomplete, 1125 _ncontinue); 1126 } 1127 1128 // 1129 // Stat relocation 1130 // 1131 ZRelocationSetSelectorStats ZStatRelocation::_stats; 1132 bool ZStatRelocation::_success; 1133 1134 void ZStatRelocation::set_at_select_relocation_set(const ZRelocationSetSelectorStats& stats) { 1135 _stats = stats; 1136 } 1137 1138 void ZStatRelocation::set_at_relocate_end(bool success) { 1139 _success = success; 1140 } 1141 1142 void ZStatRelocation::print(const char* name, const ZRelocationSetSelectorGroupStats& group) { 1143 const size_t total = _stats.small().total() + _stats.medium().total() + _stats.large().total(); 1144 1145 log_info(gc, reloc)("%s Pages: " SIZE_FORMAT " / " ZSIZE_FMT ", Empty: " ZSIZE_FMT ", Compacting: " ZSIZE_FMT "->" ZSIZE_FMT, 1146 name, 1147 group.npages(), 1148 ZSIZE_ARGS_WITH_MAX(group.total(), total), 1149 ZSIZE_ARGS_WITH_MAX(group.empty(), total), 1150 ZSIZE_ARGS_WITH_MAX(group.compacting_from(), total), 1151 ZSIZE_ARGS_WITH_MAX(group.compacting_to(), total)); 1152 } 1153 1154 void ZStatRelocation::print() { 1155 print("Small", _stats.small()); 1156 if (ZPageSizeMedium != 0) { 1157 print("Medium", _stats.medium()); 1158 } 1159 print("Large", _stats.large()); 1160 1161 log_info(gc, reloc)("Relocation: %s", _success ? "Successful" : "Incomplete"); 1162 } 1163 1164 // 1165 // Stat nmethods 1166 // 1167 void ZStatNMethods::print() { 1168 log_info(gc, nmethod)("NMethods: " SIZE_FORMAT " registered, " SIZE_FORMAT " unregistered", 1169 ZNMethodTable::registered_nmethods(), 1170 ZNMethodTable::unregistered_nmethods()); 1171 } 1172 1173 // 1174 // Stat metaspace 1175 // 1176 void ZStatMetaspace::print() { 1177 log_info(gc, metaspace)("Metaspace: " 1178 SIZE_FORMAT "M used, " 1179 SIZE_FORMAT "M committed, " SIZE_FORMAT "M reserved", 1180 MetaspaceUtils::used_bytes() / M, 1181 MetaspaceUtils::committed_bytes() / M, 1182 MetaspaceUtils::reserved_bytes() / M); 1183 } 1184 1185 // 1186 // Stat references 1187 // 1188 ZStatReferences::ZCount ZStatReferences::_soft; 1189 ZStatReferences::ZCount ZStatReferences::_weak; 1190 ZStatReferences::ZCount ZStatReferences::_final; 1191 ZStatReferences::ZCount ZStatReferences::_phantom; 1192 1193 void ZStatReferences::set(ZCount* count, size_t encountered, size_t discovered, size_t enqueued) { 1194 count->encountered = encountered; 1195 count->discovered = discovered; 1196 count->enqueued = enqueued; 1197 } 1198 1199 void ZStatReferences::set_soft(size_t encountered, size_t discovered, size_t enqueued) { 1200 set(&_soft, encountered, discovered, enqueued); 1201 } 1202 1203 void ZStatReferences::set_weak(size_t encountered, size_t discovered, size_t enqueued) { 1204 set(&_weak, encountered, discovered, enqueued); 1205 } 1206 1207 void ZStatReferences::set_final(size_t encountered, size_t discovered, size_t enqueued) { 1208 set(&_final, encountered, discovered, enqueued); 1209 } 1210 1211 void ZStatReferences::set_phantom(size_t encountered, size_t discovered, size_t enqueued) { 1212 set(&_phantom, encountered, discovered, enqueued); 1213 } 1214 1215 void ZStatReferences::print(const char* name, const ZStatReferences::ZCount& ref) { 1216 log_info(gc, ref)("%s: " 1217 SIZE_FORMAT " encountered, " 1218 SIZE_FORMAT " discovered, " 1219 SIZE_FORMAT " enqueued", 1220 name, 1221 ref.encountered, 1222 ref.discovered, 1223 ref.enqueued); 1224 } 1225 1226 void ZStatReferences::print() { 1227 print("Soft", _soft); 1228 print("Weak", _weak); 1229 print("Final", _final); 1230 print("Phantom", _phantom); 1231 } 1232 1233 // 1234 // Stat heap 1235 // 1236 ZStatHeap::ZAtInitialize ZStatHeap::_at_initialize; 1237 ZStatHeap::ZAtMarkStart ZStatHeap::_at_mark_start; 1238 ZStatHeap::ZAtMarkEnd ZStatHeap::_at_mark_end; 1239 ZStatHeap::ZAtRelocateStart ZStatHeap::_at_relocate_start; 1240 ZStatHeap::ZAtRelocateEnd ZStatHeap::_at_relocate_end; 1241 1242 size_t ZStatHeap::capacity_high() { 1243 return MAX4(_at_mark_start.capacity, 1244 _at_mark_end.capacity, 1245 _at_relocate_start.capacity, 1246 _at_relocate_end.capacity); 1247 } 1248 1249 size_t ZStatHeap::capacity_low() { 1250 return MIN4(_at_mark_start.capacity, 1251 _at_mark_end.capacity, 1252 _at_relocate_start.capacity, 1253 _at_relocate_end.capacity); 1254 } 1255 1256 size_t ZStatHeap::available(size_t used) { 1257 return _at_initialize.max_capacity - used; 1258 } 1259 1260 size_t ZStatHeap::reserve(size_t used) { 1261 return MIN2(_at_initialize.max_reserve, available(used)); 1262 } 1263 1264 size_t ZStatHeap::free(size_t used) { 1265 return available(used) - reserve(used); 1266 } 1267 1268 void ZStatHeap::set_at_initialize(size_t min_capacity, 1269 size_t max_capacity, 1270 size_t max_reserve) { 1271 _at_initialize.min_capacity = min_capacity; 1272 _at_initialize.max_capacity = max_capacity; 1273 _at_initialize.max_reserve = max_reserve; 1274 } 1275 1276 void ZStatHeap::set_at_mark_start(size_t soft_max_capacity, 1277 size_t capacity, 1278 size_t used) { 1279 _at_mark_start.soft_max_capacity = soft_max_capacity; 1280 _at_mark_start.capacity = capacity; 1281 _at_mark_start.reserve = reserve(used); 1282 _at_mark_start.used = used; 1283 _at_mark_start.free = free(used); 1284 } 1285 1286 void ZStatHeap::set_at_mark_end(size_t capacity, 1287 size_t allocated, 1288 size_t used) { 1289 _at_mark_end.capacity = capacity; 1290 _at_mark_end.reserve = reserve(used); 1291 _at_mark_end.allocated = allocated; 1292 _at_mark_end.used = used; 1293 _at_mark_end.free = free(used); 1294 } 1295 1296 void ZStatHeap::set_at_select_relocation_set(const ZRelocationSetSelectorStats& stats, size_t reclaimed) { 1297 const size_t live = stats.small().live() + stats.medium().live() + stats.large().live(); 1298 const size_t garbage = stats.small().garbage() + stats.medium().garbage() + stats.large().garbage(); 1299 1300 _at_mark_end.live = live; 1301 _at_mark_end.garbage = garbage; 1302 1303 _at_relocate_start.garbage = garbage - reclaimed; 1304 _at_relocate_start.reclaimed = reclaimed; 1305 } 1306 1307 void ZStatHeap::set_at_relocate_start(size_t capacity, 1308 size_t allocated, 1309 size_t used) { 1310 _at_relocate_start.capacity = capacity; 1311 _at_relocate_start.reserve = reserve(used); 1312 _at_relocate_start.allocated = allocated; 1313 _at_relocate_start.used = used; 1314 _at_relocate_start.free = free(used); 1315 } 1316 1317 void ZStatHeap::set_at_relocate_end(size_t capacity, 1318 size_t allocated, 1319 size_t reclaimed, 1320 size_t used, 1321 size_t used_high, 1322 size_t used_low) { 1323 _at_relocate_end.capacity = capacity; 1324 _at_relocate_end.capacity_high = capacity_high(); 1325 _at_relocate_end.capacity_low = capacity_low(); 1326 _at_relocate_end.reserve = reserve(used); 1327 _at_relocate_end.reserve_high = reserve(used_low); 1328 _at_relocate_end.reserve_low = reserve(used_high); 1329 _at_relocate_end.garbage = _at_mark_end.garbage - reclaimed; 1330 _at_relocate_end.allocated = allocated; 1331 _at_relocate_end.reclaimed = reclaimed; 1332 _at_relocate_end.used = used; 1333 _at_relocate_end.used_high = used_high; 1334 _at_relocate_end.used_low = used_low; 1335 _at_relocate_end.free = free(used); 1336 _at_relocate_end.free_high = free(used_low); 1337 _at_relocate_end.free_low = free(used_high); 1338 } 1339 1340 size_t ZStatHeap::max_capacity() { 1341 return _at_initialize.max_capacity; 1342 } 1343 1344 size_t ZStatHeap::used_at_mark_start() { 1345 return _at_mark_start.used; 1346 } 1347 1348 size_t ZStatHeap::used_at_relocate_end() { 1349 return _at_relocate_end.used; 1350 } 1351 1352 void ZStatHeap::print() { 1353 log_info(gc, heap)("Min Capacity: " 1354 ZSIZE_FMT, ZSIZE_ARGS(_at_initialize.min_capacity)); 1355 log_info(gc, heap)("Max Capacity: " 1356 ZSIZE_FMT, ZSIZE_ARGS(_at_initialize.max_capacity)); 1357 log_info(gc, heap)("Soft Max Capacity: " 1358 ZSIZE_FMT, ZSIZE_ARGS(_at_mark_start.soft_max_capacity)); 1359 1360 ZStatTablePrinter table(10, 18); 1361 log_info(gc, heap)("%s", table() 1362 .fill() 1363 .center("Mark Start") 1364 .center("Mark End") 1365 .center("Relocate Start") 1366 .center("Relocate End") 1367 .center("High") 1368 .center("Low") 1369 .end()); 1370 log_info(gc, heap)("%s", table() 1371 .right("Capacity:") 1372 .left(ZTABLE_ARGS(_at_mark_start.capacity)) 1373 .left(ZTABLE_ARGS(_at_mark_end.capacity)) 1374 .left(ZTABLE_ARGS(_at_relocate_start.capacity)) 1375 .left(ZTABLE_ARGS(_at_relocate_end.capacity)) 1376 .left(ZTABLE_ARGS(_at_relocate_end.capacity_high)) 1377 .left(ZTABLE_ARGS(_at_relocate_end.capacity_low)) 1378 .end()); 1379 log_info(gc, heap)("%s", table() 1380 .right("Reserve:") 1381 .left(ZTABLE_ARGS(_at_mark_start.reserve)) 1382 .left(ZTABLE_ARGS(_at_mark_end.reserve)) 1383 .left(ZTABLE_ARGS(_at_relocate_start.reserve)) 1384 .left(ZTABLE_ARGS(_at_relocate_end.reserve)) 1385 .left(ZTABLE_ARGS(_at_relocate_end.reserve_high)) 1386 .left(ZTABLE_ARGS(_at_relocate_end.reserve_low)) 1387 .end()); 1388 log_info(gc, heap)("%s", table() 1389 .right("Free:") 1390 .left(ZTABLE_ARGS(_at_mark_start.free)) 1391 .left(ZTABLE_ARGS(_at_mark_end.free)) 1392 .left(ZTABLE_ARGS(_at_relocate_start.free)) 1393 .left(ZTABLE_ARGS(_at_relocate_end.free)) 1394 .left(ZTABLE_ARGS(_at_relocate_end.free_high)) 1395 .left(ZTABLE_ARGS(_at_relocate_end.free_low)) 1396 .end()); 1397 log_info(gc, heap)("%s", table() 1398 .right("Used:") 1399 .left(ZTABLE_ARGS(_at_mark_start.used)) 1400 .left(ZTABLE_ARGS(_at_mark_end.used)) 1401 .left(ZTABLE_ARGS(_at_relocate_start.used)) 1402 .left(ZTABLE_ARGS(_at_relocate_end.used)) 1403 .left(ZTABLE_ARGS(_at_relocate_end.used_high)) 1404 .left(ZTABLE_ARGS(_at_relocate_end.used_low)) 1405 .end()); 1406 log_info(gc, heap)("%s", table() 1407 .right("Live:") 1408 .left(ZTABLE_ARGS_NA) 1409 .left(ZTABLE_ARGS(_at_mark_end.live)) 1410 .left(ZTABLE_ARGS(_at_mark_end.live /* Same as at mark end */)) 1411 .left(ZTABLE_ARGS(_at_mark_end.live /* Same as at mark end */)) 1412 .left(ZTABLE_ARGS_NA) 1413 .left(ZTABLE_ARGS_NA) 1414 .end()); 1415 log_info(gc, heap)("%s", table() 1416 .right("Allocated:") 1417 .left(ZTABLE_ARGS_NA) 1418 .left(ZTABLE_ARGS(_at_mark_end.allocated)) 1419 .left(ZTABLE_ARGS(_at_relocate_start.allocated)) 1420 .left(ZTABLE_ARGS(_at_relocate_end.allocated)) 1421 .left(ZTABLE_ARGS_NA) 1422 .left(ZTABLE_ARGS_NA) 1423 .end()); 1424 log_info(gc, heap)("%s", table() 1425 .right("Garbage:") 1426 .left(ZTABLE_ARGS_NA) 1427 .left(ZTABLE_ARGS(_at_mark_end.garbage)) 1428 .left(ZTABLE_ARGS(_at_relocate_start.garbage)) 1429 .left(ZTABLE_ARGS(_at_relocate_end.garbage)) 1430 .left(ZTABLE_ARGS_NA) 1431 .left(ZTABLE_ARGS_NA) 1432 .end()); 1433 log_info(gc, heap)("%s", table() 1434 .right("Reclaimed:") 1435 .left(ZTABLE_ARGS_NA) 1436 .left(ZTABLE_ARGS_NA) 1437 .left(ZTABLE_ARGS(_at_relocate_start.reclaimed)) 1438 .left(ZTABLE_ARGS(_at_relocate_end.reclaimed)) 1439 .left(ZTABLE_ARGS_NA) 1440 .left(ZTABLE_ARGS_NA) 1441 .end()); 1442 }