changeset 4524:044681b8bab0

8012086: The object count event should only send events for instances occupying more than 0.5% of the heap Reviewed-by: brutisso, jwilhelm
author ehelin
date Thu, 23 May 2013 08:14:09 +0200
parents dffc616548d2
children f2a9de120e2d
files src/share/vm/gc_implementation/shared/gcTrace.cpp src/share/vm/gc_implementation/shared/gcTrace.hpp src/share/vm/memory/heapInspection.cpp src/share/vm/memory/heapInspection.hpp src/share/vm/memory/klassInfoClosure.hpp src/share/vm/runtime/globals.hpp
diffstat 6 files changed, 121 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/gc_implementation/shared/gcTrace.cpp	Wed May 22 07:30:15 2013 +0200
+++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp	Thu May 23 08:14:09 2013 +0200
@@ -91,24 +91,32 @@
   send_reference_stats_event(REF_PHANTOM, rps.phantom_count());
 }
 
-class ObjectCountEventSenderClosure : public KlassInfoClosure {
-  GCTracer* _gc_tracer;
- public:
-  ObjectCountEventSenderClosure(GCTracer* gc_tracer) : _gc_tracer(gc_tracer) {}
- private:
-  void do_cinfo(KlassInfoEntry* entry) {
-    if (is_visible_klass(entry->klass())) {
-      _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(),
-                                                   entry->words() * BytesPerWord);
-      }
+void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) {
+  if (should_send_event(entry)) {
+    send_event(entry);
   }
+}
 
+void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) {
+  _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(),
+                                               entry->words() * BytesPerWord);
+}
+
+bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const {
+  double percentage_of_heap = ((double) entry->words()) / _total_size_in_words;
+  return percentage_of_heap > _size_threshold_percentage;
+}
+
+bool ObjectCountFilter::do_object_b(oop obj) {
+  bool is_alive = _is_alive == NULL? true : _is_alive->do_object_b(obj);
+  return is_alive && is_externally_visible_klass(obj->klass());
+}
+
+bool ObjectCountFilter::is_externally_visible_klass(klassOop k) const {
   // Do not expose internal implementation specific classes
-  bool is_visible_klass(klassOop k) {
-    return k->klass_part()->oop_is_instance() ||
-           (k->klass_part()->oop_is_array() && k != Universe::systemObjArrayKlassObj());
-  }
-};
+  return (k->klass_part()->oop_is_instance() || k->klass_part()->oop_is_array()) &&
+         k != Universe::systemObjArrayKlassObj();
+}
 
 void GCTracer::report_object_count_after_gc(BoolObjectClosure *is_alive_cl) {
   if (should_send_object_count_after_gc_event()) {
@@ -116,8 +124,11 @@
 
     KlassInfoTable cit(HeapInspection::start_of_perm_gen());
     if (!cit.allocation_failed()) {
-      ObjectCountEventSenderClosure event_sender(this);
-      HeapInspection::instance_inspection(&cit, &event_sender, false, is_alive_cl);
+      ObjectCountFilter object_filter(is_alive_cl);
+      HeapInspection::populate_table(&cit, false, &object_filter);
+
+      ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words());
+      cit.iterate(&event_sender);
     }
   }
 }
--- a/src/share/vm/gc_implementation/shared/gcTrace.hpp	Wed May 22 07:30:15 2013 +0200
+++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp	Thu May 23 08:14:09 2013 +0200
@@ -30,6 +30,7 @@
 #include "gc_implementation/shared/gcWhen.hpp"
 #include "gc_implementation/shared/copyFailedInfo.hpp"
 #include "memory/allocation.hpp"
+#include "memory/klassInfoClosure.hpp"
 #include "memory/referenceType.hpp"
 #ifndef SERIALGC
 #include "gc_implementation/g1/g1YCTypes.hpp"
@@ -139,6 +140,33 @@
   bool should_send_object_count_after_gc_event() const;
 };
 
+class ObjectCountEventSenderClosure : public KlassInfoClosure {
+  GCTracer* _gc_tracer;
+  const double _size_threshold_percentage;
+  const size_t _total_size_in_words;
+ public:
+  ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) :
+    _gc_tracer(gc_tracer),
+    _size_threshold_percentage(ObjectCountCutOffPercent / 100),
+    _total_size_in_words(total_size_in_words)
+  {}
+  virtual void do_cinfo(KlassInfoEntry* entry);
+ protected:
+  virtual void send_event(KlassInfoEntry* entry);
+ private:
+  bool should_send_event(KlassInfoEntry* entry) const;
+};
+
+class ObjectCountFilter : public BoolObjectClosure {
+  BoolObjectClosure* _is_alive;
+ public:
+  ObjectCountFilter(BoolObjectClosure* is_alive = NULL) : _is_alive(is_alive) {}
+  bool do_object_b(oop obj);
+  void do_object(oop obj) { ShouldNotReachHere(); }
+ private:
+  bool is_externally_visible_klass(klassOop k) const;
+};
+
 class YoungGCTracer : public GCTracer {
   static const uint UNSET_TENURING_THRESHOLD = (uint) -1;
 
--- a/src/share/vm/memory/heapInspection.cpp	Wed May 22 07:30:15 2013 +0200
+++ b/src/share/vm/memory/heapInspection.cpp	Thu May 23 08:14:09 2013 +0200
@@ -113,9 +113,8 @@
   }
 }
 
-KlassInfoTable::KlassInfoTable(HeapWord* ref) {
-  _size = 0;
-  _ref = ref;
+KlassInfoTable::KlassInfoTable(HeapWord* ref) :
+  _size(0), _ref(ref), _size_of_instances_in_words(0) {
   _buckets = (KlassInfoBucket *) os::malloc(sizeof(KlassInfoBucket) * _num_buckets, mtInternal);
   if (_buckets != NULL) {
     _size = _num_buckets;
@@ -160,6 +159,7 @@
   if (elt != NULL) {
     elt->set_count(elt->count() + 1);
     elt->set_words(elt->words() + obj->size());
+    _size_of_instances_in_words += obj->size();
     return true;
   } else {
     return false;
@@ -173,6 +173,10 @@
   }
 }
 
+size_t KlassInfoTable::size_of_instances_in_words() const {
+  return _size_of_instances_in_words;
+}
+
 int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) {
   return (*e1)->compare(*e1,*e2);
 }
@@ -282,10 +286,9 @@
   }
 }
 
-size_t HeapInspection::instance_inspection(KlassInfoTable* cit,
-                                           KlassInfoClosure* cl,
-                                           bool need_prologue,
-                                           BoolObjectClosure* filter) {
+size_t HeapInspection::populate_table(KlassInfoTable* cit,
+                                      bool need_prologue,
+                                      BoolObjectClosure *filter) {
   ResourceMark rm;
 
   if (need_prologue) {
@@ -294,7 +297,6 @@
 
   RecordInstanceClosure ric(cit, filter);
   Universe::heap()->object_iterate(&ric);
-  cit->iterate(cl);
 
   // need to run epilogue if we run prologue
   if (need_prologue) {
@@ -309,17 +311,20 @@
 
   KlassInfoTable cit(start_of_perm_gen());
   if (!cit.allocation_failed()) {
+    size_t missed_count = populate_table(&cit, need_prologue);
+    if (missed_count != 0) {
+      st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT
+                   " total instances in data below",
+                   missed_count);
+    }
+
     KlassInfoHisto histo("\n"
                      " num     #instances         #bytes  class name\n"
                      "----------------------------------------------");
     HistoClosure hc(&histo);
 
-    size_t missed_count = instance_inspection(&cit, &hc, need_prologue);
-    if (missed_count != 0) {
-      st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT
-                   " total instances in data below",
-                   missed_count);
-    }
+    cit.iterate(&hc);
+
     histo.sort();
     histo.print_on(st);
   } else {
--- a/src/share/vm/memory/heapInspection.hpp	Wed May 22 07:30:15 2013 +0200
+++ b/src/share/vm/memory/heapInspection.hpp	Thu May 23 08:14:09 2013 +0200
@@ -26,6 +26,7 @@
 #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP
 
 #include "memory/allocation.inline.hpp"
+#include "memory/klassInfoClosure.hpp"
 #include "oops/oop.inline.hpp"
 
 
@@ -64,12 +65,6 @@
   void print_on(outputStream* st) const;
 };
 
-class KlassInfoClosure: public StackObj {
- public:
-  // Called for each KlassInfoEntry.
-  virtual void do_cinfo(KlassInfoEntry* cie) = 0;
-};
-
 class KlassInfoBucket: public CHeapObj<mtInternal> {
  private:
   KlassInfoEntry* _list;
@@ -86,6 +81,7 @@
  private:
   int _size;
   static const int _num_buckets = 20011;
+  size_t _size_of_instances_in_words;
 
   // An aligned reference address (typically the least
   // address in the perm gen) used for hashing klass
@@ -102,6 +98,7 @@
   bool record_instance(const oop obj);
   void iterate(KlassInfoClosure* cic);
   bool allocation_failed() { return _buckets == NULL; }
+  size_t size_of_instances_in_words() const;
 };
 
 class KlassInfoHisto : public StackObj {
@@ -125,10 +122,9 @@
 class HeapInspection : public AllStatic {
  public:
   static void heap_inspection(outputStream* st, bool need_prologue);
-  static size_t instance_inspection(KlassInfoTable* cit,
-                                    KlassInfoClosure* cl,
-                                    bool need_prologue,
-                                    BoolObjectClosure* filter = NULL);
+  static size_t populate_table(KlassInfoTable* cit,
+                               bool need_prologue,
+                               BoolObjectClosure* filter = NULL);
   static HeapWord* start_of_perm_gen();
   static void find_instances_at_safepoint(klassOop k, GrowableArray<oop>* result);
  private:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/memory/klassInfoClosure.hpp	Thu May 23 08:14:09 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ */
+
+#ifndef SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
+#define SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
+
+class KlassInfoEntry;
+
+class KlassInfoClosure : public StackObj {
+ public:
+  // Called for each KlassInfoEntry.
+  virtual void do_cinfo(KlassInfoEntry* cie) = 0;
+};
+
+#endif // SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
--- a/src/share/vm/runtime/globals.hpp	Wed May 22 07:30:15 2013 +0200
+++ b/src/share/vm/runtime/globals.hpp	Thu May 23 08:14:09 2013 +0200
@@ -2302,6 +2302,10 @@
           "Print diagnostic message when GC is stalled"                     \
           "by JNI critical section")                                        \
                                                                             \
+  experimental(double, ObjectCountCutOffPercent, 0.5,                       \
+          "The percentage of the used heap that the instances of a class "  \
+          "must occupy for the class to generate a trace event.")           \
+                                                                            \
   /* GC log rotation setting */                                             \
                                                                             \
   product(bool, UseGCLogFileRotation, false,                                \