1 /*
   2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 // a simple flat profiler for Java
  26 
  27 
  28 // Forward declaration of classes defined in this header file
  29 class ThreadProfiler;
  30 class ThreadProfilerMark;
  31 class FlatProfiler;
  32 class IntervalData;
  33 
  34 // Declarations of classes defined only in the implementation.
  35 class ProfilerNode;
  36 class FlatProfilerTask;
  37 
  38 enum TickPosition {
  39   tp_code,
  40   tp_native
  41 };
  42 
  43 // One of these guys is constructed as we enter interesting regions
  44 // and destructed as we exit the region.  While we are in the region
  45 // ticks are allotted to the region.
  46 class ThreadProfilerMark: public StackObj {
  47 public:
  48   // For now, the only thread-specific region is the class loader.
  49   enum Region { noRegion, classLoaderRegion, extraRegion, maxRegion };
  50 
  51   ThreadProfilerMark(Region)  KERNEL_RETURN;
  52   ~ThreadProfilerMark()       KERNEL_RETURN;
  53 
  54 private:
  55   ThreadProfiler* _pp;
  56   Region _r;
  57 };
  58 
  59 #ifndef FPROF_KERNEL
  60 
  61 class IntervalData VALUE_OBJ_CLASS_SPEC {
  62   // Just to keep these things all together
  63 private:
  64   int _interpreted;
  65   int _compiled;
  66   int _native;
  67   int _compiling;
  68 public:
  69   int interpreted() {
  70     return _interpreted;
  71   }
  72   int compiled() {
  73     return _compiled;
  74   }
  75   int native() {
  76     return _native;
  77   }
  78   int compiling() {
  79     return _compiling;
  80   }
  81   int total() {
  82     return (interpreted() + compiled() + native() + compiling());
  83   }
  84   void inc_interpreted() {
  85     _interpreted += 1;
  86   }
  87   void inc_compiled() {
  88     _compiled += 1;
  89   }
  90   void inc_native() {
  91     _native += 1;
  92   }
  93   void inc_compiling() {
  94     _compiling += 1;
  95   }
  96   void reset() {
  97     _interpreted = 0;
  98     _compiled = 0;
  99     _native = 0;
 100     _compiling = 0;
 101   }
 102   static void print_header(outputStream* st);
 103   void print_data(outputStream* st);
 104 };
 105 #endif // FPROF_KERNEL
 106 
 107 class ThreadProfiler: public CHeapObj {
 108 public:
 109   ThreadProfiler()    KERNEL_RETURN;
 110   ~ThreadProfiler()   KERNEL_RETURN;
 111 
 112   // Resets the profiler
 113   void reset()        KERNEL_RETURN;
 114 
 115   // Activates the profiler for a certain thread
 116   void engage()       KERNEL_RETURN;
 117 
 118   // Deactivates the profiler
 119   void disengage()    KERNEL_RETURN;
 120 
 121   // Prints the collected profiling information
 122   void print(const char* thread_name) KERNEL_RETURN;
 123 
 124   // Garbage Collection Support
 125   void oops_do(OopClosure* f)         KERNEL_RETURN;
 126 
 127 #ifndef FPROF_KERNEL
 128 private:
 129   // for recording ticks.
 130   friend class ProfilerNode;
 131   char* area_bottom; // preallocated area for pnodes
 132   char* area_top;
 133   char* area_limit;
 134   static int            table_size;
 135   ProfilerNode** table;
 136 
 137 private:
 138   void record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks);
 139   void record_compiled_tick   (JavaThread* thread, frame fr, TickPosition where);
 140   void interpreted_update(methodOop method, TickPosition where);
 141   void compiled_update   (methodOop method, TickPosition where);
 142   void stub_update       (methodOop method, const char* name, TickPosition where);
 143   void adapter_update    (TickPosition where);
 144 
 145   void runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where);
 146   void unknown_compiled_update    (const CodeBlob* cb, TickPosition where);
 147 
 148   void vm_update    (TickPosition where);
 149   void vm_update    (const char* name, TickPosition where);
 150 
 151   void record_tick_for_running_frame(JavaThread* thread, frame fr);
 152   void record_tick_for_calling_frame(JavaThread* thread, frame fr);
 153 
 154   void initialize();
 155 
 156   static int  entry(int value);
 157 
 158 
 159 private:
 160   friend class FlatProfiler;
 161   void record_tick(JavaThread* thread);
 162   bool engaged;
 163   // so we can do percentages for this thread, and quick checks for activity
 164   int thread_ticks;
 165   int compiler_ticks;
 166   int interpreter_ticks;
 167 
 168 public:
 169   void inc_thread_ticks() { thread_ticks += 1; }
 170 
 171 private:
 172   friend class ThreadProfilerMark;
 173   // counters for thread-specific regions
 174   bool region_flag[ThreadProfilerMark::maxRegion];
 175   int class_loader_ticks;
 176   int extra_ticks;
 177 
 178 private:
 179   // other thread-specific regions
 180   int blocked_ticks;
 181   enum UnknownTickSites {
 182       ut_null_method,
 183       ut_vtable_stubs,
 184       ut_running_frame,
 185       ut_calling_frame,
 186       ut_no_pc,
 187       ut_no_last_Java_frame,
 188       ut_unknown_thread_state,
 189       ut_end
 190   };
 191   int unknown_ticks_array[ut_end];
 192   int unknown_ticks() {
 193     int result = 0;
 194     for (int ut = 0; ut < ut_end; ut += 1) {
 195       result += unknown_ticks_array[ut];
 196     }
 197     return result;
 198   }
 199 
 200   elapsedTimer timer;
 201 
 202   // For interval timing
 203 private:
 204   IntervalData _interval_data;
 205   IntervalData interval_data() {
 206     return _interval_data;
 207   }
 208   IntervalData* interval_data_ref() {
 209     return &_interval_data;
 210   }
 211 #endif // FPROF_KERNEL
 212 };
 213 
 214 class FlatProfiler: AllStatic {
 215 public:
 216   static void reset() KERNEL_RETURN ;
 217   static void engage(JavaThread* mainThread, bool fullProfile) KERNEL_RETURN ;
 218   static void disengage() KERNEL_RETURN ;
 219   static void print(int unused) KERNEL_RETURN ;
 220   static bool is_active() KERNEL_RETURN_(return false;) ;
 221 
 222   // This is NULL if each thread has its own thread profiler,
 223   // else this is the single thread profiler used by all threads.
 224   // In particular it makes a difference during garbage collection,
 225   // where you only want to traverse each thread profiler once.
 226   static ThreadProfiler* get_thread_profiler() KERNEL_RETURN_(return NULL;);
 227 
 228   // Garbage Collection Support
 229   static void oops_do(OopClosure* f) KERNEL_RETURN ;
 230 
 231   // Support for disassembler to inspect the PCRecorder
 232 
 233   // Returns the start address for a given pc
 234   // NULL is returned if the PCRecorder is inactive
 235   static address bucket_start_for(address pc) KERNEL_RETURN_(return NULL;);
 236 
 237   enum { MillisecsPerTick = 10 };   // ms per profiling ticks
 238 
 239   // Returns the number of ticks recorded for the bucket
 240   // pc belongs to.
 241   static int bucket_count_for(address pc) KERNEL_RETURN_(return 0;);
 242 
 243 #ifndef FPROF_KERNEL
 244 
 245  private:
 246   static bool full_profile() {
 247     return full_profile_flag;
 248   }
 249 
 250   friend class ThreadProfiler;
 251   // the following group of ticks cover everything that's not attributed to individual Java methods
 252   static int  received_gc_ticks;      // ticks during which gc was active
 253   static int vm_operation_ticks;      // total ticks in vm_operations other than GC
 254   static int threads_lock_ticks;      // the number of times we couldn't get the Threads_lock without blocking
 255   static int      blocked_ticks;      // ticks when the thread was blocked.
 256   static int class_loader_ticks;      // total ticks in class loader
 257   static int        extra_ticks;      // total ticks an extra temporary measuring
 258   static int     compiler_ticks;      // total ticks in compilation
 259   static int  interpreter_ticks;      // ticks in unknown interpreted method
 260   static int        deopt_ticks;      // ticks in deoptimization
 261   static int      unknown_ticks;      // ticks that cannot be categorized
 262   static int     received_ticks;      // ticks that were received by task
 263   static int    delivered_ticks;      // ticks that were delivered by task
 264   static int non_method_ticks() {
 265     return
 266       ( received_gc_ticks
 267       + vm_operation_ticks
 268       + deopt_ticks
 269       + threads_lock_ticks
 270       + blocked_ticks
 271       + compiler_ticks
 272       + interpreter_ticks
 273       + unknown_ticks );
 274   }
 275   static elapsedTimer timer;
 276 
 277   // Counts of each of the byte codes
 278   static int*           bytecode_ticks;
 279   static int*           bytecode_ticks_stub;
 280   static void print_byte_code_statistics();
 281 
 282   // the ticks below are for continuous profiling (to adjust recompilation, etc.)
 283   static int          all_ticks;      // total count of ticks received so far
 284   static int      all_int_ticks;      // ticks in interpreter
 285   static int     all_comp_ticks;      // ticks in compiled code (+ native)
 286   static bool full_profile_flag;      // collecting full profile?
 287 
 288   // to accumulate thread-specific data
 289   // if we aren't profiling individual threads.
 290   static ThreadProfiler* thread_profiler;
 291   static ThreadProfiler* vm_thread_profiler;
 292 
 293   static void allocate_table();
 294 
 295   // The task that periodically interrupts things.
 296   friend class FlatProfilerTask;
 297   static FlatProfilerTask* task;
 298   static void record_vm_operation();
 299   static void record_vm_tick();
 300   static void record_thread_ticks();
 301 
 302   // For interval analysis
 303  private:
 304   static int interval_ticks_previous;  // delivered_ticks from the last interval
 305   static void interval_record_thread(ThreadProfiler* tp); // extract ticks from ThreadProfiler.
 306   static void interval_print();       // print interval data.
 307   static void interval_reset();       // reset interval data.
 308   enum {interval_print_size = 10};
 309   static IntervalData* interval_data;
 310 #endif // FPROF_KERNEL
 311 };