Skip to content
Permalink
Browse files
8264311: Heap object statistics
Reviewed-by: shade
  • Loading branch information
rkennke committed May 10, 2021
1 parent 80a0268 commit dce94d8bf8e6ba1b6b0a5d528ea3ba174ec80098
@@ -130,7 +130,7 @@ class markWord {
static const int lock_bits = 2;
static const int biased_lock_bits = 1;
static const int max_hash_bits = BitsPerWord - age_bits - lock_bits - biased_lock_bits;
static const int hash_bits = max_hash_bits > 31 ? 31 : max_hash_bits;
static const int hash_bits = max_hash_bits > 22 ? 22 : max_hash_bits;
static const int unused_gap_bits = LP64_ONLY(1) NOT_LP64(0);
static const int epoch_bits = 2;

@@ -2048,6 +2048,12 @@ const intx ObjectAlignmentInBytes = 8;
false AARCH64_ONLY(DEBUG_ONLY(||true)), \
"Mark all threads after a safepoint, and clear on a modify " \
"fence. Add cleanliness checks.") \
\
product(bool, HeapObjectStats, false, DIAGNOSTIC, \
"Enable gathering of heap object statistics") \
\
product(size_t, HeapObjectStatsSamplingInterval, 500, DIAGNOSTIC, \
"Heap object statistics sampling interval (ms)") \

// end of RUNTIME_FLAGS

@@ -116,6 +116,7 @@
#include "runtime/vmOperations.hpp"
#include "runtime/vm_version.hpp"
#include "services/attachListener.hpp"
#include "services/heapObjectStatistics.hpp"
#include "services/management.hpp"
#include "services/memTracker.hpp"
#include "services/threadService.hpp"
@@ -2956,6 +2957,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
// Start the monitor deflation thread:
MonitorDeflationThread::initialize();

// Start heap object statistics sampling
HeapObjectStatistics::initialize();

// initialize compiler(s)
#if defined(COMPILER1) || COMPILER2_OR_JVMCI
#if INCLUDE_JVMCI
@@ -3404,6 +3408,8 @@ void Threads::destroy_vm() {
// complete it is safe to directly delete the thread at any time.
ThreadsSMRSupport::wait_until_not_protected(thread);

HeapObjectStatistics::shutdown();

// Stop VM thread.
{
// 4945125 The vm thread comes to a safepoint during exit.
@@ -81,6 +81,7 @@
template(ChangeSingleStep) \
template(HeapWalkOperation) \
template(HeapIterateOperation) \
template(HeapObjectStatistics) \
template(ReportJavaOutOfMemory) \
template(JFRCheckpoint) \
template(ShenandoahFullGC) \
@@ -0,0 +1,168 @@
/*
* Copyright (c) 2021, Red Hat, Inc. 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/shared/collectedHeap.hpp"
#include "logging/logStream.hpp"
#include "logging/logTag.hpp"
#include "memory/allocation.hpp"
#include "memory/iterator.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/vmThread.hpp"
#include "services/heapObjectStatistics.hpp"
#include "utilities/copy.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"

HeapObjectStatistics* HeapObjectStatistics::_instance = NULL;

class HeapObjectStatsObjectClosure : public ObjectClosure {
private:
HeapObjectStatistics* const _stats;
public:
HeapObjectStatsObjectClosure() : _stats(HeapObjectStatistics::instance()) {}
void do_object(oop obj) {
_stats->visit_object(obj);
}
};

class VM_HeapObjectStatistics : public VM_Operation {
public:
VMOp_Type type() const { return VMOp_HeapObjectStatistics; }
bool doit_prologue() {
Heap_lock->lock();
return true;
}

void doit_epilogue() {
Heap_lock->unlock();
}

void doit() {
assert(SafepointSynchronize::is_at_safepoint(), "all threads are stopped");
assert(Heap_lock->is_locked(), "should have the Heap_lock");

CollectedHeap* heap = Universe::heap();
heap->ensure_parsability(false);

HeapObjectStatistics* stats = HeapObjectStatistics::instance();
stats->begin_sample();

HeapObjectStatsObjectClosure cl;
heap->object_iterate(&cl);
}
};

HeapObjectStatisticsTask::HeapObjectStatisticsTask() : PeriodicTask(HeapObjectStatsSamplingInterval) {}

void HeapObjectStatisticsTask::task() {
VM_HeapObjectStatistics vmop;
VMThread::execute(&vmop);
}

void HeapObjectStatistics::initialize() {
assert(_instance == NULL, "Don't init twice");
if (HeapObjectStats) {
_instance = new HeapObjectStatistics();
_instance->start();
}
}

void HeapObjectStatistics::shutdown() {
if (HeapObjectStats) {
assert(_instance != NULL, "Must be initialized");
LogTarget(Info, heap, stats) lt;
if (lt.is_enabled()) {
LogStream ls(lt);
ResourceMark rm;
_instance->print(&ls);
}
_instance->stop();
delete _instance;
_instance = NULL;
}
}

HeapObjectStatistics* HeapObjectStatistics::instance() {
assert(_instance != NULL, "Must be initialized");
return _instance;
}

void HeapObjectStatistics::increase_counter(uint64_t& counter, uint64_t val) {
uint64_t oldval = counter;
uint64_t newval = counter + val;
if (newval < oldval) {
log_warning(heap, stats)("HeapObjectStats counter overflow: resulting statistics will be useless");
}
counter = newval;
}

HeapObjectStatistics::HeapObjectStatistics() :
_task(), _num_samples(0), _num_objects(0), _num_ihashed(0), _num_locked(0), _lds(0) { }

void HeapObjectStatistics::start() {
_task.enroll();
}

void HeapObjectStatistics::stop() {
_task.disenroll();
}

void HeapObjectStatistics::begin_sample() {
_num_samples++;
}

void HeapObjectStatistics::visit_object(oop obj) {
increase_counter(_num_objects);
if (!obj->mark().has_no_hash()) {
increase_counter(_num_ihashed);
if (obj->mark().age() > 0) {
increase_counter(_num_ihashed_moved);
}
}
if (obj->mark().is_locked()) {
increase_counter(_num_locked);
}
increase_counter(_lds, obj->size());
}

void HeapObjectStatistics::print(outputStream* out) const {
if (!HeapObjectStats) {
return;
}
if (_num_samples == 0 || _num_objects == 0) {
return;
}

out->print_cr("Number of samples: " UINT64_FORMAT, _num_samples);
out->print_cr("Average number of objects: " UINT64_FORMAT, _num_objects / _num_samples);
out->print_cr("Average object size: " UINT64_FORMAT " bytes, %.1f words", (_lds * HeapWordSize) / _num_objects, (float) _lds / _num_objects);
out->print_cr("Average number of hashed objects: " UINT64_FORMAT " (%.2f%%)", _num_ihashed / _num_samples, (float) (_num_ihashed * 100.0) / _num_objects);
out->print_cr("Average number of moved hashed objects: " UINT64_FORMAT " (%.2f%%)", _num_ihashed_moved / _num_samples, (float) (_num_ihashed_moved * 100.0) / _num_objects);
out->print_cr("Average number of locked objects: " UINT64_FORMAT " (%.2f%%)", _num_locked / _num_samples, (float) (_num_locked * 100) / _num_objects);
out->print_cr("Average LDS: " UINT64_FORMAT " bytes", _lds * HeapWordSize / _num_samples);
out->print_cr("Avg LDS with (assumed) 64bit header: " UINT64_FORMAT " bytes (%.1f%%)", (_lds - _num_objects) * HeapWordSize / _num_samples, ((float) _lds - _num_objects) * 100.0 / _lds);
}
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2021, Red Hat, Inc. 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.
*
*/

#ifndef SHARE_SERVICES_HEAPOBJECTSTATISTICS_HPP
#define SHARE_SERVICES_HEAPOBJECTSTATISTICS_HPP

#include "memory/allocation.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/task.hpp"
#include "runtime/vmOperation.hpp"

class outputStream;

class HeapObjectStatisticsTask : public PeriodicTask {
public:
HeapObjectStatisticsTask();
void task();
};

class HeapObjectStatistics : public CHeapObj<mtGC> {
private:
static HeapObjectStatistics* _instance;

HeapObjectStatisticsTask _task;
uint64_t _num_samples;
uint64_t _num_objects;
uint64_t _num_ihashed;
uint64_t _num_ihashed_moved;
uint64_t _num_locked;
uint64_t _lds;

static void increase_counter(uint64_t& counter, uint64_t val = 1);

void print(outputStream* out) const;

public:
static void initialize();
static void shutdown();

static HeapObjectStatistics* instance();

HeapObjectStatistics();
void start();
void stop();

void begin_sample();
void visit_object(oop object);
};

#endif // SHARE_SERVICES_HEAPOBJECTSTATISTICS_HPP

0 comments on commit dce94d8

Please sign in to comment.