Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/runtime/fprofiler.cpp
32285 views
/*1* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "classfile/classLoader.hpp"26#include "code/vtableStubs.hpp"27#include "gc_interface/collectedHeap.inline.hpp"28#include "interpreter/interpreter.hpp"29#include "memory/allocation.inline.hpp"30#include "memory/universe.inline.hpp"31#include "oops/oop.inline.hpp"32#include "oops/oop.inline2.hpp"33#include "oops/symbol.hpp"34#include "runtime/deoptimization.hpp"35#include "runtime/fprofiler.hpp"36#include "runtime/mutexLocker.hpp"37#include "runtime/stubCodeGenerator.hpp"38#include "runtime/stubRoutines.hpp"39#include "runtime/task.hpp"40#include "runtime/thread.inline.hpp"41#include "runtime/vframe.hpp"42#include "utilities/macros.hpp"4344PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC4546// Static fields of FlatProfiler47int FlatProfiler::received_gc_ticks = 0;48int FlatProfiler::vm_operation_ticks = 0;49int FlatProfiler::threads_lock_ticks = 0;50int FlatProfiler::class_loader_ticks = 0;51int FlatProfiler::extra_ticks = 0;52int FlatProfiler::blocked_ticks = 0;53int FlatProfiler::deopt_ticks = 0;54int FlatProfiler::unknown_ticks = 0;55int FlatProfiler::interpreter_ticks = 0;56int FlatProfiler::compiler_ticks = 0;57int FlatProfiler::received_ticks = 0;58int FlatProfiler::delivered_ticks = 0;59int* FlatProfiler::bytecode_ticks = NULL;60int* FlatProfiler::bytecode_ticks_stub = NULL;61int FlatProfiler::all_int_ticks = 0;62int FlatProfiler::all_comp_ticks = 0;63int FlatProfiler::all_ticks = 0;64bool FlatProfiler::full_profile_flag = false;65ThreadProfiler* FlatProfiler::thread_profiler = NULL;66ThreadProfiler* FlatProfiler::vm_thread_profiler = NULL;67FlatProfilerTask* FlatProfiler::task = NULL;68elapsedTimer FlatProfiler::timer;69int FlatProfiler::interval_ticks_previous = 0;70IntervalData* FlatProfiler::interval_data = NULL;7172ThreadProfiler::ThreadProfiler() {73// Space for the ProfilerNodes74const int area_size = 1 * ProfilerNodeSize * 1024;75area_bottom = AllocateHeap(area_size, mtInternal);76area_top = area_bottom;77area_limit = area_bottom + area_size;7879// ProfilerNode pointer table80table = NEW_C_HEAP_ARRAY(ProfilerNode*, table_size, mtInternal);81initialize();82engaged = false;83}8485ThreadProfiler::~ThreadProfiler() {86FreeHeap(area_bottom);87area_bottom = NULL;88area_top = NULL;89area_limit = NULL;90FreeHeap(table);91table = NULL;92}9394// Statics for ThreadProfiler95int ThreadProfiler::table_size = 1024;9697int ThreadProfiler::entry(int value) {98value = (value > 0) ? value : -value;99return value % table_size;100}101102ThreadProfilerMark::ThreadProfilerMark(ThreadProfilerMark::Region r) {103_r = r;104_pp = NULL;105assert(((r > ThreadProfilerMark::noRegion) && (r < ThreadProfilerMark::maxRegion)), "ThreadProfilerMark::Region out of bounds");106Thread* tp = Thread::current();107if (tp != NULL && tp->is_Java_thread()) {108JavaThread* jtp = (JavaThread*) tp;109ThreadProfiler* pp = jtp->get_thread_profiler();110_pp = pp;111if (pp != NULL) {112pp->region_flag[r] = true;113}114}115}116117ThreadProfilerMark::~ThreadProfilerMark() {118if (_pp != NULL) {119_pp->region_flag[_r] = false;120}121_pp = NULL;122}123124// Random other statics125static const int col1 = 2; // position of output column 1126static const int col2 = 11; // position of output column 2127static const int col3 = 25; // position of output column 3128static const int col4 = 55; // position of output column 4129130131// Used for detailed profiling of nmethods.132class PCRecorder : AllStatic {133private:134static int* counters;135static address base;136enum {137bucket_size = 16138};139static int index_for(address pc) { return (pc - base)/bucket_size; }140static address pc_for(int index) { return base + (index * bucket_size); }141static int size() {142return ((int)CodeCache::max_capacity())/bucket_size * BytesPerWord;143}144public:145static address bucket_start_for(address pc) {146if (counters == NULL) return NULL;147return pc_for(index_for(pc));148}149static int bucket_count_for(address pc) { return counters[index_for(pc)]; }150static void init();151static void record(address pc);152static void print();153static void print_blobs(CodeBlob* cb);154};155156int* PCRecorder::counters = NULL;157address PCRecorder::base = NULL;158159void PCRecorder::init() {160MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag);161int s = size();162counters = NEW_C_HEAP_ARRAY(int, s, mtInternal);163for (int index = 0; index < s; index++) {164counters[index] = 0;165}166base = CodeCache::first_address();167}168169void PCRecorder::record(address pc) {170if (counters == NULL) return;171assert(CodeCache::contains(pc), "must be in CodeCache");172counters[index_for(pc)]++;173}174175176address FlatProfiler::bucket_start_for(address pc) {177return PCRecorder::bucket_start_for(pc);178}179180int FlatProfiler::bucket_count_for(address pc) {181return PCRecorder::bucket_count_for(pc);182}183184void PCRecorder::print() {185if (counters == NULL) return;186187tty->cr();188tty->print_cr("Printing compiled methods with PC buckets having more than %d ticks", ProfilerPCTickThreshold);189tty->print_cr("===================================================================");190tty->cr();191192GrowableArray<CodeBlob*>* candidates = new GrowableArray<CodeBlob*>(20);193194195int s;196{197MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag);198s = size();199}200201for (int index = 0; index < s; index++) {202int count = counters[index];203if (count > ProfilerPCTickThreshold) {204address pc = pc_for(index);205CodeBlob* cb = CodeCache::find_blob_unsafe(pc);206if (cb != NULL && candidates->find(cb) < 0) {207candidates->push(cb);208}209}210}211for (int i = 0; i < candidates->length(); i++) {212print_blobs(candidates->at(i));213}214}215216void PCRecorder::print_blobs(CodeBlob* cb) {217if (cb != NULL) {218cb->print();219if (cb->is_nmethod()) {220((nmethod*)cb)->print_code();221}222tty->cr();223} else {224tty->print_cr("stub code");225}226}227228class tick_counter { // holds tick info for one node229public:230int ticks_in_code;231int ticks_in_native;232233tick_counter() { ticks_in_code = ticks_in_native = 0; }234tick_counter(int code, int native) { ticks_in_code = code; ticks_in_native = native; }235236int total() const {237return (ticks_in_code + ticks_in_native);238}239240void add(tick_counter* a) {241ticks_in_code += a->ticks_in_code;242ticks_in_native += a->ticks_in_native;243}244245void update(TickPosition where) {246switch(where) {247case tp_code: ticks_in_code++; break;248case tp_native: ticks_in_native++; break;249}250}251252void print_code(outputStream* st, int total_ticks) {253st->print("%5.1f%% %5d ", total() * 100.0 / total_ticks, ticks_in_code);254}255256void print_native(outputStream* st) {257st->print(" + %5d ", ticks_in_native);258}259};260261class ProfilerNode {262private:263ProfilerNode* _next;264public:265tick_counter ticks;266267public:268269void* operator new(size_t size, ThreadProfiler* tp) throw();270void operator delete(void* p);271272ProfilerNode() {273_next = NULL;274}275276virtual ~ProfilerNode() {277if (_next)278delete _next;279}280281void set_next(ProfilerNode* n) { _next = n; }282ProfilerNode* next() { return _next; }283284void update(TickPosition where) { ticks.update(where);}285int total_ticks() { return ticks.total(); }286287virtual bool is_interpreted() const { return false; }288virtual bool is_compiled() const { return false; }289virtual bool is_stub() const { return false; }290virtual bool is_runtime_stub() const{ return false; }291virtual void oops_do(OopClosure* f) = 0;292293virtual bool interpreted_match(Method* m) const { return false; }294virtual bool compiled_match(Method* m ) const { return false; }295virtual bool stub_match(Method* m, const char* name) const { return false; }296virtual bool adapter_match() const { return false; }297virtual bool runtimeStub_match(const CodeBlob* stub, const char* name) const { return false; }298virtual bool unknown_compiled_match(const CodeBlob* cb) const { return false; }299300static void print_title(outputStream* st) {301st->print(" + native");302st->fill_to(col3);303st->print("Method");304st->fill_to(col4);305st->cr();306}307308static void print_total(outputStream* st, tick_counter* t, int total, const char* msg) {309t->print_code(st, total);310st->fill_to(col2);311t->print_native(st);312st->fill_to(col3);313st->print("%s", msg);314st->cr();315}316317virtual Method* method() = 0;318319virtual void print_method_on(outputStream* st) {320int limit;321int i;322Method* m = method();323Symbol* k = m->klass_name();324// Print the class name with dots instead of slashes325limit = k->utf8_length();326for (i = 0 ; i < limit ; i += 1) {327char c = (char) k->byte_at(i);328if (c == '/') {329c = '.';330}331st->print("%c", c);332}333if (limit > 0) {334st->print(".");335}336Symbol* n = m->name();337limit = n->utf8_length();338for (i = 0 ; i < limit ; i += 1) {339char c = (char) n->byte_at(i);340st->print("%c", c);341}342if (Verbose || WizardMode) {343// Disambiguate overloaded methods344Symbol* sig = m->signature();345sig->print_symbol_on(st);346} else if (MethodHandles::is_signature_polymorphic(m->intrinsic_id()))347// compare with Method::print_short_name348MethodHandles::print_as_basic_type_signature_on(st, m->signature(), true);349}350351virtual void print(outputStream* st, int total_ticks) {352ticks.print_code(st, total_ticks);353st->fill_to(col2);354ticks.print_native(st);355st->fill_to(col3);356print_method_on(st);357st->cr();358}359360// for hashing into the table361static int hash(Method* method) {362// The point here is to try to make something fairly unique363// out of the fields we can read without grabbing any locks364// since the method may be locked when we need the hash.365return (366method->code_size() ^367method->max_stack() ^368method->max_locals() ^369method->size_of_parameters());370}371372// for sorting373static int compare(ProfilerNode** a, ProfilerNode** b) {374return (*b)->total_ticks() - (*a)->total_ticks();375}376};377378void* ProfilerNode::operator new(size_t size, ThreadProfiler* tp) throw() {379void* result = (void*) tp->area_top;380tp->area_top += size;381382if (tp->area_top > tp->area_limit) {383fatal("flat profiler buffer overflow");384}385return result;386}387388void ProfilerNode::operator delete(void* p){389}390391class interpretedNode : public ProfilerNode {392private:393Method* _method;394oop _class_loader; // needed to keep metadata for the method alive395public:396interpretedNode(Method* method, TickPosition where) : ProfilerNode() {397_method = method;398_class_loader = method->method_holder()->class_loader();399update(where);400}401402bool is_interpreted() const { return true; }403404bool interpreted_match(Method* m) const {405return _method == m;406}407408void oops_do(OopClosure* f) {409f->do_oop(&_class_loader);410}411412Method* method() { return _method; }413414static void print_title(outputStream* st) {415st->fill_to(col1);416st->print("%11s", "Interpreted");417ProfilerNode::print_title(st);418}419420void print(outputStream* st, int total_ticks) {421ProfilerNode::print(st, total_ticks);422}423424void print_method_on(outputStream* st) {425ProfilerNode::print_method_on(st);426MethodCounters* mcs = method()->method_counters();427if (Verbose && mcs != NULL) mcs->invocation_counter()->print_short();428}429};430431class compiledNode : public ProfilerNode {432private:433Method* _method;434oop _class_loader; // needed to keep metadata for the method alive435public:436compiledNode(Method* method, TickPosition where) : ProfilerNode() {437_method = method;438_class_loader = method->method_holder()->class_loader();439update(where);440}441bool is_compiled() const { return true; }442443bool compiled_match(Method* m) const {444return _method == m;445}446447Method* method() { return _method; }448449void oops_do(OopClosure* f) {450f->do_oop(&_class_loader);451}452453static void print_title(outputStream* st) {454st->fill_to(col1);455st->print("%11s", "Compiled");456ProfilerNode::print_title(st);457}458459void print(outputStream* st, int total_ticks) {460ProfilerNode::print(st, total_ticks);461}462463void print_method_on(outputStream* st) {464ProfilerNode::print_method_on(st);465}466};467468class stubNode : public ProfilerNode {469private:470Method* _method;471oop _class_loader; // needed to keep metadata for the method alive472const char* _symbol; // The name of the nearest VM symbol (for +ProfileVM). Points to a unique string473public:474stubNode(Method* method, const char* name, TickPosition where) : ProfilerNode() {475_method = method;476_class_loader = method->method_holder()->class_loader();477_symbol = name;478update(where);479}480481bool is_stub() const { return true; }482483void oops_do(OopClosure* f) {484f->do_oop(&_class_loader);485}486487bool stub_match(Method* m, const char* name) const {488return (_method == m) && (_symbol == name);489}490491Method* method() { return _method; }492493static void print_title(outputStream* st) {494st->fill_to(col1);495st->print("%11s", "Stub");496ProfilerNode::print_title(st);497}498499void print(outputStream* st, int total_ticks) {500ProfilerNode::print(st, total_ticks);501}502503void print_method_on(outputStream* st) {504ProfilerNode::print_method_on(st);505print_symbol_on(st);506}507508void print_symbol_on(outputStream* st) {509if(_symbol) {510st->print(" (%s)", _symbol);511}512}513};514515class adapterNode : public ProfilerNode {516public:517adapterNode(TickPosition where) : ProfilerNode() {518update(where);519}520bool is_compiled() const { return true; }521522bool adapter_match() const { return true; }523524Method* method() { return NULL; }525526void oops_do(OopClosure* f) {527;528}529530void print(outputStream* st, int total_ticks) {531ProfilerNode::print(st, total_ticks);532}533534void print_method_on(outputStream* st) {535st->print("%s", "adapters");536}537};538539class runtimeStubNode : public ProfilerNode {540private:541const CodeBlob* _stub;542const char* _symbol; // The name of the nearest VM symbol when ProfileVM is on. Points to a unique string.543public:544runtimeStubNode(const CodeBlob* stub, const char* name, TickPosition where) : ProfilerNode(), _stub(stub), _symbol(name) {545assert(stub->is_runtime_stub(), "wrong code blob");546update(where);547}548549bool is_runtime_stub() const { return true; }550551bool runtimeStub_match(const CodeBlob* stub, const char* name) const {552assert(stub->is_runtime_stub(), "wrong code blob");553return ((RuntimeStub*)_stub)->entry_point() == ((RuntimeStub*)stub)->entry_point() &&554(_symbol == name);555}556557Method* method() { return NULL; }558559static void print_title(outputStream* st) {560st->fill_to(col1);561st->print("%11s", "Runtime stub");562ProfilerNode::print_title(st);563}564565void oops_do(OopClosure* f) {566;567}568569void print(outputStream* st, int total_ticks) {570ProfilerNode::print(st, total_ticks);571}572573void print_method_on(outputStream* st) {574st->print("%s", ((RuntimeStub*)_stub)->name());575print_symbol_on(st);576}577578void print_symbol_on(outputStream* st) {579if(_symbol) {580st->print(" (%s)", _symbol);581}582}583};584585586class unknown_compiledNode : public ProfilerNode {587const char *_name;588public:589unknown_compiledNode(const CodeBlob* cb, TickPosition where) : ProfilerNode() {590if ( cb->is_buffer_blob() )591_name = ((BufferBlob*)cb)->name();592else593_name = ((SingletonBlob*)cb)->name();594update(where);595}596bool is_compiled() const { return true; }597598bool unknown_compiled_match(const CodeBlob* cb) const {599if ( cb->is_buffer_blob() )600return !strcmp(((BufferBlob*)cb)->name(), _name);601else602return !strcmp(((SingletonBlob*)cb)->name(), _name);603}604605Method* method() { return NULL; }606607void oops_do(OopClosure* f) {608;609}610611void print(outputStream* st, int total_ticks) {612ProfilerNode::print(st, total_ticks);613}614615void print_method_on(outputStream* st) {616st->print("%s", _name);617}618};619620class vmNode : public ProfilerNode {621private:622const char* _name; // "optional" name obtained by os means such as dll lookup623public:624vmNode(const TickPosition where) : ProfilerNode() {625_name = NULL;626update(where);627}628629vmNode(const char* name, const TickPosition where) : ProfilerNode() {630_name = name;631update(where);632}633634const char *name() const { return _name; }635bool is_compiled() const { return true; }636637bool vm_match(const char* name) const { return strcmp(name, _name) == 0; }638639Method* method() { return NULL; }640641static int hash(const char* name){642// Compute a simple hash643const char* cp = name;644int h = 0;645646if(name != NULL){647while(*cp != '\0'){648h = (h << 1) ^ *cp;649cp++;650}651}652return h;653}654655void oops_do(OopClosure* f) {656;657}658659void print(outputStream* st, int total_ticks) {660ProfilerNode::print(st, total_ticks);661}662663void print_method_on(outputStream* st) {664if(_name==NULL){665st->print("%s", "unknown code");666}667else {668st->print("%s", _name);669}670}671};672673void ThreadProfiler::interpreted_update(Method* method, TickPosition where) {674int index = entry(ProfilerNode::hash(method));675if (!table[index]) {676table[index] = new (this) interpretedNode(method, where);677} else {678ProfilerNode* prev = table[index];679for(ProfilerNode* node = prev; node; node = node->next()) {680if (node->interpreted_match(method)) {681node->update(where);682return;683}684prev = node;685}686prev->set_next(new (this) interpretedNode(method, where));687}688}689690void ThreadProfiler::compiled_update(Method* method, TickPosition where) {691int index = entry(ProfilerNode::hash(method));692if (!table[index]) {693table[index] = new (this) compiledNode(method, where);694} else {695ProfilerNode* prev = table[index];696for(ProfilerNode* node = prev; node; node = node->next()) {697if (node->compiled_match(method)) {698node->update(where);699return;700}701prev = node;702}703prev->set_next(new (this) compiledNode(method, where));704}705}706707void ThreadProfiler::stub_update(Method* method, const char* name, TickPosition where) {708int index = entry(ProfilerNode::hash(method));709if (!table[index]) {710table[index] = new (this) stubNode(method, name, where);711} else {712ProfilerNode* prev = table[index];713for(ProfilerNode* node = prev; node; node = node->next()) {714if (node->stub_match(method, name)) {715node->update(where);716return;717}718prev = node;719}720prev->set_next(new (this) stubNode(method, name, where));721}722}723724void ThreadProfiler::adapter_update(TickPosition where) {725int index = 0;726if (!table[index]) {727table[index] = new (this) adapterNode(where);728} else {729ProfilerNode* prev = table[index];730for(ProfilerNode* node = prev; node; node = node->next()) {731if (node->adapter_match()) {732node->update(where);733return;734}735prev = node;736}737prev->set_next(new (this) adapterNode(where));738}739}740741void ThreadProfiler::runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where) {742int index = 0;743if (!table[index]) {744table[index] = new (this) runtimeStubNode(stub, name, where);745} else {746ProfilerNode* prev = table[index];747for(ProfilerNode* node = prev; node; node = node->next()) {748if (node->runtimeStub_match(stub, name)) {749node->update(where);750return;751}752prev = node;753}754prev->set_next(new (this) runtimeStubNode(stub, name, where));755}756}757758759void ThreadProfiler::unknown_compiled_update(const CodeBlob* cb, TickPosition where) {760int index = 0;761if (!table[index]) {762table[index] = new (this) unknown_compiledNode(cb, where);763} else {764ProfilerNode* prev = table[index];765for(ProfilerNode* node = prev; node; node = node->next()) {766if (node->unknown_compiled_match(cb)) {767node->update(where);768return;769}770prev = node;771}772prev->set_next(new (this) unknown_compiledNode(cb, where));773}774}775776void ThreadProfiler::vm_update(TickPosition where) {777vm_update("", where);778}779780void ThreadProfiler::vm_update(const char* name, TickPosition where) {781int index = entry(vmNode::hash(name));782assert(index >= 0, "Must be positive");783// Note that we call strdup below since the symbol may be resource allocated784if (!table[index]) {785table[index] = new (this) vmNode(os::strdup(name), where);786} else {787ProfilerNode* prev = table[index];788for(ProfilerNode* node = prev; node; node = node->next()) {789if (((vmNode *)node)->vm_match(name)) {790node->update(where);791return;792}793prev = node;794}795prev->set_next(new (this) vmNode(os::strdup(name), where));796}797}798799800class FlatProfilerTask : public PeriodicTask {801public:802FlatProfilerTask(int interval_time) : PeriodicTask(interval_time) {}803void task();804};805806void FlatProfiler::record_vm_operation() {807if (Universe::heap()->is_gc_active()) {808FlatProfiler::received_gc_ticks += 1;809return;810}811812if (DeoptimizationMarker::is_active()) {813FlatProfiler::deopt_ticks += 1;814return;815}816817FlatProfiler::vm_operation_ticks += 1;818}819820void FlatProfiler::record_vm_tick() {821// Profile the VM Thread itself if needed822// This is done without getting the Threads_lock and we can go deep823// inside Safepoint, etc.824if( ProfileVM ) {825ResourceMark rm;826ExtendedPC epc;827const char *name = NULL;828char buf[256];829buf[0] = '\0';830831vm_thread_profiler->inc_thread_ticks();832833// Get a snapshot of a current VMThread pc (and leave it running!)834// The call may fail if, for instance the VM thread is interrupted while835// holding the Interrupt_lock or for other reasons.836epc = os::get_thread_pc(VMThread::vm_thread());837if(epc.pc() != NULL) {838if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) {839name = buf;840}841}842if (name != NULL) {843vm_thread_profiler->vm_update(name, tp_native);844}845}846}847848void FlatProfiler::record_thread_ticks() {849850int maxthreads, suspendedthreadcount;851JavaThread** threadsList;852bool interval_expired = false;853854if (ProfileIntervals &&855(FlatProfiler::received_ticks >= interval_ticks_previous + ProfileIntervalsTicks)) {856interval_expired = true;857interval_ticks_previous = FlatProfiler::received_ticks;858}859860// Try not to wait for the Threads_lock861if (Threads_lock->try_lock()) {862{ // Threads_lock scope863maxthreads = Threads::number_of_threads();864threadsList = NEW_C_HEAP_ARRAY(JavaThread *, maxthreads, mtInternal);865suspendedthreadcount = 0;866for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {867if (tp->is_Compiler_thread()) {868// Only record ticks for active compiler threads869CompilerThread* cthread = (CompilerThread*)tp;870if (cthread->task() != NULL) {871// The compiler is active. If we need to access any of the fields872// of the compiler task we should suspend the CompilerThread first.873FlatProfiler::compiler_ticks += 1;874continue;875}876}877878// First externally suspend all threads by marking each for879// external suspension - so it will stop at its next transition880// Then do a safepoint881ThreadProfiler* pp = tp->get_thread_profiler();882if (pp != NULL && pp->engaged) {883MutexLockerEx ml(tp->SR_lock(), Mutex::_no_safepoint_check_flag);884if (!tp->is_external_suspend() && !tp->is_exiting()) {885tp->set_external_suspend();886threadsList[suspendedthreadcount++] = tp;887}888}889}890Threads_lock->unlock();891}892// Suspend each thread. This call should just return893// for any threads that have already self-suspended894// Net result should be one safepoint895for (int j = 0; j < suspendedthreadcount; j++) {896JavaThread *tp = threadsList[j];897if (tp) {898tp->java_suspend();899}900}901902// We are responsible for resuming any thread on this list903for (int i = 0; i < suspendedthreadcount; i++) {904JavaThread *tp = threadsList[i];905if (tp) {906ThreadProfiler* pp = tp->get_thread_profiler();907if (pp != NULL && pp->engaged) {908HandleMark hm;909FlatProfiler::delivered_ticks += 1;910if (interval_expired) {911FlatProfiler::interval_record_thread(pp);912}913// This is the place where we check to see if a user thread is914// blocked waiting for compilation.915if (tp->blocked_on_compilation()) {916pp->compiler_ticks += 1;917pp->interval_data_ref()->inc_compiling();918} else {919pp->record_tick(tp);920}921}922MutexLocker ml(Threads_lock);923tp->java_resume();924}925}926if (interval_expired) {927FlatProfiler::interval_print();928FlatProfiler::interval_reset();929}930931FREE_C_HEAP_ARRAY(JavaThread *, threadsList, mtInternal);932} else {933// Couldn't get the threads lock, just record that rather than blocking934FlatProfiler::threads_lock_ticks += 1;935}936937}938939void FlatProfilerTask::task() {940FlatProfiler::received_ticks += 1;941942if (ProfileVM) {943FlatProfiler::record_vm_tick();944}945946VM_Operation* op = VMThread::vm_operation();947if (op != NULL) {948FlatProfiler::record_vm_operation();949if (SafepointSynchronize::is_at_safepoint()) {950return;951}952}953FlatProfiler::record_thread_ticks();954}955956void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) {957FlatProfiler::all_int_ticks++;958if (!FlatProfiler::full_profile()) {959return;960}961962if (!fr.is_interpreted_frame_valid(thread)) {963// tick came at a bad time964interpreter_ticks += 1;965FlatProfiler::interpreter_ticks += 1;966return;967}968969// The frame has been fully validated so we can trust the method and bci970971Method* method = *fr.interpreter_frame_method_addr();972973interpreted_update(method, where);974975// update byte code table976InterpreterCodelet* desc = Interpreter::codelet_containing(fr.pc());977if (desc != NULL && desc->bytecode() >= 0) {978ticks[desc->bytecode()]++;979}980}981982void ThreadProfiler::record_compiled_tick(JavaThread* thread, frame fr, TickPosition where) {983const char *name = NULL;984TickPosition localwhere = where;985986FlatProfiler::all_comp_ticks++;987if (!FlatProfiler::full_profile()) return;988989CodeBlob* cb = fr.cb();990991// For runtime stubs, record as native rather than as compiled992if (cb->is_runtime_stub()) {993RegisterMap map(thread, false);994fr = fr.sender(&map);995cb = fr.cb();996localwhere = tp_native;997}998Method* method = (cb->is_nmethod()) ? ((nmethod *)cb)->method() :999(Method*)NULL;10001001if (method == NULL) {1002if (cb->is_runtime_stub())1003runtime_stub_update(cb, name, localwhere);1004else1005unknown_compiled_update(cb, localwhere);1006}1007else {1008if (method->is_native()) {1009stub_update(method, name, localwhere);1010} else {1011compiled_update(method, localwhere);1012}1013}1014}10151016extern "C" void find(int x);101710181019void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr) {1020// The tick happened in real code -> non VM code1021if (fr.is_interpreted_frame()) {1022interval_data_ref()->inc_interpreted();1023record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks);1024return;1025}10261027if (CodeCache::contains(fr.pc())) {1028interval_data_ref()->inc_compiled();1029PCRecorder::record(fr.pc());1030record_compiled_tick(thread, fr, tp_code);1031return;1032}10331034if (VtableStubs::stub_containing(fr.pc()) != NULL) {1035unknown_ticks_array[ut_vtable_stubs] += 1;1036return;1037}10381039frame caller = fr.profile_find_Java_sender_frame(thread);10401041if (caller.sp() != NULL && caller.pc() != NULL) {1042record_tick_for_calling_frame(thread, caller);1043return;1044}10451046unknown_ticks_array[ut_running_frame] += 1;1047FlatProfiler::unknown_ticks += 1;1048}10491050void ThreadProfiler::record_tick_for_calling_frame(JavaThread* thread, frame fr) {1051// The tick happened in VM code1052interval_data_ref()->inc_native();1053if (fr.is_interpreted_frame()) {1054record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub);1055return;1056}1057if (CodeCache::contains(fr.pc())) {1058record_compiled_tick(thread, fr, tp_native);1059return;1060}10611062frame caller = fr.profile_find_Java_sender_frame(thread);10631064if (caller.sp() != NULL && caller.pc() != NULL) {1065record_tick_for_calling_frame(thread, caller);1066return;1067}10681069unknown_ticks_array[ut_calling_frame] += 1;1070FlatProfiler::unknown_ticks += 1;1071}10721073void ThreadProfiler::record_tick(JavaThread* thread) {1074FlatProfiler::all_ticks++;1075thread_ticks += 1;10761077// Here's another way to track global state changes.1078// When the class loader starts it marks the ThreadProfiler to tell it it is in the class loader1079// and we check that here.1080// This is more direct, and more than one thread can be in the class loader at a time,1081// but it does mean the class loader has to know about the profiler.1082if (region_flag[ThreadProfilerMark::classLoaderRegion]) {1083class_loader_ticks += 1;1084FlatProfiler::class_loader_ticks += 1;1085return;1086} else if (region_flag[ThreadProfilerMark::extraRegion]) {1087extra_ticks += 1;1088FlatProfiler::extra_ticks += 1;1089return;1090}1091// Note that the WatcherThread can now stop for safepoints1092uint32_t debug_bits = 0;1093if (!thread->wait_for_ext_suspend_completion(SuspendRetryCount,1094SuspendRetryDelay, &debug_bits)) {1095unknown_ticks_array[ut_unknown_thread_state] += 1;1096FlatProfiler::unknown_ticks += 1;1097return;1098}10991100frame fr;11011102switch (thread->thread_state()) {1103case _thread_in_native:1104case _thread_in_native_trans:1105case _thread_in_vm:1106case _thread_in_vm_trans:1107if (thread->profile_last_Java_frame(&fr)) {1108if (fr.is_runtime_frame()) {1109RegisterMap map(thread, false);1110fr = fr.sender(&map);1111}1112record_tick_for_calling_frame(thread, fr);1113} else {1114unknown_ticks_array[ut_no_last_Java_frame] += 1;1115FlatProfiler::unknown_ticks += 1;1116}1117break;1118// handle_special_runtime_exit_condition self-suspends threads in Java1119case _thread_in_Java:1120case _thread_in_Java_trans:1121if (thread->profile_last_Java_frame(&fr)) {1122if (fr.is_safepoint_blob_frame()) {1123RegisterMap map(thread, false);1124fr = fr.sender(&map);1125}1126record_tick_for_running_frame(thread, fr);1127} else {1128unknown_ticks_array[ut_no_last_Java_frame] += 1;1129FlatProfiler::unknown_ticks += 1;1130}1131break;1132case _thread_blocked:1133case _thread_blocked_trans:1134if (thread->osthread() && thread->osthread()->get_state() == RUNNABLE) {1135if (thread->profile_last_Java_frame(&fr)) {1136if (fr.is_safepoint_blob_frame()) {1137RegisterMap map(thread, false);1138fr = fr.sender(&map);1139record_tick_for_running_frame(thread, fr);1140} else {1141record_tick_for_calling_frame(thread, fr);1142}1143} else {1144unknown_ticks_array[ut_no_last_Java_frame] += 1;1145FlatProfiler::unknown_ticks += 1;1146}1147} else {1148blocked_ticks += 1;1149FlatProfiler::blocked_ticks += 1;1150}1151break;1152case _thread_uninitialized:1153case _thread_new:1154// not used, included for completeness1155case _thread_new_trans:1156unknown_ticks_array[ut_no_last_Java_frame] += 1;1157FlatProfiler::unknown_ticks += 1;1158break;1159default:1160unknown_ticks_array[ut_unknown_thread_state] += 1;1161FlatProfiler::unknown_ticks += 1;1162break;1163}1164return;1165}11661167void ThreadProfiler::engage() {1168engaged = true;1169timer.start();1170}11711172void ThreadProfiler::disengage() {1173engaged = false;1174timer.stop();1175}11761177void ThreadProfiler::initialize() {1178for (int index = 0; index < table_size; index++) {1179table[index] = NULL;1180}1181thread_ticks = 0;1182blocked_ticks = 0;1183compiler_ticks = 0;1184interpreter_ticks = 0;1185for (int ut = 0; ut < ut_end; ut += 1) {1186unknown_ticks_array[ut] = 0;1187}1188region_flag[ThreadProfilerMark::classLoaderRegion] = false;1189class_loader_ticks = 0;1190region_flag[ThreadProfilerMark::extraRegion] = false;1191extra_ticks = 0;1192timer.start();1193interval_data_ref()->reset();1194}11951196void ThreadProfiler::reset() {1197timer.stop();1198if (table != NULL) {1199for (int index = 0; index < table_size; index++) {1200ProfilerNode* n = table[index];1201if (n != NULL) {1202delete n;1203}1204}1205}1206initialize();1207}12081209void FlatProfiler::allocate_table() {1210{ // Bytecode table1211bytecode_ticks = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal);1212bytecode_ticks_stub = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal);1213for(int index = 0; index < Bytecodes::number_of_codes; index++) {1214bytecode_ticks[index] = 0;1215bytecode_ticks_stub[index] = 0;1216}1217}12181219if (ProfilerRecordPC) PCRecorder::init();12201221interval_data = NEW_C_HEAP_ARRAY(IntervalData, interval_print_size, mtInternal);1222FlatProfiler::interval_reset();1223}12241225void FlatProfiler::engage(JavaThread* mainThread, bool fullProfile) {1226full_profile_flag = fullProfile;1227if (bytecode_ticks == NULL) {1228allocate_table();1229}1230if(ProfileVM && (vm_thread_profiler == NULL)){1231vm_thread_profiler = new ThreadProfiler();1232}1233if (task == NULL) {1234task = new FlatProfilerTask(WatcherThread::delay_interval);1235task->enroll();1236}1237timer.start();1238if (mainThread != NULL) {1239// When mainThread was created, it might not have a ThreadProfiler1240ThreadProfiler* pp = mainThread->get_thread_profiler();1241if (pp == NULL) {1242mainThread->set_thread_profiler(new ThreadProfiler());1243} else {1244pp->reset();1245}1246mainThread->get_thread_profiler()->engage();1247}1248// This is where we would assign thread_profiler1249// if we wanted only one thread_profiler for all threads.1250thread_profiler = NULL;1251}12521253void FlatProfiler::disengage() {1254if (!task) {1255return;1256}1257timer.stop();1258task->disenroll();1259delete task;1260task = NULL;1261if (thread_profiler != NULL) {1262thread_profiler->disengage();1263} else {1264MutexLocker tl(Threads_lock);1265for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {1266ThreadProfiler* pp = tp->get_thread_profiler();1267if (pp != NULL) {1268pp->disengage();1269}1270}1271}1272}12731274void FlatProfiler::reset() {1275if (task) {1276disengage();1277}12781279class_loader_ticks = 0;1280extra_ticks = 0;1281received_gc_ticks = 0;1282vm_operation_ticks = 0;1283compiler_ticks = 0;1284deopt_ticks = 0;1285interpreter_ticks = 0;1286blocked_ticks = 0;1287unknown_ticks = 0;1288received_ticks = 0;1289delivered_ticks = 0;1290timer.stop();1291}12921293bool FlatProfiler::is_active() {1294return task != NULL;1295}12961297void FlatProfiler::print_byte_code_statistics() {1298GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200);12991300tty->print_cr(" Bytecode ticks:");1301for (int index = 0; index < Bytecodes::number_of_codes; index++) {1302if (FlatProfiler::bytecode_ticks[index] > 0 || FlatProfiler::bytecode_ticks_stub[index] > 0) {1303tty->print_cr(" %4d %4d = %s",1304FlatProfiler::bytecode_ticks[index],1305FlatProfiler::bytecode_ticks_stub[index],1306Bytecodes::name( (Bytecodes::Code) index));1307}1308}1309tty->cr();1310}13111312void print_ticks(const char* title, int ticks, int total) {1313if (ticks > 0) {1314tty->print("%5.1f%% %5d", ticks * 100.0 / total, ticks);1315tty->fill_to(col3);1316tty->print("%s", title);1317tty->cr();1318}1319}13201321void ThreadProfiler::print(const char* thread_name) {1322ResourceMark rm;1323MutexLocker ppl(ProfilePrint_lock);1324int index = 0; // Declared outside for loops for portability13251326if (table == NULL) {1327return;1328}13291330if (thread_ticks <= 0) {1331return;1332}13331334const char* title = "too soon to tell";1335double secs = timer.seconds();13361337GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200);1338for(index = 0; index < table_size; index++) {1339for(ProfilerNode* node = table[index]; node; node = node->next())1340array->append(node);1341}13421343array->sort(&ProfilerNode::compare);13441345// compute total (sanity check)1346int active =1347class_loader_ticks +1348compiler_ticks +1349interpreter_ticks +1350unknown_ticks();1351for (index = 0; index < array->length(); index++) {1352active += array->at(index)->ticks.total();1353}1354int total = active + blocked_ticks;13551356tty->cr();1357tty->print_cr("Flat profile of %3.2f secs (%d total ticks): %s", secs, total, thread_name);1358if (total != thread_ticks) {1359print_ticks("Lost ticks", thread_ticks-total, thread_ticks);1360}1361tty->cr();13621363// print interpreted methods1364tick_counter interpreted_ticks;1365bool has_interpreted_ticks = false;1366int print_count = 0;1367for (index = 0; index < array->length(); index++) {1368ProfilerNode* n = array->at(index);1369if (n->is_interpreted()) {1370interpreted_ticks.add(&n->ticks);1371if (!has_interpreted_ticks) {1372interpretedNode::print_title(tty);1373has_interpreted_ticks = true;1374}1375if (print_count++ < ProfilerNumberOfInterpretedMethods) {1376n->print(tty, active);1377}1378}1379}1380if (has_interpreted_ticks) {1381if (print_count <= ProfilerNumberOfInterpretedMethods) {1382title = "Total interpreted";1383} else {1384title = "Total interpreted (including elided)";1385}1386interpretedNode::print_total(tty, &interpreted_ticks, active, title);1387tty->cr();1388}13891390// print compiled methods1391tick_counter compiled_ticks;1392bool has_compiled_ticks = false;1393print_count = 0;1394for (index = 0; index < array->length(); index++) {1395ProfilerNode* n = array->at(index);1396if (n->is_compiled()) {1397compiled_ticks.add(&n->ticks);1398if (!has_compiled_ticks) {1399compiledNode::print_title(tty);1400has_compiled_ticks = true;1401}1402if (print_count++ < ProfilerNumberOfCompiledMethods) {1403n->print(tty, active);1404}1405}1406}1407if (has_compiled_ticks) {1408if (print_count <= ProfilerNumberOfCompiledMethods) {1409title = "Total compiled";1410} else {1411title = "Total compiled (including elided)";1412}1413compiledNode::print_total(tty, &compiled_ticks, active, title);1414tty->cr();1415}14161417// print stub methods1418tick_counter stub_ticks;1419bool has_stub_ticks = false;1420print_count = 0;1421for (index = 0; index < array->length(); index++) {1422ProfilerNode* n = array->at(index);1423if (n->is_stub()) {1424stub_ticks.add(&n->ticks);1425if (!has_stub_ticks) {1426stubNode::print_title(tty);1427has_stub_ticks = true;1428}1429if (print_count++ < ProfilerNumberOfStubMethods) {1430n->print(tty, active);1431}1432}1433}1434if (has_stub_ticks) {1435if (print_count <= ProfilerNumberOfStubMethods) {1436title = "Total stub";1437} else {1438title = "Total stub (including elided)";1439}1440stubNode::print_total(tty, &stub_ticks, active, title);1441tty->cr();1442}14431444// print runtime stubs1445tick_counter runtime_stub_ticks;1446bool has_runtime_stub_ticks = false;1447print_count = 0;1448for (index = 0; index < array->length(); index++) {1449ProfilerNode* n = array->at(index);1450if (n->is_runtime_stub()) {1451runtime_stub_ticks.add(&n->ticks);1452if (!has_runtime_stub_ticks) {1453runtimeStubNode::print_title(tty);1454has_runtime_stub_ticks = true;1455}1456if (print_count++ < ProfilerNumberOfRuntimeStubNodes) {1457n->print(tty, active);1458}1459}1460}1461if (has_runtime_stub_ticks) {1462if (print_count <= ProfilerNumberOfRuntimeStubNodes) {1463title = "Total runtime stubs";1464} else {1465title = "Total runtime stubs (including elided)";1466}1467runtimeStubNode::print_total(tty, &runtime_stub_ticks, active, title);1468tty->cr();1469}14701471if (blocked_ticks + class_loader_ticks + interpreter_ticks + compiler_ticks + unknown_ticks() != 0) {1472tty->fill_to(col1);1473tty->print_cr("Thread-local ticks:");1474print_ticks("Blocked (of total)", blocked_ticks, total);1475print_ticks("Class loader", class_loader_ticks, active);1476print_ticks("Extra", extra_ticks, active);1477print_ticks("Interpreter", interpreter_ticks, active);1478print_ticks("Compilation", compiler_ticks, active);1479print_ticks("Unknown: vtable stubs", unknown_ticks_array[ut_vtable_stubs], active);1480print_ticks("Unknown: null method", unknown_ticks_array[ut_null_method], active);1481print_ticks("Unknown: running frame", unknown_ticks_array[ut_running_frame], active);1482print_ticks("Unknown: calling frame", unknown_ticks_array[ut_calling_frame], active);1483print_ticks("Unknown: no pc", unknown_ticks_array[ut_no_pc], active);1484print_ticks("Unknown: no last frame", unknown_ticks_array[ut_no_last_Java_frame], active);1485print_ticks("Unknown: thread_state", unknown_ticks_array[ut_unknown_thread_state], active);1486tty->cr();1487}14881489if (WizardMode) {1490tty->print_cr("Node area used: %dKb", (area_top - area_bottom) / 1024);1491}1492reset();1493}14941495/*1496ThreadProfiler::print_unknown(){1497if (table == NULL) {1498return;1499}15001501if (thread_ticks <= 0) {1502return;1503}1504} */15051506void FlatProfiler::print(int unused) {1507ResourceMark rm;1508if (thread_profiler != NULL) {1509thread_profiler->print("All threads");1510} else {1511MutexLocker tl(Threads_lock);1512for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {1513ThreadProfiler* pp = tp->get_thread_profiler();1514if (pp != NULL) {1515pp->print(tp->get_thread_name());1516}1517}1518}15191520if (ProfilerPrintByteCodeStatistics) {1521print_byte_code_statistics();1522}15231524if (non_method_ticks() > 0) {1525tty->cr();1526tty->print_cr("Global summary of %3.2f seconds:", timer.seconds());1527print_ticks("Received ticks", received_ticks, received_ticks);1528print_ticks("Received GC ticks", received_gc_ticks, received_ticks);1529print_ticks("Compilation", compiler_ticks, received_ticks);1530print_ticks("Deoptimization", deopt_ticks, received_ticks);1531print_ticks("Other VM operations", vm_operation_ticks, received_ticks);1532#ifndef PRODUCT1533print_ticks("Blocked ticks", blocked_ticks, received_ticks);1534print_ticks("Threads_lock blocks", threads_lock_ticks, received_ticks);1535print_ticks("Delivered ticks", delivered_ticks, received_ticks);1536print_ticks("All ticks", all_ticks, received_ticks);1537#endif1538print_ticks("Class loader", class_loader_ticks, received_ticks);1539print_ticks("Extra ", extra_ticks, received_ticks);1540print_ticks("Interpreter", interpreter_ticks, received_ticks);1541print_ticks("Unknown code", unknown_ticks, received_ticks);1542}15431544PCRecorder::print();15451546if(ProfileVM){1547tty->cr();1548vm_thread_profiler->print("VM Thread");1549}1550}15511552void IntervalData::print_header(outputStream* st) {1553st->print("i/c/n/g");1554}15551556void IntervalData::print_data(outputStream* st) {1557st->print("%d/%d/%d/%d", interpreted(), compiled(), native(), compiling());1558}15591560void FlatProfiler::interval_record_thread(ThreadProfiler* tp) {1561IntervalData id = tp->interval_data();1562int total = id.total();1563tp->interval_data_ref()->reset();15641565// Insertion sort the data, if it's relevant.1566for (int i = 0; i < interval_print_size; i += 1) {1567if (total > interval_data[i].total()) {1568for (int j = interval_print_size - 1; j > i; j -= 1) {1569interval_data[j] = interval_data[j-1];1570}1571interval_data[i] = id;1572break;1573}1574}1575}15761577void FlatProfiler::interval_print() {1578if ((interval_data[0].total() > 0)) {1579tty->stamp();1580tty->print("\t");1581IntervalData::print_header(tty);1582for (int i = 0; i < interval_print_size; i += 1) {1583if (interval_data[i].total() > 0) {1584tty->print("\t");1585interval_data[i].print_data(tty);1586}1587}1588tty->cr();1589}1590}15911592void FlatProfiler::interval_reset() {1593for (int i = 0; i < interval_print_size; i += 1) {1594interval_data[i].reset();1595}1596}15971598void ThreadProfiler::oops_do(OopClosure* f) {1599if (table == NULL) return;16001601for(int index = 0; index < table_size; index++) {1602for(ProfilerNode* node = table[index]; node; node = node->next())1603node->oops_do(f);1604}1605}16061607void FlatProfiler::oops_do(OopClosure* f) {1608if (thread_profiler != NULL) {1609thread_profiler->oops_do(f);1610} else {1611for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {1612ThreadProfiler* pp = tp->get_thread_profiler();1613if (pp != NULL) {1614pp->oops_do(f);1615}1616}1617}1618}161916201621