aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #ifndef SHARE_VM_RUNTIME_FPROFILER_HPP aoqi@0: #define SHARE_VM_RUNTIME_FPROFILER_HPP aoqi@0: aoqi@0: #include "utilities/macros.hpp" aoqi@0: #include "runtime/timer.hpp" aoqi@0: aoqi@0: // a simple flat profiler for Java aoqi@0: aoqi@0: aoqi@0: // Forward declaration of classes defined in this header file aoqi@0: class ThreadProfiler; aoqi@0: class ThreadProfilerMark; aoqi@0: class FlatProfiler; aoqi@0: class IntervalData; aoqi@0: aoqi@0: // Declarations of classes defined only in the implementation. aoqi@0: class ProfilerNode; aoqi@0: class FlatProfilerTask; aoqi@0: aoqi@0: enum TickPosition { aoqi@0: tp_code, aoqi@0: tp_native aoqi@0: }; aoqi@0: aoqi@0: // One of these guys is constructed as we enter interesting regions aoqi@0: // and destructed as we exit the region. While we are in the region aoqi@0: // ticks are allotted to the region. aoqi@0: class ThreadProfilerMark: public StackObj { aoqi@0: public: aoqi@0: // For now, the only thread-specific region is the class loader. aoqi@0: enum Region { noRegion, classLoaderRegion, extraRegion, maxRegion }; aoqi@0: aoqi@0: ThreadProfilerMark(Region) NOT_FPROF_RETURN; aoqi@0: ~ThreadProfilerMark() NOT_FPROF_RETURN; aoqi@0: aoqi@0: private: aoqi@0: ThreadProfiler* _pp; aoqi@0: Region _r; aoqi@0: }; aoqi@0: aoqi@0: #if INCLUDE_FPROF aoqi@0: aoqi@0: class IntervalData VALUE_OBJ_CLASS_SPEC { aoqi@0: // Just to keep these things all together aoqi@0: private: aoqi@0: int _interpreted; aoqi@0: int _compiled; aoqi@0: int _native; aoqi@0: int _compiling; aoqi@0: public: aoqi@0: int interpreted() { aoqi@0: return _interpreted; aoqi@0: } aoqi@0: int compiled() { aoqi@0: return _compiled; aoqi@0: } aoqi@0: int native() { aoqi@0: return _native; aoqi@0: } aoqi@0: int compiling() { aoqi@0: return _compiling; aoqi@0: } aoqi@0: int total() { aoqi@0: return (interpreted() + compiled() + native() + compiling()); aoqi@0: } aoqi@0: void inc_interpreted() { aoqi@0: _interpreted += 1; aoqi@0: } aoqi@0: void inc_compiled() { aoqi@0: _compiled += 1; aoqi@0: } aoqi@0: void inc_native() { aoqi@0: _native += 1; aoqi@0: } aoqi@0: void inc_compiling() { aoqi@0: _compiling += 1; aoqi@0: } aoqi@0: void reset() { aoqi@0: _interpreted = 0; aoqi@0: _compiled = 0; aoqi@0: _native = 0; aoqi@0: _compiling = 0; aoqi@0: } aoqi@0: static void print_header(outputStream* st); aoqi@0: void print_data(outputStream* st); aoqi@0: }; aoqi@0: #endif // INCLUDE_FPROF aoqi@0: aoqi@0: class ThreadProfiler: public CHeapObj { aoqi@0: public: aoqi@0: ThreadProfiler() NOT_FPROF_RETURN; aoqi@0: ~ThreadProfiler() NOT_FPROF_RETURN; aoqi@0: aoqi@0: // Resets the profiler aoqi@0: void reset() NOT_FPROF_RETURN; aoqi@0: aoqi@0: // Activates the profiler for a certain thread aoqi@0: void engage() NOT_FPROF_RETURN; aoqi@0: aoqi@0: // Deactivates the profiler aoqi@0: void disengage() NOT_FPROF_RETURN; aoqi@0: aoqi@0: // Prints the collected profiling information aoqi@0: void print(const char* thread_name) NOT_FPROF_RETURN; aoqi@0: aoqi@0: // Garbage Collection Support aoqi@0: void oops_do(OopClosure* f) NOT_FPROF_RETURN; aoqi@0: aoqi@0: #if INCLUDE_FPROF aoqi@0: private: aoqi@0: // for recording ticks. aoqi@0: friend class ProfilerNode; aoqi@0: char* area_bottom; // preallocated area for pnodes aoqi@0: char* area_top; aoqi@0: char* area_limit; aoqi@0: static int table_size; aoqi@0: ProfilerNode** table; aoqi@0: aoqi@0: private: aoqi@0: void record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks); aoqi@0: void record_compiled_tick (JavaThread* thread, frame fr, TickPosition where); aoqi@0: void interpreted_update(Method* method, TickPosition where); aoqi@0: void compiled_update (Method* method, TickPosition where); aoqi@0: void stub_update (Method* method, const char* name, TickPosition where); aoqi@0: void adapter_update (TickPosition where); aoqi@0: aoqi@0: void runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where); aoqi@0: void unknown_compiled_update (const CodeBlob* cb, TickPosition where); aoqi@0: aoqi@0: void vm_update (TickPosition where); aoqi@0: void vm_update (const char* name, TickPosition where); aoqi@0: aoqi@0: void record_tick_for_running_frame(JavaThread* thread, frame fr); aoqi@0: void record_tick_for_calling_frame(JavaThread* thread, frame fr); aoqi@0: aoqi@0: void initialize(); aoqi@0: aoqi@0: static int entry(int value); aoqi@0: aoqi@0: aoqi@0: private: aoqi@0: friend class FlatProfiler; aoqi@0: void record_tick(JavaThread* thread); aoqi@0: bool engaged; aoqi@0: // so we can do percentages for this thread, and quick checks for activity aoqi@0: int thread_ticks; aoqi@0: int compiler_ticks; aoqi@0: int interpreter_ticks; aoqi@0: aoqi@0: public: aoqi@0: void inc_thread_ticks() { thread_ticks += 1; } aoqi@0: aoqi@0: private: aoqi@0: friend class ThreadProfilerMark; aoqi@0: // counters for thread-specific regions aoqi@0: bool region_flag[ThreadProfilerMark::maxRegion]; aoqi@0: int class_loader_ticks; aoqi@0: int extra_ticks; aoqi@0: aoqi@0: private: aoqi@0: // other thread-specific regions aoqi@0: int blocked_ticks; aoqi@0: enum UnknownTickSites { aoqi@0: ut_null_method, aoqi@0: ut_vtable_stubs, aoqi@0: ut_running_frame, aoqi@0: ut_calling_frame, aoqi@0: ut_no_pc, aoqi@0: ut_no_last_Java_frame, aoqi@0: ut_unknown_thread_state, aoqi@0: ut_end aoqi@0: }; aoqi@0: int unknown_ticks_array[ut_end]; aoqi@0: int unknown_ticks() { aoqi@0: int result = 0; aoqi@0: for (int ut = 0; ut < ut_end; ut += 1) { aoqi@0: result += unknown_ticks_array[ut]; aoqi@0: } aoqi@0: return result; aoqi@0: } aoqi@0: aoqi@0: elapsedTimer timer; aoqi@0: aoqi@0: // For interval timing aoqi@0: private: aoqi@0: IntervalData _interval_data; aoqi@0: IntervalData interval_data() { aoqi@0: return _interval_data; aoqi@0: } aoqi@0: IntervalData* interval_data_ref() { aoqi@0: return &_interval_data; aoqi@0: } aoqi@0: #endif // INCLUDE_FPROF aoqi@0: }; aoqi@0: aoqi@0: class FlatProfiler: AllStatic { aoqi@0: public: aoqi@0: static void reset() NOT_FPROF_RETURN ; aoqi@0: static void engage(JavaThread* mainThread, bool fullProfile) NOT_FPROF_RETURN ; aoqi@0: static void disengage() NOT_FPROF_RETURN ; aoqi@0: static void print(int unused) NOT_FPROF_RETURN ; aoqi@0: static bool is_active() NOT_FPROF_RETURN_(false) ; aoqi@0: aoqi@0: // This is NULL if each thread has its own thread profiler, aoqi@0: // else this is the single thread profiler used by all threads. aoqi@0: // In particular it makes a difference during garbage collection, aoqi@0: // where you only want to traverse each thread profiler once. aoqi@0: static ThreadProfiler* get_thread_profiler() NOT_FPROF_RETURN_(NULL); aoqi@0: aoqi@0: // Garbage Collection Support aoqi@0: static void oops_do(OopClosure* f) NOT_FPROF_RETURN ; aoqi@0: aoqi@0: // Support for disassembler to inspect the PCRecorder aoqi@0: aoqi@0: // Returns the start address for a given pc aoqi@0: // NULL is returned if the PCRecorder is inactive aoqi@0: static address bucket_start_for(address pc) NOT_FPROF_RETURN_(NULL); aoqi@0: aoqi@0: enum { MillisecsPerTick = 10 }; // ms per profiling ticks aoqi@0: aoqi@0: // Returns the number of ticks recorded for the bucket aoqi@0: // pc belongs to. aoqi@0: static int bucket_count_for(address pc) NOT_FPROF_RETURN_(0); aoqi@0: aoqi@0: #if INCLUDE_FPROF aoqi@0: aoqi@0: private: aoqi@0: static bool full_profile() { aoqi@0: return full_profile_flag; aoqi@0: } aoqi@0: aoqi@0: friend class ThreadProfiler; aoqi@0: // the following group of ticks cover everything that's not attributed to individual Java methods aoqi@0: static int received_gc_ticks; // ticks during which gc was active aoqi@0: static int vm_operation_ticks; // total ticks in vm_operations other than GC aoqi@0: static int threads_lock_ticks; // the number of times we couldn't get the Threads_lock without blocking aoqi@0: static int blocked_ticks; // ticks when the thread was blocked. aoqi@0: static int class_loader_ticks; // total ticks in class loader aoqi@0: static int extra_ticks; // total ticks an extra temporary measuring aoqi@0: static int compiler_ticks; // total ticks in compilation aoqi@0: static int interpreter_ticks; // ticks in unknown interpreted method aoqi@0: static int deopt_ticks; // ticks in deoptimization aoqi@0: static int unknown_ticks; // ticks that cannot be categorized aoqi@0: static int received_ticks; // ticks that were received by task aoqi@0: static int delivered_ticks; // ticks that were delivered by task aoqi@0: static int non_method_ticks() { aoqi@0: return aoqi@0: ( received_gc_ticks aoqi@0: + vm_operation_ticks aoqi@0: + deopt_ticks aoqi@0: + threads_lock_ticks aoqi@0: + blocked_ticks aoqi@0: + compiler_ticks aoqi@0: + interpreter_ticks aoqi@0: + unknown_ticks ); aoqi@0: } aoqi@0: static elapsedTimer timer; aoqi@0: aoqi@0: // Counts of each of the byte codes aoqi@0: static int* bytecode_ticks; aoqi@0: static int* bytecode_ticks_stub; aoqi@0: static void print_byte_code_statistics(); aoqi@0: aoqi@0: // the ticks below are for continuous profiling (to adjust recompilation, etc.) aoqi@0: static int all_ticks; // total count of ticks received so far aoqi@0: static int all_int_ticks; // ticks in interpreter aoqi@0: static int all_comp_ticks; // ticks in compiled code (+ native) aoqi@0: static bool full_profile_flag; // collecting full profile? aoqi@0: aoqi@0: // to accumulate thread-specific data aoqi@0: // if we aren't profiling individual threads. aoqi@0: static ThreadProfiler* thread_profiler; aoqi@0: static ThreadProfiler* vm_thread_profiler; aoqi@0: aoqi@0: static void allocate_table(); aoqi@0: aoqi@0: // The task that periodically interrupts things. aoqi@0: friend class FlatProfilerTask; aoqi@0: static FlatProfilerTask* task; aoqi@0: static void record_vm_operation(); aoqi@0: static void record_vm_tick(); aoqi@0: static void record_thread_ticks(); aoqi@0: aoqi@0: // For interval analysis aoqi@0: private: aoqi@0: static int interval_ticks_previous; // delivered_ticks from the last interval aoqi@0: static void interval_record_thread(ThreadProfiler* tp); // extract ticks from ThreadProfiler. aoqi@0: static void interval_print(); // print interval data. aoqi@0: static void interval_reset(); // reset interval data. aoqi@0: enum {interval_print_size = 10}; aoqi@0: static IntervalData* interval_data; aoqi@0: #endif // INCLUDE_FPROF aoqi@0: }; aoqi@0: aoqi@0: #endif // SHARE_VM_RUNTIME_FPROFILER_HPP