0ad50c2b5c
Reviewed-by: rehn, dholmes
1427 lines
43 KiB
C++
1427 lines
43 KiB
C++
/*
|
|
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
#include "precompiled.hpp"
|
|
#include "gc/z/zCollectedHeap.hpp"
|
|
#include "gc/z/zCPU.inline.hpp"
|
|
#include "gc/z/zGlobals.hpp"
|
|
#include "gc/z/zHeap.inline.hpp"
|
|
#include "gc/z/zLargePages.inline.hpp"
|
|
#include "gc/z/zNMethodTable.hpp"
|
|
#include "gc/z/zNUMA.hpp"
|
|
#include "gc/z/zStat.hpp"
|
|
#include "gc/z/zTracer.inline.hpp"
|
|
#include "gc/z/zUtils.hpp"
|
|
#include "memory/resourceArea.hpp"
|
|
#include "runtime/atomic.hpp"
|
|
#include "runtime/os.hpp"
|
|
#include "runtime/timer.hpp"
|
|
#include "utilities/align.hpp"
|
|
#include "utilities/compilerWarnings.hpp"
|
|
#include "utilities/debug.hpp"
|
|
#include "utilities/ticks.hpp"
|
|
|
|
#define ZSIZE_FMT SIZE_FORMAT "M(%.0f%%)"
|
|
#define ZSIZE_ARGS(size) ((size) / M), (percent_of(size, ZStatHeap::max_capacity()))
|
|
|
|
#define ZTABLE_ARGS_NA "%9s", "-"
|
|
#define ZTABLE_ARGS(size) SIZE_FORMAT_W(8) "M (%.0f%%)", \
|
|
((size) / M), (percent_of(size, ZStatHeap::max_capacity()))
|
|
|
|
//
|
|
// Stat sampler/counter data
|
|
//
|
|
struct ZStatSamplerData {
|
|
uint64_t _nsamples;
|
|
uint64_t _sum;
|
|
uint64_t _max;
|
|
|
|
ZStatSamplerData() :
|
|
_nsamples(0),
|
|
_sum(0),
|
|
_max(0) {}
|
|
|
|
void add(const ZStatSamplerData& new_sample) {
|
|
_nsamples += new_sample._nsamples;
|
|
_sum += new_sample._sum;
|
|
_max = MAX2(_max, new_sample._max);
|
|
}
|
|
};
|
|
|
|
struct ZStatCounterData {
|
|
uint64_t _counter;
|
|
|
|
ZStatCounterData() :
|
|
_counter(0) {}
|
|
};
|
|
|
|
//
|
|
// Stat sampler history
|
|
//
|
|
template <size_t size>
|
|
class ZStatSamplerHistoryInterval {
|
|
private:
|
|
size_t _next;
|
|
ZStatSamplerData _samples[size];
|
|
ZStatSamplerData _accumulated;
|
|
ZStatSamplerData _total;
|
|
|
|
public:
|
|
ZStatSamplerHistoryInterval() :
|
|
_next(0),
|
|
_samples(),
|
|
_accumulated(),
|
|
_total() {}
|
|
|
|
bool add(const ZStatSamplerData& new_sample) {
|
|
// Insert sample
|
|
const ZStatSamplerData old_sample = _samples[_next];
|
|
_samples[_next] = new_sample;
|
|
|
|
// Adjust accumulated
|
|
_accumulated._nsamples += new_sample._nsamples;
|
|
_accumulated._sum += new_sample._sum;
|
|
_accumulated._max = MAX2(_accumulated._max, new_sample._max);
|
|
|
|
// Adjust total
|
|
_total._nsamples -= old_sample._nsamples;
|
|
_total._sum -= old_sample._sum;
|
|
_total._nsamples += new_sample._nsamples;
|
|
_total._sum += new_sample._sum;
|
|
if (_total._max < new_sample._max) {
|
|
// Found new max
|
|
_total._max = new_sample._max;
|
|
} else if (_total._max == old_sample._max) {
|
|
// Removed old max, reset and find new max
|
|
_total._max = 0;
|
|
for (size_t i = 0; i < size; i++) {
|
|
if (_total._max < _samples[i]._max) {
|
|
_total._max = _samples[i]._max;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Adjust next
|
|
if (++_next == size) {
|
|
_next = 0;
|
|
|
|
// Clear accumulated
|
|
const ZStatSamplerData zero;
|
|
_accumulated = zero;
|
|
|
|
// Became full
|
|
return true;
|
|
}
|
|
|
|
// Not yet full
|
|
return false;
|
|
}
|
|
|
|
const ZStatSamplerData& total() const {
|
|
return _total;
|
|
}
|
|
|
|
const ZStatSamplerData& accumulated() const {
|
|
return _accumulated;
|
|
}
|
|
};
|
|
|
|
class ZStatSamplerHistory : public CHeapObj<mtGC> {
|
|
private:
|
|
ZStatSamplerHistoryInterval<10> _10seconds;
|
|
ZStatSamplerHistoryInterval<60> _10minutes;
|
|
ZStatSamplerHistoryInterval<60> _10hours;
|
|
ZStatSamplerData _total;
|
|
|
|
uint64_t avg(uint64_t sum, uint64_t nsamples) const {
|
|
return (nsamples > 0) ? sum / nsamples : 0;
|
|
}
|
|
|
|
public:
|
|
ZStatSamplerHistory() :
|
|
_10seconds(),
|
|
_10minutes(),
|
|
_10hours(),
|
|
_total() {}
|
|
|
|
void add(const ZStatSamplerData& new_sample) {
|
|
if (_10seconds.add(new_sample)) {
|
|
if (_10minutes.add(_10seconds.total())) {
|
|
if (_10hours.add(_10minutes.total())) {
|
|
_total.add(_10hours.total());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint64_t avg_10_seconds() const {
|
|
const uint64_t sum = _10seconds.total()._sum;
|
|
const uint64_t nsamples = _10seconds.total()._nsamples;
|
|
return avg(sum, nsamples);
|
|
}
|
|
|
|
uint64_t avg_10_minutes() const {
|
|
const uint64_t sum = _10seconds.accumulated()._sum +
|
|
_10minutes.total()._sum;
|
|
const uint64_t nsamples = _10seconds.accumulated()._nsamples +
|
|
_10minutes.total()._nsamples;
|
|
return avg(sum, nsamples);
|
|
}
|
|
|
|
uint64_t avg_10_hours() const {
|
|
const uint64_t sum = _10seconds.accumulated()._sum +
|
|
_10minutes.accumulated()._sum +
|
|
_10hours.total()._sum;
|
|
const uint64_t nsamples = _10seconds.accumulated()._nsamples +
|
|
_10minutes.accumulated()._nsamples +
|
|
_10hours.total()._nsamples;
|
|
return avg(sum, nsamples);
|
|
}
|
|
|
|
uint64_t avg_total() const {
|
|
const uint64_t sum = _10seconds.accumulated()._sum +
|
|
_10minutes.accumulated()._sum +
|
|
_10hours.accumulated()._sum +
|
|
_total._sum;
|
|
const uint64_t nsamples = _10seconds.accumulated()._nsamples +
|
|
_10minutes.accumulated()._nsamples +
|
|
_10hours.accumulated()._nsamples +
|
|
_total._nsamples;
|
|
return avg(sum, nsamples);
|
|
}
|
|
|
|
uint64_t max_10_seconds() const {
|
|
return _10seconds.total()._max;
|
|
}
|
|
|
|
uint64_t max_10_minutes() const {
|
|
return MAX2(_10seconds.accumulated()._max,
|
|
_10minutes.total()._max);
|
|
}
|
|
|
|
uint64_t max_10_hours() const {
|
|
return MAX3(_10seconds.accumulated()._max,
|
|
_10minutes.accumulated()._max,
|
|
_10hours.total()._max);
|
|
}
|
|
|
|
uint64_t max_total() const {
|
|
return MAX4(_10seconds.accumulated()._max,
|
|
_10minutes.accumulated()._max,
|
|
_10hours.accumulated()._max,
|
|
_total._max);
|
|
}
|
|
};
|
|
|
|
//
|
|
// Stat unit printers
|
|
//
|
|
void ZStatUnitTime(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) {
|
|
log.print(" %10s: %-41s "
|
|
"%9.3f / %-9.3f "
|
|
"%9.3f / %-9.3f "
|
|
"%9.3f / %-9.3f "
|
|
"%9.3f / %-9.3f ms",
|
|
sampler.group(),
|
|
sampler.name(),
|
|
TimeHelper::counter_to_millis(history.avg_10_seconds()),
|
|
TimeHelper::counter_to_millis(history.max_10_seconds()),
|
|
TimeHelper::counter_to_millis(history.avg_10_minutes()),
|
|
TimeHelper::counter_to_millis(history.max_10_minutes()),
|
|
TimeHelper::counter_to_millis(history.avg_10_hours()),
|
|
TimeHelper::counter_to_millis(history.max_10_hours()),
|
|
TimeHelper::counter_to_millis(history.avg_total()),
|
|
TimeHelper::counter_to_millis(history.max_total()));
|
|
}
|
|
|
|
void ZStatUnitBytes(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) {
|
|
log.print(" %10s: %-41s "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " MB",
|
|
sampler.group(),
|
|
sampler.name(),
|
|
history.avg_10_seconds() / M,
|
|
history.max_10_seconds() / M,
|
|
history.avg_10_minutes() / M,
|
|
history.max_10_minutes() / M,
|
|
history.avg_10_hours() / M,
|
|
history.max_10_hours() / M,
|
|
history.avg_total() / M,
|
|
history.max_total() / M);
|
|
}
|
|
|
|
void ZStatUnitThreads(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) {
|
|
log.print(" %10s: %-41s "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " threads",
|
|
sampler.group(),
|
|
sampler.name(),
|
|
history.avg_10_seconds(),
|
|
history.max_10_seconds(),
|
|
history.avg_10_minutes(),
|
|
history.max_10_minutes(),
|
|
history.avg_10_hours(),
|
|
history.max_10_hours(),
|
|
history.avg_total(),
|
|
history.max_total());
|
|
}
|
|
|
|
void ZStatUnitBytesPerSecond(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) {
|
|
log.print(" %10s: %-41s "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " MB/s",
|
|
sampler.group(),
|
|
sampler.name(),
|
|
history.avg_10_seconds() / M,
|
|
history.max_10_seconds() / M,
|
|
history.avg_10_minutes() / M,
|
|
history.max_10_minutes() / M,
|
|
history.avg_10_hours() / M,
|
|
history.max_10_hours() / M,
|
|
history.avg_total() / M,
|
|
history.max_total() / M);
|
|
}
|
|
|
|
void ZStatUnitOpsPerSecond(LogTargetHandle log, const ZStatSampler& sampler, const ZStatSamplerHistory& history) {
|
|
log.print(" %10s: %-41s "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " "
|
|
UINT64_FORMAT_W(9) " / " UINT64_FORMAT_W(-9) " ops/s",
|
|
sampler.group(),
|
|
sampler.name(),
|
|
history.avg_10_seconds(),
|
|
history.max_10_seconds(),
|
|
history.avg_10_minutes(),
|
|
history.max_10_minutes(),
|
|
history.avg_10_hours(),
|
|
history.max_10_hours(),
|
|
history.avg_total(),
|
|
history.max_total());
|
|
}
|
|
|
|
//
|
|
// Stat value
|
|
//
|
|
uintptr_t ZStatValue::_base = 0;
|
|
uint32_t ZStatValue::_cpu_offset = 0;
|
|
|
|
ZStatValue::ZStatValue(const char* group,
|
|
const char* name,
|
|
uint32_t id,
|
|
uint32_t size) :
|
|
_group(group),
|
|
_name(name),
|
|
_id(id),
|
|
_offset(_cpu_offset) {
|
|
assert(_base == 0, "Already initialized");
|
|
_cpu_offset += size;
|
|
}
|
|
|
|
template <typename T>
|
|
T* ZStatValue::get_cpu_local(uint32_t cpu) const {
|
|
assert(_base != 0, "Not initialized");
|
|
const uintptr_t cpu_base = _base + (_cpu_offset * cpu);
|
|
const uintptr_t value_addr = cpu_base + _offset;
|
|
return (T*)value_addr;
|
|
}
|
|
|
|
void ZStatValue::initialize() {
|
|
// Finalize and align CPU offset
|
|
_cpu_offset = align_up(_cpu_offset, (uint32_t)ZCacheLineSize);
|
|
|
|
// Allocation aligned memory
|
|
const size_t size = _cpu_offset * ZCPU::count();
|
|
_base = ZUtils::alloc_aligned(ZCacheLineSize, size);
|
|
}
|
|
|
|
const char* ZStatValue::group() const {
|
|
return _group;
|
|
}
|
|
|
|
const char* ZStatValue::name() const {
|
|
return _name;
|
|
}
|
|
|
|
uint32_t ZStatValue::id() const {
|
|
return _id;
|
|
}
|
|
|
|
//
|
|
// Stat iterable value
|
|
//
|
|
template <typename T> uint32_t ZStatIterableValue<T>::_count = 0;
|
|
template <typename T> T* ZStatIterableValue<T>::_first = NULL;
|
|
|
|
template <typename T>
|
|
ZStatIterableValue<T>::ZStatIterableValue(const char* group,
|
|
const char* name,
|
|
uint32_t size) :
|
|
ZStatValue(group, name, _count++, size),
|
|
_next(insert()) {}
|
|
|
|
template <typename T>
|
|
T* ZStatIterableValue<T>::insert() const {
|
|
T** current = &_first;
|
|
|
|
while (*current != NULL) {
|
|
// First sort by group, then by name
|
|
const int group_cmp = strcmp((*current)->group(), group());
|
|
const int name_cmp = strcmp((*current)->name(), name());
|
|
if ((group_cmp > 0) || (group_cmp == 0 && name_cmp > 0)) {
|
|
break;
|
|
}
|
|
|
|
current = &(*current)->_next;
|
|
}
|
|
|
|
T* const next = *current;
|
|
*current = (T*)this;
|
|
return next;
|
|
}
|
|
|
|
//
|
|
// Stat sampler
|
|
//
|
|
ZStatSampler::ZStatSampler(const char* group, const char* name, ZStatUnitPrinter printer) :
|
|
ZStatIterableValue<ZStatSampler>(group, name, sizeof(ZStatSamplerData)),
|
|
_printer(printer) {}
|
|
|
|
ZStatSamplerData* ZStatSampler::get() const {
|
|
return get_cpu_local<ZStatSamplerData>(ZCPU::id());
|
|
}
|
|
|
|
ZStatSamplerData ZStatSampler::collect_and_reset() const {
|
|
ZStatSamplerData all;
|
|
|
|
const uint32_t ncpus = ZCPU::count();
|
|
for (uint32_t i = 0; i < ncpus; i++) {
|
|
ZStatSamplerData* const cpu_data = get_cpu_local<ZStatSamplerData>(i);
|
|
if (cpu_data->_nsamples > 0) {
|
|
const uint64_t nsamples = Atomic::xchg(&cpu_data->_nsamples, (uint64_t)0);
|
|
const uint64_t sum = Atomic::xchg(&cpu_data->_sum, (uint64_t)0);
|
|
const uint64_t max = Atomic::xchg(&cpu_data->_max, (uint64_t)0);
|
|
all._nsamples += nsamples;
|
|
all._sum += sum;
|
|
if (all._max < max) {
|
|
all._max = max;
|
|
}
|
|
}
|
|
}
|
|
|
|
return all;
|
|
}
|
|
|
|
ZStatUnitPrinter ZStatSampler::printer() const {
|
|
return _printer;
|
|
}
|
|
|
|
//
|
|
// Stat counter
|
|
//
|
|
ZStatCounter::ZStatCounter(const char* group, const char* name, ZStatUnitPrinter printer) :
|
|
ZStatIterableValue<ZStatCounter>(group, name, sizeof(ZStatCounterData)),
|
|
_sampler(group, name, printer) {}
|
|
|
|
ZStatCounterData* ZStatCounter::get() const {
|
|
return get_cpu_local<ZStatCounterData>(ZCPU::id());
|
|
}
|
|
|
|
void ZStatCounter::sample_and_reset() const {
|
|
uint64_t counter = 0;
|
|
|
|
const uint32_t ncpus = ZCPU::count();
|
|
for (uint32_t i = 0; i < ncpus; i++) {
|
|
ZStatCounterData* const cpu_data = get_cpu_local<ZStatCounterData>(i);
|
|
counter += Atomic::xchg(&cpu_data->_counter, (uint64_t)0);
|
|
}
|
|
|
|
ZStatSample(_sampler, counter);
|
|
}
|
|
|
|
//
|
|
// Stat unsampled counter
|
|
//
|
|
ZStatUnsampledCounter::ZStatUnsampledCounter(const char* name) :
|
|
ZStatIterableValue<ZStatUnsampledCounter>("Unsampled", name, sizeof(ZStatCounterData)) {}
|
|
|
|
ZStatCounterData* ZStatUnsampledCounter::get() const {
|
|
return get_cpu_local<ZStatCounterData>(ZCPU::id());
|
|
}
|
|
|
|
ZStatCounterData ZStatUnsampledCounter::collect_and_reset() const {
|
|
ZStatCounterData all;
|
|
|
|
const uint32_t ncpus = ZCPU::count();
|
|
for (uint32_t i = 0; i < ncpus; i++) {
|
|
ZStatCounterData* const cpu_data = get_cpu_local<ZStatCounterData>(i);
|
|
all._counter += Atomic::xchg(&cpu_data->_counter, (uint64_t)0);
|
|
}
|
|
|
|
return all;
|
|
}
|
|
|
|
//
|
|
// Stat MMU (Minimum Mutator Utilization)
|
|
//
|
|
ZStatMMUPause::ZStatMMUPause() :
|
|
_start(0.0),
|
|
_end(0.0) {}
|
|
|
|
ZStatMMUPause::ZStatMMUPause(const Ticks& start, const Ticks& end) :
|
|
_start(TimeHelper::counter_to_millis(start.value())),
|
|
_end(TimeHelper::counter_to_millis(end.value())) {}
|
|
|
|
double ZStatMMUPause::end() const {
|
|
return _end;
|
|
}
|
|
|
|
double ZStatMMUPause::overlap(double start, double end) const {
|
|
const double start_max = MAX2(start, _start);
|
|
const double end_min = MIN2(end, _end);
|
|
|
|
if (end_min > start_max) {
|
|
// Overlap found
|
|
return end_min - start_max;
|
|
}
|
|
|
|
// No overlap
|
|
return 0.0;
|
|
}
|
|
|
|
size_t ZStatMMU::_next = 0;
|
|
size_t ZStatMMU::_npauses = 0;
|
|
ZStatMMUPause ZStatMMU::_pauses[200];
|
|
double ZStatMMU::_mmu_2ms = 100.0;
|
|
double ZStatMMU::_mmu_5ms = 100.0;
|
|
double ZStatMMU::_mmu_10ms = 100.0;
|
|
double ZStatMMU::_mmu_20ms = 100.0;
|
|
double ZStatMMU::_mmu_50ms = 100.0;
|
|
double ZStatMMU::_mmu_100ms = 100.0;
|
|
|
|
const ZStatMMUPause& ZStatMMU::pause(size_t index) {
|
|
return _pauses[(_next - index - 1) % ARRAY_SIZE(_pauses)];
|
|
}
|
|
|
|
double ZStatMMU::calculate_mmu(double time_slice) {
|
|
const double end = pause(0).end();
|
|
const double start = end - time_slice;
|
|
double time_paused = 0.0;
|
|
|
|
// Find all overlapping pauses
|
|
for (size_t i = 0; i < _npauses; i++) {
|
|
const double overlap = pause(i).overlap(start, end);
|
|
if (overlap == 0.0) {
|
|
// No overlap
|
|
break;
|
|
}
|
|
|
|
time_paused += overlap;
|
|
}
|
|
|
|
// Calculate MMU
|
|
const double time_mutator = time_slice - time_paused;
|
|
return percent_of(time_mutator, time_slice);
|
|
}
|
|
|
|
void ZStatMMU::register_pause(const Ticks& start, const Ticks& end) {
|
|
// Add pause
|
|
const size_t index = _next++ % ARRAY_SIZE(_pauses);
|
|
_pauses[index] = ZStatMMUPause(start, end);
|
|
_npauses = MIN2(_npauses + 1, ARRAY_SIZE(_pauses));
|
|
|
|
// Recalculate MMUs
|
|
_mmu_2ms = MIN2(_mmu_2ms, calculate_mmu(2));
|
|
_mmu_5ms = MIN2(_mmu_5ms, calculate_mmu(5));
|
|
_mmu_10ms = MIN2(_mmu_10ms, calculate_mmu(10));
|
|
_mmu_20ms = MIN2(_mmu_20ms, calculate_mmu(20));
|
|
_mmu_50ms = MIN2(_mmu_50ms, calculate_mmu(50));
|
|
_mmu_100ms = MIN2(_mmu_100ms, calculate_mmu(100));
|
|
}
|
|
|
|
void ZStatMMU::print() {
|
|
log_info(gc, mmu)("MMU: 2ms/%.1f%%, 5ms/%.1f%%, 10ms/%.1f%%, 20ms/%.1f%%, 50ms/%.1f%%, 100ms/%.1f%%",
|
|
_mmu_2ms, _mmu_5ms, _mmu_10ms, _mmu_20ms, _mmu_50ms, _mmu_100ms);
|
|
}
|
|
|
|
//
|
|
// Stat phases
|
|
//
|
|
ConcurrentGCTimer ZStatPhase::_timer;
|
|
|
|
ZStatPhase::ZStatPhase(const char* group, const char* name) :
|
|
_sampler(group, name, ZStatUnitTime) {}
|
|
|
|
void ZStatPhase::log_start(LogTargetHandle log, bool thread) const {
|
|
if (!log.is_enabled()) {
|
|
return;
|
|
}
|
|
|
|
if (thread) {
|
|
ResourceMark rm;
|
|
log.print("%s (%s)", name(), Thread::current()->name());
|
|
} else {
|
|
log.print("%s", name());
|
|
}
|
|
}
|
|
|
|
void ZStatPhase::log_end(LogTargetHandle log, const Tickspan& duration, bool thread) const {
|
|
if (!log.is_enabled()) {
|
|
return;
|
|
}
|
|
|
|
if (thread) {
|
|
ResourceMark rm;
|
|
log.print("%s (%s) %.3fms", name(), Thread::current()->name(), TimeHelper::counter_to_millis(duration.value()));
|
|
} else {
|
|
log.print("%s %.3fms", name(), TimeHelper::counter_to_millis(duration.value()));
|
|
}
|
|
}
|
|
|
|
ConcurrentGCTimer* ZStatPhase::timer() {
|
|
return &_timer;
|
|
}
|
|
|
|
const char* ZStatPhase::name() const {
|
|
return _sampler.name();
|
|
}
|
|
|
|
ZStatPhaseCycle::ZStatPhaseCycle(const char* name) :
|
|
ZStatPhase("Collector", name) {}
|
|
|
|
void ZStatPhaseCycle::register_start(const Ticks& start) const {
|
|
timer()->register_gc_start(start);
|
|
|
|
ZTracer::tracer()->report_gc_start(ZCollectedHeap::heap()->gc_cause(), start);
|
|
|
|
ZCollectedHeap::heap()->print_heap_before_gc();
|
|
ZCollectedHeap::heap()->trace_heap_before_gc(ZTracer::tracer());
|
|
|
|
log_info(gc, start)("Garbage Collection (%s)",
|
|
GCCause::to_string(ZCollectedHeap::heap()->gc_cause()));
|
|
}
|
|
|
|
void ZStatPhaseCycle::register_end(const Ticks& start, const Ticks& end) const {
|
|
timer()->register_gc_end(end);
|
|
|
|
ZCollectedHeap::heap()->print_heap_after_gc();
|
|
ZCollectedHeap::heap()->trace_heap_after_gc(ZTracer::tracer());
|
|
|
|
ZTracer::tracer()->report_gc_end(end, timer()->time_partitions());
|
|
|
|
const Tickspan duration = end - start;
|
|
ZStatSample(_sampler, duration.value());
|
|
|
|
ZStatLoad::print();
|
|
ZStatMMU::print();
|
|
ZStatMark::print();
|
|
ZStatRelocation::print();
|
|
ZStatNMethods::print();
|
|
ZStatMetaspace::print();
|
|
ZStatReferences::print();
|
|
ZStatHeap::print();
|
|
|
|
log_info(gc)("Garbage Collection (%s) " ZSIZE_FMT "->" ZSIZE_FMT,
|
|
GCCause::to_string(ZCollectedHeap::heap()->gc_cause()),
|
|
ZSIZE_ARGS(ZStatHeap::used_at_mark_start()),
|
|
ZSIZE_ARGS(ZStatHeap::used_at_relocate_end()));
|
|
}
|
|
|
|
Tickspan ZStatPhasePause::_max;
|
|
|
|
ZStatPhasePause::ZStatPhasePause(const char* name) :
|
|
ZStatPhase("Phase", name) {}
|
|
|
|
const Tickspan& ZStatPhasePause::max() {
|
|
return _max;
|
|
}
|
|
|
|
void ZStatPhasePause::register_start(const Ticks& start) const {
|
|
timer()->register_gc_pause_start(name(), start);
|
|
|
|
LogTarget(Debug, gc, phases, start) log;
|
|
log_start(log);
|
|
}
|
|
|
|
void ZStatPhasePause::register_end(const Ticks& start, const Ticks& end) const {
|
|
timer()->register_gc_pause_end(end);
|
|
|
|
const Tickspan duration = end - start;
|
|
ZStatSample(_sampler, duration.value());
|
|
|
|
// Track max pause time
|
|
if (_max < duration) {
|
|
_max = duration;
|
|
}
|
|
|
|
// Track minimum mutator utilization
|
|
ZStatMMU::register_pause(start, end);
|
|
|
|
LogTarget(Info, gc, phases) log;
|
|
log_end(log, duration);
|
|
}
|
|
|
|
ZStatPhaseConcurrent::ZStatPhaseConcurrent(const char* name) :
|
|
ZStatPhase("Phase", name) {}
|
|
|
|
void ZStatPhaseConcurrent::register_start(const Ticks& start) const {
|
|
timer()->register_gc_concurrent_start(name(), start);
|
|
|
|
LogTarget(Debug, gc, phases, start) log;
|
|
log_start(log);
|
|
}
|
|
|
|
void ZStatPhaseConcurrent::register_end(const Ticks& start, const Ticks& end) const {
|
|
timer()->register_gc_concurrent_end(end);
|
|
|
|
const Tickspan duration = end - start;
|
|
ZStatSample(_sampler, duration.value());
|
|
|
|
LogTarget(Info, gc, phases) log;
|
|
log_end(log, duration);
|
|
}
|
|
|
|
ZStatSubPhase::ZStatSubPhase(const char* name) :
|
|
ZStatPhase("Subphase", name) {}
|
|
|
|
void ZStatSubPhase::register_start(const Ticks& start) const {
|
|
LogTarget(Debug, gc, phases, start) log;
|
|
log_start(log, true /* thread */);
|
|
}
|
|
|
|
void ZStatSubPhase::register_end(const Ticks& start, const Ticks& end) const {
|
|
ZTracer::tracer()->report_thread_phase(name(), start, end);
|
|
|
|
const Tickspan duration = end - start;
|
|
ZStatSample(_sampler, duration.value());
|
|
|
|
LogTarget(Debug, gc, phases) log;
|
|
log_end(log, duration, true /* thread */);
|
|
}
|
|
|
|
ZStatCriticalPhase::ZStatCriticalPhase(const char* name, bool verbose) :
|
|
ZStatPhase("Critical", name),
|
|
_counter("Critical", name, ZStatUnitOpsPerSecond),
|
|
_verbose(verbose) {}
|
|
|
|
void ZStatCriticalPhase::register_start(const Ticks& start) const {
|
|
LogTarget(Debug, gc, start) log;
|
|
log_start(log, true /* thread */);
|
|
}
|
|
|
|
void ZStatCriticalPhase::register_end(const Ticks& start, const Ticks& end) const {
|
|
ZTracer::tracer()->report_thread_phase(name(), start, end);
|
|
|
|
const Tickspan duration = end - start;
|
|
ZStatSample(_sampler, duration.value());
|
|
ZStatInc(_counter);
|
|
|
|
if (_verbose) {
|
|
LogTarget(Info, gc) log;
|
|
log_end(log, duration, true /* thread */);
|
|
} else {
|
|
LogTarget(Debug, gc) log;
|
|
log_end(log, duration, true /* thread */);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stat timer
|
|
//
|
|
THREAD_LOCAL uint32_t ZStatTimerDisable::_active = 0;
|
|
|
|
//
|
|
// Stat sample/inc
|
|
//
|
|
void ZStatSample(const ZStatSampler& sampler, uint64_t value) {
|
|
ZStatSamplerData* const cpu_data = sampler.get();
|
|
Atomic::add(&cpu_data->_nsamples, 1u);
|
|
Atomic::add(&cpu_data->_sum, value);
|
|
|
|
uint64_t max = cpu_data->_max;
|
|
for (;;) {
|
|
if (max >= value) {
|
|
// Not max
|
|
break;
|
|
}
|
|
|
|
const uint64_t new_max = value;
|
|
const uint64_t prev_max = Atomic::cmpxchg(&cpu_data->_max, max, new_max);
|
|
if (prev_max == max) {
|
|
// Success
|
|
break;
|
|
}
|
|
|
|
// Retry
|
|
max = prev_max;
|
|
}
|
|
|
|
ZTracer::tracer()->report_stat_sampler(sampler, value);
|
|
}
|
|
|
|
void ZStatInc(const ZStatCounter& counter, uint64_t increment) {
|
|
ZStatCounterData* const cpu_data = counter.get();
|
|
const uint64_t value = Atomic::add(&cpu_data->_counter, increment);
|
|
|
|
ZTracer::tracer()->report_stat_counter(counter, increment, value);
|
|
}
|
|
|
|
void ZStatInc(const ZStatUnsampledCounter& counter, uint64_t increment) {
|
|
ZStatCounterData* const cpu_data = counter.get();
|
|
Atomic::add(&cpu_data->_counter, increment);
|
|
}
|
|
|
|
//
|
|
// Stat allocation rate
|
|
//
|
|
const ZStatUnsampledCounter ZStatAllocRate::_counter("Allocation Rate");
|
|
TruncatedSeq ZStatAllocRate::_rate(ZStatAllocRate::sample_window_sec * ZStatAllocRate::sample_hz);
|
|
TruncatedSeq ZStatAllocRate::_rate_avg(ZStatAllocRate::sample_window_sec * ZStatAllocRate::sample_hz);
|
|
|
|
const ZStatUnsampledCounter& ZStatAllocRate::counter() {
|
|
return _counter;
|
|
}
|
|
|
|
uint64_t ZStatAllocRate::sample_and_reset() {
|
|
const ZStatCounterData bytes_per_sample = _counter.collect_and_reset();
|
|
const uint64_t bytes_per_second = bytes_per_sample._counter * sample_hz;
|
|
|
|
_rate.add(bytes_per_second);
|
|
_rate_avg.add(_rate.avg());
|
|
|
|
return bytes_per_second;
|
|
}
|
|
|
|
double ZStatAllocRate::avg() {
|
|
return _rate.avg();
|
|
}
|
|
|
|
double ZStatAllocRate::avg_sd() {
|
|
return _rate_avg.sd();
|
|
}
|
|
|
|
//
|
|
// Stat thread
|
|
//
|
|
ZStat::ZStat() :
|
|
_metronome(sample_hz) {
|
|
set_name("ZStat");
|
|
create_and_start();
|
|
}
|
|
|
|
void ZStat::sample_and_collect(ZStatSamplerHistory* history) const {
|
|
// Sample counters
|
|
for (const ZStatCounter* counter = ZStatCounter::first(); counter != NULL; counter = counter->next()) {
|
|
counter->sample_and_reset();
|
|
}
|
|
|
|
// Collect samples
|
|
for (const ZStatSampler* sampler = ZStatSampler::first(); sampler != NULL; sampler = sampler->next()) {
|
|
ZStatSamplerHistory& sampler_history = history[sampler->id()];
|
|
sampler_history.add(sampler->collect_and_reset());
|
|
}
|
|
}
|
|
|
|
bool ZStat::should_print(LogTargetHandle log) const {
|
|
static uint64_t print_at = ZStatisticsInterval;
|
|
const uint64_t now = os::elapsedTime();
|
|
|
|
if (now < print_at) {
|
|
return false;
|
|
}
|
|
|
|
print_at = ((now / ZStatisticsInterval) * ZStatisticsInterval) + ZStatisticsInterval;
|
|
|
|
return log.is_enabled();
|
|
}
|
|
|
|
void ZStat::print(LogTargetHandle log, const ZStatSamplerHistory* history) const {
|
|
// Print
|
|
log.print("=== Garbage Collection Statistics =======================================================================================================================");
|
|
log.print(" Last 10s Last 10m Last 10h Total");
|
|
log.print(" Avg / Max Avg / Max Avg / Max Avg / Max");
|
|
|
|
for (const ZStatSampler* sampler = ZStatSampler::first(); sampler != NULL; sampler = sampler->next()) {
|
|
const ZStatSamplerHistory& sampler_history = history[sampler->id()];
|
|
const ZStatUnitPrinter printer = sampler->printer();
|
|
printer(log, *sampler, sampler_history);
|
|
}
|
|
|
|
log.print("=========================================================================================================================================================");
|
|
}
|
|
|
|
void ZStat::run_service() {
|
|
ZStatSamplerHistory* const history = new ZStatSamplerHistory[ZStatSampler::count()];
|
|
LogTarget(Info, gc, stats) log;
|
|
|
|
// Main loop
|
|
while (_metronome.wait_for_tick()) {
|
|
sample_and_collect(history);
|
|
if (should_print(log)) {
|
|
print(log, history);
|
|
}
|
|
}
|
|
|
|
delete [] history;
|
|
}
|
|
|
|
void ZStat::stop_service() {
|
|
_metronome.stop();
|
|
}
|
|
|
|
//
|
|
// Stat table
|
|
//
|
|
class ZStatTablePrinter {
|
|
private:
|
|
static const size_t _buffer_size = 256;
|
|
|
|
const size_t _column0_width;
|
|
const size_t _columnN_width;
|
|
char _buffer[_buffer_size];
|
|
|
|
public:
|
|
class ZColumn {
|
|
private:
|
|
char* const _buffer;
|
|
const size_t _position;
|
|
const size_t _width;
|
|
const size_t _width_next;
|
|
|
|
ZColumn next() const {
|
|
// Insert space between columns
|
|
_buffer[_position + _width] = ' ';
|
|
return ZColumn(_buffer, _position + _width + 1, _width_next, _width_next);
|
|
}
|
|
|
|
size_t print(size_t position, const char* fmt, va_list va) {
|
|
const int res = jio_vsnprintf(_buffer + position, _buffer_size - position, fmt, va);
|
|
if (res < 0) {
|
|
return 0;
|
|
}
|
|
|
|
return (size_t)res;
|
|
}
|
|
|
|
public:
|
|
ZColumn(char* buffer, size_t position, size_t width, size_t width_next) :
|
|
_buffer(buffer),
|
|
_position(position),
|
|
_width(width),
|
|
_width_next(width_next) {}
|
|
|
|
ZColumn left(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) {
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
const size_t written = print(_position, fmt, va);
|
|
va_end(va);
|
|
|
|
if (written < _width) {
|
|
// Fill empty space
|
|
memset(_buffer + _position + written, ' ', _width - written);
|
|
}
|
|
|
|
return next();
|
|
}
|
|
|
|
ZColumn right(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) {
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
const size_t written = print(_position, fmt, va);
|
|
va_end(va);
|
|
|
|
if (written > _width) {
|
|
// Line too long
|
|
return fill('?');
|
|
}
|
|
|
|
if (written < _width) {
|
|
// Short line, move all to right
|
|
memmove(_buffer + _position + _width - written, _buffer + _position, written);
|
|
|
|
// Fill empty space
|
|
memset(_buffer + _position, ' ', _width - written);
|
|
}
|
|
|
|
return next();
|
|
}
|
|
|
|
ZColumn center(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) {
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
const size_t written = print(_position, fmt, va);
|
|
va_end(va);
|
|
|
|
if (written > _width) {
|
|
// Line too long
|
|
return fill('?');
|
|
}
|
|
|
|
if (written < _width) {
|
|
// Short line, move all to center
|
|
const size_t start_space = (_width - written) / 2;
|
|
const size_t end_space = _width - written - start_space;
|
|
memmove(_buffer + _position + start_space, _buffer + _position, written);
|
|
|
|
// Fill empty spaces
|
|
memset(_buffer + _position, ' ', start_space);
|
|
memset(_buffer + _position + start_space + written, ' ', end_space);
|
|
}
|
|
|
|
return next();
|
|
}
|
|
|
|
ZColumn fill(char filler = ' ') {
|
|
memset(_buffer + _position, filler, _width);
|
|
return next();
|
|
}
|
|
|
|
const char* end() {
|
|
_buffer[_position] = '\0';
|
|
return _buffer;
|
|
}
|
|
};
|
|
|
|
public:
|
|
ZStatTablePrinter(size_t column0_width, size_t columnN_width) :
|
|
_column0_width(column0_width),
|
|
_columnN_width(columnN_width) {}
|
|
|
|
ZColumn operator()() {
|
|
return ZColumn(_buffer, 0, _column0_width, _columnN_width);
|
|
}
|
|
};
|
|
|
|
//
|
|
// Stat cycle
|
|
//
|
|
uint64_t ZStatCycle::_nwarmup_cycles = 0;
|
|
Ticks ZStatCycle::_start_of_last;
|
|
Ticks ZStatCycle::_end_of_last;
|
|
NumberSeq ZStatCycle::_normalized_duration(0.3 /* alpha */);
|
|
|
|
void ZStatCycle::at_start() {
|
|
_start_of_last = Ticks::now();
|
|
}
|
|
|
|
void ZStatCycle::at_end(GCCause::Cause cause, double boost_factor) {
|
|
_end_of_last = Ticks::now();
|
|
|
|
if (cause == GCCause::_z_warmup) {
|
|
_nwarmup_cycles++;
|
|
}
|
|
|
|
// Calculate normalized cycle duration. The measured duration is
|
|
// normalized using the boost factor to avoid artificial deflation
|
|
// of the duration when boost mode is enabled.
|
|
const double duration = (_end_of_last - _start_of_last).seconds();
|
|
const double normalized_duration = duration * boost_factor;
|
|
_normalized_duration.add(normalized_duration);
|
|
}
|
|
|
|
bool ZStatCycle::is_warm() {
|
|
return _nwarmup_cycles >= 3;
|
|
}
|
|
|
|
uint64_t ZStatCycle::nwarmup_cycles() {
|
|
return _nwarmup_cycles;
|
|
}
|
|
|
|
bool ZStatCycle::is_normalized_duration_trustable() {
|
|
// The normalized duration is considered trustable if we have
|
|
// completed at least one warmup cycle
|
|
return _nwarmup_cycles > 0;
|
|
}
|
|
|
|
const AbsSeq& ZStatCycle::normalized_duration() {
|
|
return _normalized_duration;
|
|
}
|
|
|
|
double ZStatCycle::time_since_last() {
|
|
if (_end_of_last.value() == 0) {
|
|
// No end recorded yet, return time since VM start
|
|
return os::elapsedTime();
|
|
}
|
|
|
|
const Ticks now = Ticks::now();
|
|
const Tickspan time_since_last = now - _end_of_last;
|
|
return time_since_last.seconds();
|
|
}
|
|
|
|
//
|
|
// Stat load
|
|
//
|
|
void ZStatLoad::print() {
|
|
double loadavg[3] = {};
|
|
os::loadavg(loadavg, ARRAY_SIZE(loadavg));
|
|
log_info(gc, load)("Load: %.2f/%.2f/%.2f", loadavg[0], loadavg[1], loadavg[2]);
|
|
}
|
|
|
|
//
|
|
// Stat mark
|
|
//
|
|
size_t ZStatMark::_nstripes;
|
|
size_t ZStatMark::_nproactiveflush;
|
|
size_t ZStatMark::_nterminateflush;
|
|
size_t ZStatMark::_ntrycomplete;
|
|
size_t ZStatMark::_ncontinue;
|
|
|
|
void ZStatMark::set_at_mark_start(size_t nstripes) {
|
|
_nstripes = nstripes;
|
|
}
|
|
|
|
void ZStatMark::set_at_mark_end(size_t nproactiveflush,
|
|
size_t nterminateflush,
|
|
size_t ntrycomplete,
|
|
size_t ncontinue) {
|
|
_nproactiveflush = nproactiveflush;
|
|
_nterminateflush = nterminateflush;
|
|
_ntrycomplete = ntrycomplete;
|
|
_ncontinue = ncontinue;
|
|
}
|
|
|
|
void ZStatMark::print() {
|
|
log_info(gc, marking)("Mark: "
|
|
SIZE_FORMAT " stripe(s), "
|
|
SIZE_FORMAT " proactive flush(es), "
|
|
SIZE_FORMAT " terminate flush(es), "
|
|
SIZE_FORMAT " completion(s), "
|
|
SIZE_FORMAT " continuation(s) ",
|
|
_nstripes,
|
|
_nproactiveflush,
|
|
_nterminateflush,
|
|
_ntrycomplete,
|
|
_ncontinue);
|
|
}
|
|
|
|
//
|
|
// Stat relocation
|
|
//
|
|
size_t ZStatRelocation::_relocating;
|
|
bool ZStatRelocation::_success;
|
|
|
|
void ZStatRelocation::set_at_select_relocation_set(size_t relocating) {
|
|
_relocating = relocating;
|
|
}
|
|
|
|
void ZStatRelocation::set_at_relocate_end(bool success) {
|
|
_success = success;
|
|
}
|
|
|
|
void ZStatRelocation::print() {
|
|
if (_success) {
|
|
log_info(gc, reloc)("Relocation: Successful, " SIZE_FORMAT "M relocated", _relocating / M);
|
|
} else {
|
|
log_info(gc, reloc)("Relocation: Incomplete");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stat nmethods
|
|
//
|
|
void ZStatNMethods::print() {
|
|
log_info(gc, nmethod)("NMethods: " SIZE_FORMAT " registered, " SIZE_FORMAT " unregistered",
|
|
ZNMethodTable::registered_nmethods(),
|
|
ZNMethodTable::unregistered_nmethods());
|
|
}
|
|
|
|
//
|
|
// Stat metaspace
|
|
//
|
|
void ZStatMetaspace::print() {
|
|
log_info(gc, metaspace)("Metaspace: "
|
|
SIZE_FORMAT "M used, " SIZE_FORMAT "M capacity, "
|
|
SIZE_FORMAT "M committed, " SIZE_FORMAT "M reserved",
|
|
MetaspaceUtils::used_bytes() / M,
|
|
MetaspaceUtils::capacity_bytes() / M,
|
|
MetaspaceUtils::committed_bytes() / M,
|
|
MetaspaceUtils::reserved_bytes() / M);
|
|
}
|
|
|
|
//
|
|
// Stat references
|
|
//
|
|
ZStatReferences::ZCount ZStatReferences::_soft;
|
|
ZStatReferences::ZCount ZStatReferences::_weak;
|
|
ZStatReferences::ZCount ZStatReferences::_final;
|
|
ZStatReferences::ZCount ZStatReferences::_phantom;
|
|
|
|
void ZStatReferences::set(ZCount* count, size_t encountered, size_t discovered, size_t enqueued) {
|
|
count->encountered = encountered;
|
|
count->discovered = discovered;
|
|
count->enqueued = enqueued;
|
|
}
|
|
|
|
void ZStatReferences::set_soft(size_t encountered, size_t discovered, size_t enqueued) {
|
|
set(&_soft, encountered, discovered, enqueued);
|
|
}
|
|
|
|
void ZStatReferences::set_weak(size_t encountered, size_t discovered, size_t enqueued) {
|
|
set(&_weak, encountered, discovered, enqueued);
|
|
}
|
|
|
|
void ZStatReferences::set_final(size_t encountered, size_t discovered, size_t enqueued) {
|
|
set(&_final, encountered, discovered, enqueued);
|
|
}
|
|
|
|
void ZStatReferences::set_phantom(size_t encountered, size_t discovered, size_t enqueued) {
|
|
set(&_phantom, encountered, discovered, enqueued);
|
|
}
|
|
|
|
void ZStatReferences::print(const char* name, const ZStatReferences::ZCount& ref) {
|
|
log_info(gc, ref)("%s: "
|
|
SIZE_FORMAT " encountered, "
|
|
SIZE_FORMAT " discovered, "
|
|
SIZE_FORMAT " enqueued",
|
|
name,
|
|
ref.encountered,
|
|
ref.discovered,
|
|
ref.enqueued);
|
|
}
|
|
|
|
void ZStatReferences::print() {
|
|
print("Soft", _soft);
|
|
print("Weak", _weak);
|
|
print("Final", _final);
|
|
print("Phantom", _phantom);
|
|
}
|
|
|
|
//
|
|
// Stat heap
|
|
//
|
|
ZStatHeap::ZAtInitialize ZStatHeap::_at_initialize;
|
|
ZStatHeap::ZAtMarkStart ZStatHeap::_at_mark_start;
|
|
ZStatHeap::ZAtMarkEnd ZStatHeap::_at_mark_end;
|
|
ZStatHeap::ZAtRelocateStart ZStatHeap::_at_relocate_start;
|
|
ZStatHeap::ZAtRelocateEnd ZStatHeap::_at_relocate_end;
|
|
|
|
size_t ZStatHeap::capacity_high() {
|
|
return MAX4(_at_mark_start.capacity,
|
|
_at_mark_end.capacity,
|
|
_at_relocate_start.capacity,
|
|
_at_relocate_end.capacity);
|
|
}
|
|
|
|
size_t ZStatHeap::capacity_low() {
|
|
return MIN4(_at_mark_start.capacity,
|
|
_at_mark_end.capacity,
|
|
_at_relocate_start.capacity,
|
|
_at_relocate_end.capacity);
|
|
}
|
|
|
|
size_t ZStatHeap::available(size_t used) {
|
|
return _at_initialize.max_capacity - used;
|
|
}
|
|
|
|
size_t ZStatHeap::reserve(size_t used) {
|
|
return MIN2(_at_initialize.max_reserve, available(used));
|
|
}
|
|
|
|
size_t ZStatHeap::free(size_t used) {
|
|
return available(used) - reserve(used);
|
|
}
|
|
|
|
void ZStatHeap::set_at_initialize(size_t min_capacity,
|
|
size_t max_capacity,
|
|
size_t max_reserve) {
|
|
_at_initialize.min_capacity = min_capacity;
|
|
_at_initialize.max_capacity = max_capacity;
|
|
_at_initialize.max_reserve = max_reserve;
|
|
}
|
|
|
|
void ZStatHeap::set_at_mark_start(size_t soft_max_capacity,
|
|
size_t capacity,
|
|
size_t used) {
|
|
_at_mark_start.soft_max_capacity = soft_max_capacity;
|
|
_at_mark_start.capacity = capacity;
|
|
_at_mark_start.reserve = reserve(used);
|
|
_at_mark_start.used = used;
|
|
_at_mark_start.free = free(used);
|
|
}
|
|
|
|
void ZStatHeap::set_at_mark_end(size_t capacity,
|
|
size_t allocated,
|
|
size_t used) {
|
|
_at_mark_end.capacity = capacity;
|
|
_at_mark_end.reserve = reserve(used);
|
|
_at_mark_end.allocated = allocated;
|
|
_at_mark_end.used = used;
|
|
_at_mark_end.free = free(used);
|
|
}
|
|
|
|
void ZStatHeap::set_at_select_relocation_set(size_t live,
|
|
size_t garbage,
|
|
size_t reclaimed) {
|
|
_at_mark_end.live = live;
|
|
_at_mark_end.garbage = garbage;
|
|
|
|
_at_relocate_start.garbage = garbage - reclaimed;
|
|
_at_relocate_start.reclaimed = reclaimed;
|
|
}
|
|
|
|
void ZStatHeap::set_at_relocate_start(size_t capacity,
|
|
size_t allocated,
|
|
size_t used) {
|
|
_at_relocate_start.capacity = capacity;
|
|
_at_relocate_start.reserve = reserve(used);
|
|
_at_relocate_start.allocated = allocated;
|
|
_at_relocate_start.used = used;
|
|
_at_relocate_start.free = free(used);
|
|
}
|
|
|
|
void ZStatHeap::set_at_relocate_end(size_t capacity,
|
|
size_t allocated,
|
|
size_t reclaimed,
|
|
size_t used,
|
|
size_t used_high,
|
|
size_t used_low) {
|
|
_at_relocate_end.capacity = capacity;
|
|
_at_relocate_end.capacity_high = capacity_high();
|
|
_at_relocate_end.capacity_low = capacity_low();
|
|
_at_relocate_end.reserve = reserve(used);
|
|
_at_relocate_end.reserve_high = reserve(used_low);
|
|
_at_relocate_end.reserve_low = reserve(used_high);
|
|
_at_relocate_end.garbage = _at_mark_end.garbage - reclaimed;
|
|
_at_relocate_end.allocated = allocated;
|
|
_at_relocate_end.reclaimed = reclaimed;
|
|
_at_relocate_end.used = used;
|
|
_at_relocate_end.used_high = used_high;
|
|
_at_relocate_end.used_low = used_low;
|
|
_at_relocate_end.free = free(used);
|
|
_at_relocate_end.free_high = free(used_low);
|
|
_at_relocate_end.free_low = free(used_high);
|
|
}
|
|
|
|
size_t ZStatHeap::max_capacity() {
|
|
return _at_initialize.max_capacity;
|
|
}
|
|
|
|
size_t ZStatHeap::used_at_mark_start() {
|
|
return _at_mark_start.used;
|
|
}
|
|
|
|
size_t ZStatHeap::used_at_relocate_end() {
|
|
return _at_relocate_end.used;
|
|
}
|
|
|
|
void ZStatHeap::print() {
|
|
log_info(gc, heap)("Min Capacity: "
|
|
ZSIZE_FMT, ZSIZE_ARGS(_at_initialize.min_capacity));
|
|
log_info(gc, heap)("Max Capacity: "
|
|
ZSIZE_FMT, ZSIZE_ARGS(_at_initialize.max_capacity));
|
|
log_info(gc, heap)("Soft Max Capacity: "
|
|
ZSIZE_FMT, ZSIZE_ARGS(_at_mark_start.soft_max_capacity));
|
|
|
|
ZStatTablePrinter table(10, 18);
|
|
log_info(gc, heap)("%s", table()
|
|
.fill()
|
|
.center("Mark Start")
|
|
.center("Mark End")
|
|
.center("Relocate Start")
|
|
.center("Relocate End")
|
|
.center("High")
|
|
.center("Low")
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Capacity:")
|
|
.left(ZTABLE_ARGS(_at_mark_start.capacity))
|
|
.left(ZTABLE_ARGS(_at_mark_end.capacity))
|
|
.left(ZTABLE_ARGS(_at_relocate_start.capacity))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.capacity))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.capacity_high))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.capacity_low))
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Reserve:")
|
|
.left(ZTABLE_ARGS(_at_mark_start.reserve))
|
|
.left(ZTABLE_ARGS(_at_mark_end.reserve))
|
|
.left(ZTABLE_ARGS(_at_relocate_start.reserve))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.reserve))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.reserve_high))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.reserve_low))
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Free:")
|
|
.left(ZTABLE_ARGS(_at_mark_start.free))
|
|
.left(ZTABLE_ARGS(_at_mark_end.free))
|
|
.left(ZTABLE_ARGS(_at_relocate_start.free))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.free))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.free_high))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.free_low))
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Used:")
|
|
.left(ZTABLE_ARGS(_at_mark_start.used))
|
|
.left(ZTABLE_ARGS(_at_mark_end.used))
|
|
.left(ZTABLE_ARGS(_at_relocate_start.used))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.used))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.used_high))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.used_low))
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Live:")
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS(_at_mark_end.live))
|
|
.left(ZTABLE_ARGS(_at_mark_end.live /* Same as at mark end */))
|
|
.left(ZTABLE_ARGS(_at_mark_end.live /* Same as at mark end */))
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS_NA)
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Allocated:")
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS(_at_mark_end.allocated))
|
|
.left(ZTABLE_ARGS(_at_relocate_start.allocated))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.allocated))
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS_NA)
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Garbage:")
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS(_at_mark_end.garbage))
|
|
.left(ZTABLE_ARGS(_at_relocate_start.garbage))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.garbage))
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS_NA)
|
|
.end());
|
|
log_info(gc, heap)("%s", table()
|
|
.right("Reclaimed:")
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS(_at_relocate_start.reclaimed))
|
|
.left(ZTABLE_ARGS(_at_relocate_end.reclaimed))
|
|
.left(ZTABLE_ARGS_NA)
|
|
.left(ZTABLE_ARGS_NA)
|
|
.end());
|
|
}
|