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