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