8196923: [REDO] NMT: Report array class count in NMT summary
Added instance and array class counters in NMT summary report Reviewed-by: minqi, stuefe, coleenp
This commit is contained in:
parent
8d72dcd040
commit
934390b571
@ -80,6 +80,9 @@
|
||||
#include "trace/tracing.hpp"
|
||||
#endif
|
||||
|
||||
volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
|
||||
volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0;
|
||||
|
||||
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
|
||||
|
||||
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
|
||||
@ -443,6 +446,11 @@ void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
||||
// Link the new item into the list, making sure the linked class is stable
|
||||
// since the list can be walked without a lock
|
||||
OrderAccess::release_store(&_klasses, k);
|
||||
if (k->is_array_klass()) {
|
||||
ClassLoaderDataGraph::inc_array_classes(1);
|
||||
} else {
|
||||
ClassLoaderDataGraph::inc_instance_classes(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (publicize && k->class_loader_data() != NULL) {
|
||||
@ -468,9 +476,9 @@ class ClassLoaderDataGraphKlassIteratorStatic {
|
||||
|
||||
InstanceKlass* try_get_next_class() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||
int max_classes = InstanceKlass::number_of_instance_classes();
|
||||
size_t max_classes = ClassLoaderDataGraph::num_instance_classes();
|
||||
assert(max_classes > 0, "should not be called with no instance classes");
|
||||
for (int i = 0; i < max_classes; ) {
|
||||
for (size_t i = 0; i < max_classes; ) {
|
||||
|
||||
if (_current_class_entry != NULL) {
|
||||
Klass* k = _current_class_entry;
|
||||
@ -545,6 +553,13 @@ void ClassLoaderData::remove_class(Klass* scratch_class) {
|
||||
Klass* next = k->next_link();
|
||||
prev->set_next_link(next);
|
||||
}
|
||||
|
||||
if (k->is_array_klass()) {
|
||||
ClassLoaderDataGraph::dec_array_classes(1);
|
||||
} else {
|
||||
ClassLoaderDataGraph::dec_instance_classes(1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
prev = k;
|
||||
@ -639,9 +654,34 @@ bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
|
||||
return alive;
|
||||
}
|
||||
|
||||
class ReleaseKlassClosure: public KlassClosure {
|
||||
private:
|
||||
size_t _instance_class_released;
|
||||
size_t _array_class_released;
|
||||
public:
|
||||
ReleaseKlassClosure() : _instance_class_released(0), _array_class_released(0) { }
|
||||
|
||||
size_t instance_class_released() const { return _instance_class_released; }
|
||||
size_t array_class_released() const { return _array_class_released; }
|
||||
|
||||
void do_klass(Klass* k) {
|
||||
if (k->is_array_klass()) {
|
||||
_array_class_released ++;
|
||||
} else {
|
||||
assert(k->is_instance_klass(), "Must be");
|
||||
_instance_class_released ++;
|
||||
InstanceKlass::release_C_heap_structures(InstanceKlass::cast(k));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ClassLoaderData::~ClassLoaderData() {
|
||||
// Release C heap structures for all the classes.
|
||||
classes_do(InstanceKlass::release_C_heap_structures);
|
||||
ReleaseKlassClosure cl;
|
||||
classes_do(&cl);
|
||||
|
||||
ClassLoaderDataGraph::dec_array_classes(cl.array_class_released());
|
||||
ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released());
|
||||
|
||||
// Release C heap allocated hashtable for all the packages.
|
||||
if (_packages != NULL) {
|
||||
|
@ -80,6 +80,9 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
// allocations until class unloading
|
||||
static bool _metaspace_oom;
|
||||
|
||||
static volatile size_t _num_instance_classes;
|
||||
static volatile size_t _num_array_classes;
|
||||
|
||||
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
|
||||
static void post_class_unload_events();
|
||||
public:
|
||||
@ -154,6 +157,15 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
static void print_creation(outputStream* out, Handle loader, ClassLoaderData* cld, TRAPS);
|
||||
|
||||
static bool unload_list_contains(const void* x);
|
||||
|
||||
// instance and array class counters
|
||||
static inline size_t num_instance_classes();
|
||||
static inline size_t num_array_classes();
|
||||
static inline void inc_instance_classes(size_t count);
|
||||
static inline void dec_instance_classes(size_t count);
|
||||
static inline void inc_array_classes(size_t count);
|
||||
static inline void dec_array_classes(size_t count);
|
||||
|
||||
#ifndef PRODUCT
|
||||
static bool contains_loader_data(ClassLoaderData* loader_data);
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2018, 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
|
||||
@ -50,3 +50,29 @@ inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAP
|
||||
}
|
||||
return ClassLoaderDataGraph::add(loader, false, THREAD);
|
||||
}
|
||||
|
||||
size_t ClassLoaderDataGraph::num_instance_classes() {
|
||||
return _num_instance_classes;
|
||||
}
|
||||
|
||||
size_t ClassLoaderDataGraph::num_array_classes() {
|
||||
return _num_array_classes;
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::inc_instance_classes(size_t count) {
|
||||
Atomic::add(count, &_num_instance_classes);
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::dec_instance_classes(size_t count) {
|
||||
assert(count <= _num_instance_classes, "Sanity");
|
||||
Atomic::sub(count, &_num_instance_classes);
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::inc_array_classes(size_t count) {
|
||||
Atomic::add(count, &_num_array_classes);
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::dec_array_classes(size_t count) {
|
||||
assert(count <= _num_array_classes, "Sanity");
|
||||
Atomic::sub(count, &_num_array_classes);
|
||||
}
|
||||
|
@ -124,8 +124,6 @@
|
||||
|
||||
#endif // ndef DTRACE_ENABLED
|
||||
|
||||
volatile int InstanceKlass::_total_instanceKlass_count = 0;
|
||||
|
||||
static inline bool is_class_loader(const Symbol* class_name,
|
||||
const ClassFileParser& parser) {
|
||||
assert(class_name != NULL, "invariant");
|
||||
@ -193,8 +191,6 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par
|
||||
// Add all classes to our internal class loader list here,
|
||||
// including classes in the bootstrap (NULL) class loader.
|
||||
loader_data->add_class(ik, publicize);
|
||||
Atomic::inc(&_total_instanceKlass_count);
|
||||
|
||||
return ik;
|
||||
}
|
||||
|
||||
@ -2241,9 +2237,6 @@ void InstanceKlass::release_C_heap_structures() {
|
||||
// class can't be referenced anymore).
|
||||
if (_array_name != NULL) _array_name->decrement_refcount();
|
||||
if (_source_debug_extension != NULL) FREE_C_HEAP_ARRAY(char, _source_debug_extension);
|
||||
|
||||
assert(_total_instanceKlass_count >= 1, "Sanity check");
|
||||
Atomic::dec(&_total_instanceKlass_count);
|
||||
}
|
||||
|
||||
void InstanceKlass::set_source_debug_extension(const char* array, int length) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2018, 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
|
||||
@ -135,10 +135,7 @@ class InstanceKlass: public Klass {
|
||||
initialization_error // error happened during initialization
|
||||
};
|
||||
|
||||
static int number_of_instance_classes() { return _total_instanceKlass_count; }
|
||||
|
||||
private:
|
||||
static volatile int _total_instanceKlass_count;
|
||||
static InstanceKlass* allocate_instance_klass(const ClassFileParser& parser, TRAPS);
|
||||
|
||||
protected:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2018, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
@ -312,10 +313,10 @@ void CounterDecay::decay() {
|
||||
// and hence GC's will not be going on, all Java mutators are suspended
|
||||
// at this point and hence SystemDictionary_lock is also not needed.
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint");
|
||||
int nclasses = InstanceKlass::number_of_instance_classes();
|
||||
int classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
|
||||
size_t nclasses = ClassLoaderDataGraph::num_instance_classes();
|
||||
size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
|
||||
CounterHalfLifeTime);
|
||||
for (int i = 0; i < classes_per_tick; i++) {
|
||||
for (size_t i = 0; i < classes_per_tick; i++) {
|
||||
InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class();
|
||||
if (k != NULL) {
|
||||
k->methods_do(do_method);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2018, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "gc/shared/collectedHeap.inline.hpp"
|
||||
@ -116,10 +117,10 @@ void MemProfiler::do_trace() {
|
||||
}
|
||||
|
||||
// Print trace line in log
|
||||
fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
|
||||
fprintf(_log_fp, "%6.1f,%5d," SIZE_FORMAT_W(5) "," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
|
||||
os::elapsedTime(),
|
||||
jtiwh.length(),
|
||||
InstanceKlass::number_of_instance_classes(),
|
||||
ClassLoaderDataGraph::num_instance_classes(),
|
||||
Universe::heap()->used() / K,
|
||||
Universe::heap()->capacity() / K);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/thread.inline.hpp"
|
||||
@ -180,7 +181,8 @@ bool MemBaseline::baseline_allocation_sites() {
|
||||
bool MemBaseline::baseline(bool summaryOnly) {
|
||||
reset();
|
||||
|
||||
_class_count = InstanceKlass::number_of_instance_classes();
|
||||
_instance_class_count = ClassLoaderDataGraph::num_instance_classes();
|
||||
_array_class_count = ClassLoaderDataGraph::num_array_classes();
|
||||
|
||||
if (!baseline_summary()) {
|
||||
return false;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -67,7 +67,8 @@ class MemBaseline VALUE_OBJ_CLASS_SPEC {
|
||||
VirtualMemorySnapshot _virtual_memory_snapshot;
|
||||
MetaspaceSnapshot _metaspace_snapshot;
|
||||
|
||||
size_t _class_count;
|
||||
size_t _instance_class_count;
|
||||
size_t _array_class_count;
|
||||
|
||||
// Allocation sites information
|
||||
// Malloc allocation sites
|
||||
@ -89,7 +90,7 @@ class MemBaseline VALUE_OBJ_CLASS_SPEC {
|
||||
// create a memory baseline
|
||||
MemBaseline():
|
||||
_baseline_type(Not_baselined),
|
||||
_class_count(0) {
|
||||
_instance_class_count(0), _array_class_count(0) {
|
||||
}
|
||||
|
||||
bool baseline(bool summaryOnly = true);
|
||||
@ -160,7 +161,17 @@ class MemBaseline VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
size_t class_count() const {
|
||||
assert(baseline_type() != Not_baselined, "Not yet baselined");
|
||||
return _class_count;
|
||||
return _instance_class_count + _array_class_count;
|
||||
}
|
||||
|
||||
size_t instance_class_count() const {
|
||||
assert(baseline_type() != Not_baselined, "Not yet baselined");
|
||||
return _instance_class_count;
|
||||
}
|
||||
|
||||
size_t array_class_count() const {
|
||||
assert(baseline_type() != Not_baselined, "Not yet baselined");
|
||||
return _array_class_count;
|
||||
}
|
||||
|
||||
size_t thread_count() const {
|
||||
@ -172,7 +183,8 @@ class MemBaseline VALUE_OBJ_CLASS_SPEC {
|
||||
void reset() {
|
||||
_baseline_type = Not_baselined;
|
||||
// _malloc_memory_snapshot and _virtual_memory_snapshot are copied over.
|
||||
_class_count = 0;
|
||||
_instance_class_count = 0;
|
||||
_array_class_count = 0;
|
||||
|
||||
_malloc_sites.clear();
|
||||
_virtual_memory_sites.clear();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -145,7 +145,10 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag,
|
||||
|
||||
if (flag == mtClass) {
|
||||
// report class count
|
||||
out->print_cr("%27s (classes #" SIZE_FORMAT ")", " ", _class_count);
|
||||
out->print_cr("%27s (classes #" SIZE_FORMAT ")",
|
||||
" ", (_instance_class_count + _array_class_count));
|
||||
out->print_cr("%27s ( instance classes #" SIZE_FORMAT ", array classes #" SIZE_FORMAT ")",
|
||||
" ", _instance_class_count, _array_class_count);
|
||||
} else if (flag == mtThread) {
|
||||
// report thread count
|
||||
out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count());
|
||||
@ -459,6 +462,17 @@ void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag,
|
||||
out->print(" %+d", (int)(_current_baseline.class_count() - _early_baseline.class_count()));
|
||||
}
|
||||
out->print_cr(")");
|
||||
|
||||
out->print("%27s ( instance classes #" SIZE_FORMAT, " ", _current_baseline.instance_class_count());
|
||||
if (_current_baseline.instance_class_count() != _early_baseline.instance_class_count()) {
|
||||
out->print(" %+d", (int)(_current_baseline.instance_class_count() - _early_baseline.instance_class_count()));
|
||||
}
|
||||
out->print(", array classes #" SIZE_FORMAT, _current_baseline.array_class_count());
|
||||
if (_current_baseline.array_class_count() != _early_baseline.array_class_count()) {
|
||||
out->print(" %+d", (int)(_current_baseline.array_class_count() - _early_baseline.array_class_count()));
|
||||
}
|
||||
out->print_cr(")");
|
||||
|
||||
} else if (flag == mtThread) {
|
||||
// report thread count
|
||||
out->print("%27s (thread #" SIZE_FORMAT "", " ", _current_baseline.thread_count());
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2018, 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
|
||||
@ -94,7 +94,8 @@ class MemSummaryReporter : public MemReporterBase {
|
||||
private:
|
||||
MallocMemorySnapshot* _malloc_snapshot;
|
||||
VirtualMemorySnapshot* _vm_snapshot;
|
||||
size_t _class_count;
|
||||
size_t _instance_class_count;
|
||||
size_t _array_class_count;
|
||||
|
||||
public:
|
||||
// This constructor is for normal reporting from a recent baseline.
|
||||
@ -102,7 +103,8 @@ class MemSummaryReporter : public MemReporterBase {
|
||||
size_t scale = K) : MemReporterBase(output, scale),
|
||||
_malloc_snapshot(baseline.malloc_memory_snapshot()),
|
||||
_vm_snapshot(baseline.virtual_memory_snapshot()),
|
||||
_class_count(baseline.class_count()) { }
|
||||
_instance_class_count(baseline.instance_class_count()),
|
||||
_array_class_count(baseline.array_class_count()) { }
|
||||
|
||||
|
||||
// Generate summary report
|
||||
|
60
test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java
Normal file
60
test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8193184
|
||||
* @key nmt
|
||||
* @summary Check class counters in summary report
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:NativeMemoryTracking=summary JcmdSummaryClass
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
|
||||
|
||||
import java.util.regex.*;
|
||||
|
||||
public class JcmdSummaryClass {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
OutputAnalyzer output;
|
||||
// Grab my own PID
|
||||
String pid = Long.toString(ProcessTools.getProcessId());
|
||||
|
||||
// Run 'jcmd <pid> VM.native_memory baseline=true'
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory"});
|
||||
pb.start().waitFor();
|
||||
|
||||
String classes_line = "classes #\\d+";
|
||||
String instance_array_classes_line = "instance classes #\\d+, array classes #\\d+";
|
||||
output = new OutputAnalyzer(pb.start());
|
||||
output.shouldMatch(classes_line);
|
||||
output.shouldMatch(instance_array_classes_line);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user