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(%.0lf%%)"
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 (%.0lf%%)", \
49 ((size) / M), (percent_of(size, ZStatHeap::max_capacity()))
50
51//
52// Stat sampler/counter data
53//
54struct 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
71struct ZStatCounterData {
72 uint64_t _counter;
73
74 ZStatCounterData() :
75 _counter(0) {}
76};
77
78//
79// Stat sampler history
80//
81template <size_t size>
82class ZStatSamplerHistoryInterval {
83private:
84 size_t _next;
85 ZStatSamplerData _samples[size];
86 ZStatSamplerData _accumulated;
87 ZStatSamplerData _total;
88
89public:
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
149class ZStatSamplerHistory : public CHeapObj<mtGC> {
150private:
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
160public:
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//
239void 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
257void 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
275void 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
293void 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
311void 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//
332uintptr_t ZStatValue::_base = 0;
333uint32_t ZStatValue::_cpu_offset = 0;
334
335ZStatValue::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
347template <typename T>
348T* 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
355void 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
365const char* ZStatValue::group() const {
366 return _group;
367}
368
369const char* ZStatValue::name() const {
370 return _name;
371}
372
373uint32_t ZStatValue::id() const {
374 return _id;
375}
376
377//
378// Stat iterable value
379//
380template <typename T> uint32_t ZStatIterableValue<T>::_count = 0;
381template <typename T> T* ZStatIterableValue<T>::_first = NULL;
382
383template <typename T>
384ZStatIterableValue<T>::ZStatIterableValue(const char* group,
385 const char* name,
386 uint32_t size) :
387 ZStatValue(group, name, _count++, size),
388 _next(insert()) {}
389
390template <typename T>
391T* 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//
413ZStatSampler::ZStatSampler(const char* group, const char* name, ZStatUnitPrinter printer) :
414 ZStatIterableValue<ZStatSampler>(group, name, sizeof(ZStatSamplerData)),
415 _printer(printer) {}
416
417ZStatSamplerData* ZStatSampler::get() const {
418 return get_cpu_local<ZStatSamplerData>(ZCPU::id());
419}
420
421ZStatSamplerData 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
442ZStatUnitPrinter ZStatSampler::printer() const {
443 return _printer;
444}
445
446//
447// Stat counter
448//
449ZStatCounter::ZStatCounter(const char* group, const char* name, ZStatUnitPrinter printer) :
450 ZStatIterableValue<ZStatCounter>(group, name, sizeof(ZStatCounterData)),
451 _sampler(group, name, printer) {}
452
453ZStatCounterData* ZStatCounter::get() const {
454 return get_cpu_local<ZStatCounterData>(ZCPU::id());
455}
456
457void 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//
472ZStatUnsampledCounter::ZStatUnsampledCounter(const char* name) :
473 ZStatIterableValue<ZStatUnsampledCounter>("Unsampled", name, sizeof(ZStatCounterData)) {}
474
475ZStatCounterData* ZStatUnsampledCounter::get() const {
476 return get_cpu_local<ZStatCounterData>(ZCPU::id());
477}
478
479ZStatCounterData 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//
494ZStatMMUPause::ZStatMMUPause() :
495 _start(0.0),
496 _end(0.0) {}
497
498ZStatMMUPause::ZStatMMUPause(const Ticks& start, const Ticks& end) :
499 _start(TimeHelper::counter_to_millis(start.value())),
500 _end(TimeHelper::counter_to_millis(end.value())) {}
501
502double ZStatMMUPause::end() const {
503 return _end;
504}
505
506double 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
519size_t ZStatMMU::_next = 0;
520size_t ZStatMMU::_npauses = 0;
521ZStatMMUPause ZStatMMU::_pauses[200];
522double ZStatMMU::_mmu_2ms = 100.0;
523double ZStatMMU::_mmu_5ms = 100.0;
524double ZStatMMU::_mmu_10ms = 100.0;
525double ZStatMMU::_mmu_20ms = 100.0;
526double ZStatMMU::_mmu_50ms = 100.0;
527double ZStatMMU::_mmu_100ms = 100.0;
528
529const ZStatMMUPause& ZStatMMU::pause(size_t index) {
530 return _pauses[(_next - index - 1) % ARRAY_SIZE(_pauses)];
531}
532
533double 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
554void 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
569void 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//
577ConcurrentGCTimer ZStatPhase::_timer;
578
579ZStatPhase::ZStatPhase(const char* group, const char* name) :
580 _sampler(group, name, ZStatUnitTime) {}
581
582void 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
595void 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
608ConcurrentGCTimer* ZStatPhase::timer() {
609 return &_timer;
610}
611
612const char* ZStatPhase::name() const {
613 return _sampler.name();
614}
615
616ZStatPhaseCycle::ZStatPhaseCycle(const char* name) :
617 ZStatPhase("Collector", name) {}
618
619void 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
631void 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
657Tickspan ZStatPhasePause::_max;
658
659ZStatPhasePause::ZStatPhasePause(const char* name) :
660 ZStatPhase("Phase", name) {}
661
662const Tickspan& ZStatPhasePause::max() {
663 return _max;
664}
665
666void 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
673void 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
691ZStatPhaseConcurrent::ZStatPhaseConcurrent(const char* name) :
692 ZStatPhase("Phase", name) {}
693
694void 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
701void 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
711ZStatSubPhase::ZStatSubPhase(const char* name) :
712 ZStatPhase("Subphase", name) {}
713
714void ZStatSubPhase::register_start(const Ticks& start) const {
715 LogTarget(Debug, gc, phases, start) log;
716 log_start(log, true /* thread */);
717}
718
719void 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
729ZStatCriticalPhase::ZStatCriticalPhase(const char* name, bool verbose) :
730 ZStatPhase("Critical", name),
731 _counter("Critical", name, ZStatUnitOpsPerSecond),
732 _verbose(verbose) {}
733
734void ZStatCriticalPhase::register_start(const Ticks& start) const {
735 LogTarget(Debug, gc, start) log;
736 log_start(log, true /* thread */);
737}
738
739void 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//
763void 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
791void 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
800void 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//
808const ZStatUnsampledCounter ZStatAllocRate::_counter("Allocation Rate");
809TruncatedSeq ZStatAllocRate::_rate(ZStatAllocRate::sample_window_sec * ZStatAllocRate::sample_hz);
810TruncatedSeq ZStatAllocRate::_rate_avg(ZStatAllocRate::sample_window_sec * ZStatAllocRate::sample_hz);
811
812const ZStatUnsampledCounter& ZStatAllocRate::counter() {
813 return _counter;
814}
815
816uint64_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
826double ZStatAllocRate::avg() {
827 return _rate.avg();
828}
829
830double ZStatAllocRate::avg_sd() {
831 return _rate_avg.sd();
832}
833
834//
835// Stat thread
836//
837ZStat::ZStat() :
838 _metronome(sample_hz) {
839 set_name("ZStat");
840 create_and_start();
841}
842
843void 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
856bool 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
869void 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
884void 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
899void ZStat::stop_service() {
900 _metronome.stop();
901}
902
903//
904// Stat table
905//
906class ZStatTablePrinter {
907private:
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
914public:
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
1019public:
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//
1032uint64_t ZStatCycle::_ncycles = 0;
1033Ticks ZStatCycle::_start_of_last;
1034Ticks ZStatCycle::_end_of_last;
1035NumberSeq ZStatCycle::_normalized_duration(0.3 /* alpha */);
1036
1037void ZStatCycle::at_start() {
1038 _start_of_last = Ticks::now();
1039}
1040
1041void 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
1053uint64_t ZStatCycle::ncycles() {
1054 return _ncycles;
1055}
1056
1057const AbsSeq& ZStatCycle::normalized_duration() {
1058 return _normalized_duration;
1059}
1060
1061double 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//
1075void 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//
1084size_t ZStatMark::_nstripes;
1085size_t ZStatMark::_nproactiveflush;
1086size_t ZStatMark::_nterminateflush;
1087size_t ZStatMark::_ntrycomplete;
1088size_t ZStatMark::_ncontinue;
1089
1090void ZStatMark::set_at_mark_start(size_t nstripes) {
1091 _nstripes = nstripes;
1092}
1093
1094void 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
1104void 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//
1121size_t ZStatRelocation::_relocating;
1122bool ZStatRelocation::_success;
1123
1124void ZStatRelocation::set_at_select_relocation_set(size_t relocating) {
1125 _relocating = relocating;
1126}
1127
1128void ZStatRelocation::set_at_relocate_end(bool success) {
1129 _success = success;
1130}
1131
1132void 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//
1143void 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//
1152void 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//
1165ZStatReferences::ZCount ZStatReferences::_soft;
1166ZStatReferences::ZCount ZStatReferences::_weak;
1167ZStatReferences::ZCount ZStatReferences::_final;
1168ZStatReferences::ZCount ZStatReferences::_phantom;
1169
1170void 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
1176void ZStatReferences::set_soft(size_t encountered, size_t discovered, size_t enqueued) {
1177 set(&_soft, encountered, discovered, enqueued);
1178}
1179
1180void ZStatReferences::set_weak(size_t encountered, size_t discovered, size_t enqueued) {
1181 set(&_weak, encountered, discovered, enqueued);
1182}
1183
1184void ZStatReferences::set_final(size_t encountered, size_t discovered, size_t enqueued) {
1185 set(&_final, encountered, discovered, enqueued);
1186}
1187
1188void ZStatReferences::set_phantom(size_t encountered, size_t discovered, size_t enqueued) {
1189 set(&_phantom, encountered, discovered, enqueued);
1190}
1191
1192void 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
1203void 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//
1213ZStatHeap::ZAtInitialize ZStatHeap::_at_initialize;
1214ZStatHeap::ZAtMarkStart ZStatHeap::_at_mark_start;
1215ZStatHeap::ZAtMarkEnd ZStatHeap::_at_mark_end;
1216ZStatHeap::ZAtRelocateStart ZStatHeap::_at_relocate_start;
1217ZStatHeap::ZAtRelocateEnd ZStatHeap::_at_relocate_end;
1218
1219size_t ZStatHeap::available(size_t used) {
1220 return _at_initialize.max_capacity - used;
1221}
1222
1223size_t ZStatHeap::reserve(size_t used) {
1224 return MIN2(_at_initialize.max_reserve, available(used));
1225}
1226
1227size_t ZStatHeap::free(size_t used) {
1228 return available(used) - reserve(used);
1229}
1230
1231void 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
1239void 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
1249void 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
1259void 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
1269void 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
1279void 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
1302size_t ZStatHeap::max_capacity() {
1303 return _at_initialize.max_capacity;
1304}
1305
1306size_t ZStatHeap::used_at_mark_start() {
1307 return _at_mark_start.used;
1308}
1309
1310size_t ZStatHeap::used_at_relocate_end() {
1311 return _at_relocate_end.used;
1312}
1313
1314void 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}
1405