8196923: [REDO] NMT: Report array class count in NMT summary
authorzgu
Thu, 08 Feb 2018 13:21:22 -0500
changeset 48884 7e17b00dc245
parent 48883 0f1be3c7b6b2
child 48885 00e159258897
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
src/hotspot/share/classfile/classLoaderData.cpp
src/hotspot/share/classfile/classLoaderData.hpp
src/hotspot/share/classfile/classLoaderData.inline.hpp
src/hotspot/share/oops/instanceKlass.cpp
src/hotspot/share/oops/instanceKlass.hpp
src/hotspot/share/runtime/compilationPolicy.cpp
src/hotspot/share/runtime/memprofiler.cpp
src/hotspot/share/services/memBaseline.cpp
src/hotspot/share/services/memBaseline.hpp
src/hotspot/share/services/memReporter.cpp
src/hotspot/share/services/memReporter.hpp
test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java
--- 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) {
--- 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
--- 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);
+}
--- 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) {
--- 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:
--- 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);
--- 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);
   }
--- 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;
--- 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();
--- 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());
--- 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
--- /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 <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);
+    }
+}