changeset 4614:04f81958a8e2

8012182: Add information about class loading and unloading to event based tracing framework Reviewed-by: coleenp, dholmes, sspitsyn Contributed-by: calvin.cheung@oracle.com
author mgronlun
date Thu, 18 Apr 2013 17:46:34 +0200
parents be693a09e7f5
children 0e9dba751d8b
files src/share/vm/classfile/systemDictionary.cpp src/share/vm/classfile/systemDictionary.hpp src/share/vm/gc_implementation/shared/gcTraceSend.cpp src/share/vm/runtime/objectMonitor.cpp src/share/vm/trace/trace.xml src/share/vm/trace/traceBackend.hpp src/share/vm/trace/traceEvent.hpp src/share/vm/trace/traceEventClasses.xsl src/share/vm/trace/traceStream.hpp
diffstat 9 files changed, 151 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/systemDictionary.cpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/classfile/systemDictionary.cpp	Thu Apr 18 17:46:34 2013 +0200
@@ -54,7 +54,11 @@
 #include "runtime/signature.hpp"
 #include "services/classLoadingService.hpp"
 #include "services/threadService.hpp"
-#include "trace/traceMacros.hpp"
+
+#if INCLUDE_TRACE
+ #include "memory/iterator.hpp"
+ #include "trace/tracing.hpp"
+#endif
 
 
 Dictionary*            SystemDictionary::_dictionary          = NULL;
@@ -581,6 +585,8 @@
   assert(name != NULL && !FieldType::is_array(name) &&
          !FieldType::is_obj(name), "invalid class name");
 
+  TracingTime class_load_start_time = Tracing::time();
+
   // UseNewReflection
   // Fix for 4474172; see evaluation for more details
   class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
@@ -820,6 +826,7 @@
         }
         return NULL;
       }
+      post_class_load_event(class_load_start_time, k, class_loader);
     }
   }
 
@@ -939,6 +946,8 @@
                                         TRAPS) {
   TempNewSymbol parsed_name = NULL;
 
+  TracingTime class_load_start_time = Tracing::time();
+
   // Parse the stream. Note that we do this even though this klass might
   // already be present in the SystemDictionary, otherwise we would not
   // throw potential ClassFormatErrors.
@@ -996,6 +1005,8 @@
         assert(THREAD->is_Java_thread(), "thread->is_Java_thread()");
         JvmtiExport::post_class_load((JavaThread *) THREAD, k());
     }
+
+    post_class_load_event(class_load_start_time, k, class_loader);
   }
 
   return k();
@@ -1012,7 +1023,6 @@
                                                ClassFileStream* st,
                                                bool verify,
                                                TRAPS) {
-
   // Classloaders that support parallelism, e.g. bootstrap classloader,
   // or all classloaders with UnsyncloadClass do not acquire lock here
   bool DoObjectLock = true;
@@ -1655,6 +1665,7 @@
   return newsize;
 }
 bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive) {
+  post_class_unload_events(is_alive);
   bool result = dictionary()->do_unloading(is_alive);
   constraints()->purge_loader_constraints(is_alive);
   resolution_errors()->purge_resolution_errors(is_alive);
@@ -2601,6 +2612,73 @@
             "Loaded klasses should be in SystemDictionary");
 }
 
+// utility function for posting class load event
+void SystemDictionary::post_class_load_event(TracingTime start_time,
+                                             instanceKlassHandle k,
+                                             Handle initiating_loader) {
+#if INCLUDE_TRACE
+  EventClassLoad event(UNTIMED);
+  if (event.should_commit()) {
+    event.set_endtime(Tracing::time());
+    event.set_starttime(start_time);
+    event.set_loadedClass(k());
+    oop defining_class_loader = k->class_loader();
+    event.set_definingClassLoader(defining_class_loader != NULL ?
+                                  defining_class_loader->klass() : (klassOop)NULL);
+    oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
+    event.set_initiatingClassLoader(class_loader != NULL ?
+                                    class_loader->klass() : (klassOop)NULL);
+    event.commit();
+  }
+#endif /* INCLUDE_TRACE */
+}
+
+void SystemDictionary::post_class_unload_events(BoolObjectClosure* is_alive) {
+#if INCLUDE_TRACE
+  assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
+  if (Tracing::enabled()) {
+    _should_write_unload_events = Tracing::is_event_enabled(TraceClassUnloadEvent);
+    _class_unload_time = Tracing::time();
+    _is_alive = is_alive;
+    classes_do(&class_unload_event);
+
+    if (_no_of_classes_unloading > 0) {
+      Tracing::on_unloading_classes(is_alive, _no_of_classes_unloading);
+      _no_of_classes_unloading = 0;
+    }
+    _should_write_unload_events = false;
+    _is_alive = NULL;
+  }
+#endif /* INCLUDE_TRACE */
+}
+
+#if INCLUDE_TRACE
+
+TracingTime SystemDictionary::_class_unload_time;
+BoolObjectClosure* SystemDictionary::_is_alive = NULL;
+int SystemDictionary::_no_of_classes_unloading = 0;
+bool SystemDictionary::_should_write_unload_events = false;
+
+void SystemDictionary::class_unload_event(klassOop curklass) {
+
+  Klass* myklass = curklass->klass_part();
+  oop class_loader = myklass->class_loader();
+
+  if (class_loader != NULL && _is_alive != NULL && !_is_alive->do_object_b(class_loader)) {
+    _no_of_classes_unloading++;
+    if (_should_write_unload_events) {
+      // post class unload event
+      EventClassUnload event(UNTIMED);
+      event.set_endtime(_class_unload_time);
+      event.set_unloadedClass(curklass);
+      event.set_definingClassLoader(class_loader->klass());
+      event.commit();
+    }
+  }
+}
+
+#endif /* INCLUDE_TRACE */
+
 #ifndef PRODUCT
 
 // statistics code
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Apr 18 17:46:34 2013 +0200
@@ -33,6 +33,7 @@
 #include "runtime/reflectionUtils.hpp"
 #include "utilities/hashtable.hpp"
 #include "utilities/hashtable.inline.hpp"
+#include "trace/traceTime.hpp"
 
 // The system dictionary stores all loaded classes and maps:
 //
@@ -76,6 +77,7 @@
 template <MEMFLAGS F> class HashtableBucket;
 class ResolutionErrorTable;
 class SymbolPropertyTable;
+class BoolObjectClosure;
 
 // Certain classes are preloaded, such as java.lang.Object and java.lang.String.
 // They are all "well-known", in the sense that no class loader is allowed
@@ -613,6 +615,11 @@
   // Setup link to hierarchy
   static void add_to_hierarchy(instanceKlassHandle k, TRAPS);
 
+  // event based tracing
+  static void post_class_load_event(TracingTime start_time, instanceKlassHandle k,
+                                    Handle initiating_loader);
+  static void post_class_unload_events(BoolObjectClosure* is_alive);
+
 private:
   // We pass in the hashtable index so we can calculate it outside of
   // the SystemDictionary_lock.
@@ -669,6 +676,14 @@
 
   static bool _has_loadClassInternal;
   static bool _has_checkPackageAccess;
+
+#if INCLUDE_TRACE
+  static TracingTime _class_unload_time;
+  static BoolObjectClosure* _is_alive;
+  static int _no_of_classes_unloading;
+  static bool _should_write_unload_events;
+  static void class_unload_event(klassOop curklass);
+#endif
 };
 
 class SystemDictionaryHandles : AllStatic {
--- a/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/gc_implementation/shared/gcTraceSend.cpp	Thu Apr 18 17:46:34 2013 +0200
@@ -136,7 +136,7 @@
 
 bool GCTracer::should_send_object_count_after_gc_event() const {
 #if INCLUDE_TRACE
-  return Tracing::enabled(EventObjectCountAfterGC::eventId);
+  return Tracing::is_event_enabled(EventObjectCountAfterGC::eventId);
 #else
   return false;
 #endif
--- a/src/share/vm/runtime/objectMonitor.cpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/runtime/objectMonitor.cpp	Thu Apr 18 17:46:34 2013 +0200
@@ -973,7 +973,7 @@
 #if INCLUDE_TRACE
    // get the owner's thread id for the MonitorEnter event
    // if it is enabled and the thread isn't suspended
-   if (not_suspended && Tracing::enabled(TraceJavaMonitorEnterEvent)) {
+   if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
      _previous_owner_tid = SharedRuntime::get_java_tid(Self);
    }
 #endif
--- a/src/share/vm/trace/trace.xml	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/trace/trace.xml	Thu Apr 18 17:46:34 2013 +0200
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
- Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2012, 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
@@ -109,6 +109,19 @@
       <value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on" relation="JAVA_MONITOR_ADDRESS"/>
     </event>
 
+    <event id="ClassLoad" path="vm/class/load" label="Class Load"
+            has_thread="true" has_stacktrace="true" is_instant="false">
+      <value type="CLASS" field="loadedClass" label="Loaded Class"/>
+      <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+      <value type="CLASS" field="initiatingClassLoader" label="Initiating Class Loader"/>
+    </event>
+
+    <event id="ClassUnload" path="vm/class/unload" label="Class Unload"
+        has_thread="true" is_instant="true">
+      <value type="CLASS" field="unloadedClass" label="Unloaded Class"/>
+      <value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
+    </event>
+
     <struct id="VirtualSpace">
       <value type="ADDRESS" field="start" label="Start Address" description="Start address of the virtual space" />
       <value type="ADDRESS" field="committedEnd" label="Committed End Address" description="End address of the committed memory for the virtual space" />
--- a/src/share/vm/trace/traceBackend.hpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/trace/traceBackend.hpp	Thu Apr 18 17:46:34 2013 +0200
@@ -33,9 +33,12 @@
 
 class TraceBackend {
 public:
-  static bool enabled(TraceEventId id) {
+  static bool enabled(void) {
     return EnableTracing;
   }
+  static bool is_event_enabled(TraceEventId id) {
+    return enabled();
+  }
 
   static TracingTime time() {
     return os::elapsed_counter();
@@ -44,6 +47,9 @@
   static TracingTime time_adjustment(jlong time) {
     return time;
   }
+
+  static void on_unloading_classes(BoolObjectClosure* is_alive, int no_of_classes_unloading) {
+  }
 };
 
 typedef TraceBackend Tracing;
--- a/src/share/vm/trace/traceEvent.hpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/trace/traceEvent.hpp	Thu Apr 18 17:46:34 2013 +0200
@@ -73,7 +73,7 @@
   }
 
   static bool is_enabled() {
-    return Tracing::enabled(T::eventId);
+    return Tracing::is_event_enabled(T::eventId);
   }
 
   bool should_commit() {
--- a/src/share/vm/trace/traceEventClasses.xsl	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/trace/traceEventClasses.xsl	Thu Apr 18 17:46:34 2013 +0200
@@ -37,6 +37,7 @@
 // INCLUDE_TRACE
 
 #include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
 #include "tracefiles/traceTypes.hpp"
 #include "trace/traceEvent.hpp"
 
@@ -130,6 +131,7 @@
   <xsl:value-of select="concat('  Event', @id, '(EventStartTime timing=TIMED) : TraceEvent&lt;Event', @id, '&gt;(timing) {}', $newline)"/>
   void writeEvent(void) {
     ResourceMark rm;
+    HandleMark hm;
     TraceStream ts(*tty);
     ts.print("<xsl:value-of select="@label"/>: [");
 <xsl:apply-templates select="value|structvalue" mode="write-data"/>
--- a/src/share/vm/trace/traceStream.hpp	Fri Feb 08 12:48:24 2013 +0100
+++ b/src/share/vm/trace/traceStream.hpp	Thu Apr 18 17:46:34 2013 +0200
@@ -27,9 +27,11 @@
 
 #if INCLUDE_TRACE
 
+#include "oops/klass.hpp"
+#include "oops/klassOop.hpp"
+#include "oops/methodOop.hpp"
+#include "oops/symbol.hpp"
 #include "utilities/ostream.hpp"
-#include "oops/methodOop.hpp"
-#include "oops/klassOop.hpp"
 
 class TraceStream : public StackObj {
  private:
@@ -78,12 +80,32 @@
     _st.print("%s = %f", label, val);
   }
 
-  void print_val(const char* label, klassOop& val) {
-    _st.print("%s = %s", label, val->print_string());
+  // Caller is machine generated code located in traceEventClasses.hpp
+  // Event<TraceId>::writeEvent() (pseudocode) contains the
+  // necessary ResourceMark for the resource allocations below.
+  // See traceEventClasses.xsl for details.
+  void print_val(const char* label, const klassOop& val) {
+    const char* description = "NULL";
+    if (val != NULL) {
+      Klass* myklass = val->klass_part();
+      Symbol* name = myklass->name();
+      if (name != NULL) {
+        description = name->as_C_string();
+      }
+    }
+    _st.print("%s = %s", label, description);
   }
 
-  void print_val(const char* label, methodOop& val) {
-    _st.print("%s = %s", label, val->name_and_sig_as_C_string());
+  // Caller is machine generated code located in traceEventClasses.hpp
+  // Event<TraceId>::writeEvent() (pseudocode) contains the
+  // necessary ResourceMark for the resource allocations below.
+  // See traceEventClasses.xsl for details.
+  void print_val(const char* label, const methodOop& val) {
+    const char* description = "NULL";
+    if (val != NULL) {
+      description = val->name_and_sig_as_C_string();
+    }
+    _st.print("%s = %s", label, description);
   }
 
   void print_val(const char* label, const char* val) {
@@ -95,5 +117,5 @@
   }
 };
 
-#endif
-#endif
+#endif /* INCLUDE_TRACE */
+#endif /* SHARE_VM_TRACE_TRACESTREAM_HPP */