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