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