diff src/share/vm/classfile/classLoader.hpp @ 875:6a93908f268f

6857194: Add hotspot perf counters to aid class loading performance measurement Summary: Add new jvmstat counters to measure detailed class loading time Reviewed-by: acorn, kamg
author mchung
date Fri, 10 Jul 2009 11:10:00 -0700
parents a61af66fc99e
children 89e0543e1737
line wrap: on
line diff
--- a/src/share/vm/classfile/classLoader.hpp	Fri Jun 19 07:33:25 2009 -0700
+++ b/src/share/vm/classfile/classLoader.hpp	Fri Jul 10 11:10:00 2009 -0700
@@ -149,9 +149,26 @@
   static PerfCounter* _perf_accumulated_time;
   static PerfCounter* _perf_classes_inited;
   static PerfCounter* _perf_class_init_time;
+  static PerfCounter* _perf_class_init_selftime;
+  static PerfCounter* _perf_classes_verified;
   static PerfCounter* _perf_class_verify_time;
+  static PerfCounter* _perf_class_verify_selftime;
   static PerfCounter* _perf_classes_linked;
   static PerfCounter* _perf_class_link_time;
+  static PerfCounter* _perf_class_link_selftime;
+  static PerfCounter* _perf_class_parse_time;
+  static PerfCounter* _perf_class_parse_selftime;
+  static PerfCounter* _perf_sys_class_lookup_time;
+  static PerfCounter* _perf_shared_classload_time;
+  static PerfCounter* _perf_sys_classload_time;
+  static PerfCounter* _perf_app_classload_time;
+  static PerfCounter* _perf_app_classload_selftime;
+  static PerfCounter* _perf_app_classload_count;
+  static PerfCounter* _perf_define_appclasses;
+  static PerfCounter* _perf_define_appclass_time;
+  static PerfCounter* _perf_define_appclass_selftime;
+  static PerfCounter* _perf_app_classfile_bytes_read;
+  static PerfCounter* _perf_sys_classfile_bytes_read;
 
   static PerfCounter* _sync_systemLoaderLockContentionRate;
   static PerfCounter* _sync_nonSystemLoaderLockContentionRate;
@@ -196,12 +213,29 @@
   static void print_bootclasspath();
 
   // Timing
-  static PerfCounter* perf_accumulated_time()  { return _perf_accumulated_time; }
-  static PerfCounter* perf_classes_inited()    { return _perf_classes_inited; }
-  static PerfCounter* perf_class_init_time()   { return _perf_class_init_time; }
-  static PerfCounter* perf_class_verify_time() { return _perf_class_verify_time; }
-  static PerfCounter* perf_classes_linked()    { return _perf_classes_linked; }
-  static PerfCounter* perf_class_link_time() { return _perf_class_link_time; }
+  static PerfCounter* perf_accumulated_time()         { return _perf_accumulated_time; }
+  static PerfCounter* perf_classes_inited()           { return _perf_classes_inited; }
+  static PerfCounter* perf_class_init_time()          { return _perf_class_init_time; }
+  static PerfCounter* perf_class_init_selftime()      { return _perf_class_init_selftime; }
+  static PerfCounter* perf_classes_verified()         { return _perf_classes_verified; }
+  static PerfCounter* perf_class_verify_time()        { return _perf_class_verify_time; }
+  static PerfCounter* perf_class_verify_selftime()    { return _perf_class_verify_selftime; }
+  static PerfCounter* perf_classes_linked()           { return _perf_classes_linked; }
+  static PerfCounter* perf_class_link_time()          { return _perf_class_link_time; }
+  static PerfCounter* perf_class_link_selftime()      { return _perf_class_link_selftime; }
+  static PerfCounter* perf_class_parse_time()         { return _perf_class_parse_time; }
+  static PerfCounter* perf_class_parse_selftime()     { return _perf_class_parse_selftime; }
+  static PerfCounter* perf_sys_class_lookup_time()    { return _perf_sys_class_lookup_time; }
+  static PerfCounter* perf_shared_classload_time()    { return _perf_shared_classload_time; }
+  static PerfCounter* perf_sys_classload_time()       { return _perf_sys_classload_time; }
+  static PerfCounter* perf_app_classload_time()       { return _perf_app_classload_time; }
+  static PerfCounter* perf_app_classload_selftime()   { return _perf_app_classload_selftime; }
+  static PerfCounter* perf_app_classload_count()      { return _perf_app_classload_count; }
+  static PerfCounter* perf_define_appclasses()        { return _perf_define_appclasses; }
+  static PerfCounter* perf_define_appclass_time()     { return _perf_define_appclass_time; }
+  static PerfCounter* perf_define_appclass_selftime() { return _perf_define_appclass_selftime; }
+  static PerfCounter* perf_app_classfile_bytes_read() { return _perf_app_classfile_bytes_read; }
+  static PerfCounter* perf_sys_classfile_bytes_read() { return _perf_sys_classfile_bytes_read; }
 
   // Record how often system loader lock object is contended
   static PerfCounter* sync_systemLoaderLockContentionRate() {
@@ -307,3 +341,118 @@
   static int  compile_the_world_counter() { return _compile_the_world_counter; }
 #endif //PRODUCT
 };
+
+// PerfClassTraceTime is used to measure time for class loading related events.
+// This class tracks cumulative time and exclusive time for specific event types.
+// During the execution of one event, other event types (e.g. class loading and
+// resolution) as well as recursive calls of the same event type could happen.
+// Only one elapsed timer (cumulative) and one thread-local self timer (exclusive)
+// (i.e. only one event type) are active at a time even multiple PerfClassTraceTime
+// instances have been created as multiple events are happening.
+class PerfClassTraceTime {
+  public:
+    enum {
+       CLASS_LOAD   = 0,
+       PARSE_CLASS  = 1,
+       CLASS_LINK   = 2,
+       CLASS_VERIFY = 3,
+       CLASS_CLINIT = 4,
+       DEFINE_CLASS = 5,
+       EVENT_TYPE_COUNT = 6
+    };
+  protected:
+    // _t tracks time from initialization to destruction of this timer instance
+    // including time for all other event types, and recursive calls of this type.
+    // When a timer is called recursively, the elapsedTimer _t would not be used.
+    elapsedTimer     _t;
+    PerfLongCounter* _timep;
+    PerfLongCounter* _selftimep;
+    PerfLongCounter* _eventp;
+    // pointer to thread-local recursion counter and timer array
+    // The thread_local timers track cumulative time for specific event types
+    // exclusive of time for other event types, but including recursive calls
+    // of the same type.
+    int*             _recursion_counters;
+    elapsedTimer*    _timers;
+    int              _event_type;
+    int              _prev_active_event;
+
+  public:
+
+    inline PerfClassTraceTime(PerfLongCounter* timep,     /* counter incremented with inclusive time */
+                              PerfLongCounter* selftimep, /* counter incremented with exclusive time */
+                              PerfLongCounter* eventp,    /* event counter */
+                              int* recursion_counters,    /* thread-local recursion counter array */
+                              elapsedTimer* timers,       /* thread-local timer array */
+                              int type                    /* event type */ ) :
+        _timep(timep), _selftimep(selftimep), _eventp(eventp), _recursion_counters(recursion_counters), _timers(timers), _event_type(type) {
+      initialize();
+    }
+
+    inline PerfClassTraceTime(PerfLongCounter* timep,     /* counter incremented with inclusive time */
+                              elapsedTimer* timers,       /* thread-local timer array */
+                              int type                    /* event type */ ) :
+        _timep(timep), _selftimep(NULL), _eventp(NULL), _recursion_counters(NULL), _timers(timers), _event_type(type) {
+      initialize();
+    }
+
+    void initialize() {
+      if (!UsePerfData) return;
+
+      if (_eventp != NULL) {
+        // increment the event counter
+        _eventp->inc();
+      }
+
+      // stop the current active thread-local timer to measure inclusive time
+      _prev_active_event = -1;
+      for (int i=0; i < EVENT_TYPE_COUNT; i++) {
+         if (_timers[i].is_active()) {
+           assert(_prev_active_event == -1, "should have only one active timer");
+           _prev_active_event = i;
+           _timers[i].stop();
+         }
+      }
+
+      if (_recursion_counters == NULL || (_recursion_counters[_event_type])++ == 0) {
+        // start the inclusive timer if not recursively called
+        _t.start();
+      }
+
+      // start thread-local timer of the given event type
+      if (!_timers[_event_type].is_active()) {
+        _timers[_event_type].start();
+      }
+    }
+
+    inline void suspend() { _t.stop(); _timers[_event_type].stop(); }
+    inline void resume()  { _t.start(); _timers[_event_type].start(); }
+
+    ~PerfClassTraceTime() {
+      if (!UsePerfData) return;
+
+      // stop the thread-local timer as the event completes
+      // and resume the thread-local timer of the event next on the stack
+      _timers[_event_type].stop();
+      jlong selftime = _timers[_event_type].ticks();
+
+      if (_prev_active_event >= 0) {
+        _timers[_prev_active_event].start();
+      }
+
+      if (_recursion_counters != NULL && --(_recursion_counters[_event_type]) > 0) return;
+
+      // increment the counters only on the leaf call
+      _t.stop();
+      _timep->inc(_t.ticks());
+      if (_selftimep != NULL) {
+        _selftimep->inc(selftime);
+      }
+      // add all class loading related event selftime to the accumulated time counter
+      ClassLoader::perf_accumulated_time()->inc(selftime);
+
+      // reset the timer
+      _timers[_event_type].reset();
+    }
+};
+