# HG changeset patch # User zgu # Date 1518114082 18000 # Node ID 7e17b00dc24538e21d2e369630d92b628c459b40 # Parent 0f1be3c7b6b2a0561668773db96ebd4ac56ce85a 8196923: [REDO] NMT: Report array class count in NMT summary Summary: Added instance and array class counters in NMT summary report Reviewed-by: minqi, stuefe, coleenp diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/classfile/classLoaderData.cpp --- a/src/hotspot/share/classfile/classLoaderData.cpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/classfile/classLoaderData.cpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ // 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 @@ 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 @@ 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 @@ 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) { diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/classfile/classLoaderData.hpp --- a/src/hotspot/share/classfile/classLoaderData.hpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/classfile/classLoaderData.hpp Thu Feb 08 13:21:22 2018 -0500 @@ -80,6 +80,9 @@ // 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 @@ 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 diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/classfile/classLoaderData.inline.hpp --- a/src/hotspot/share/classfile/classLoaderData.inline.hpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/classfile/classLoaderData.inline.hpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ } 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); +} diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/oops/instanceKlass.cpp --- a/src/hotspot/share/oops/instanceKlass.cpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/oops/instanceKlass.cpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ // 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 @@ // 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) { diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/oops/instanceKlass.hpp --- a/src/hotspot/share/oops/instanceKlass.hpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/oops/instanceKlass.hpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ 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: diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/runtime/compilationPolicy.cpp --- a/src/hotspot/share/runtime/compilationPolicy.cpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/runtime/compilationPolicy.cpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ // 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); diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/runtime/memprofiler.cpp --- a/src/hotspot/share/runtime/memprofiler.cpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/runtime/memprofiler.cpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ } // 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); } diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/services/memBaseline.cpp --- a/src/hotspot/share/services/memBaseline.cpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/services/memBaseline.cpp Thu Feb 08 13:21:22 2018 -0500 @@ -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(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; diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/services/memBaseline.hpp --- a/src/hotspot/share/services/memBaseline.hpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/services/memBaseline.hpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ 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 @@ // 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 @@ 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 @@ 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(); diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/services/memReporter.cpp --- a/src/hotspot/share/services/memReporter.cpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/services/memReporter.cpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ 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 @@ 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()); diff -r 0f1be3c7b6b2 -r 7e17b00dc245 src/hotspot/share/services/memReporter.hpp --- a/src/hotspot/share/services/memReporter.hpp Thu Feb 08 08:38:42 2018 -0800 +++ b/src/hotspot/share/services/memReporter.hpp Thu Feb 08 13:21:22 2018 -0500 @@ -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 @@ 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 @@ 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 diff -r 0f1be3c7b6b2 -r 7e17b00dc245 test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java Thu Feb 08 13:21:22 2018 -0500 @@ -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 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); + } +}