fprofiler.cpp revision 1472:c18cbe5936b8
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# include "incls/_precompiled.incl" 26# include "incls/_fprofiler.cpp.incl" 27 28// Static fields of FlatProfiler 29int FlatProfiler::received_gc_ticks = 0; 30int FlatProfiler::vm_operation_ticks = 0; 31int FlatProfiler::threads_lock_ticks = 0; 32int FlatProfiler::class_loader_ticks = 0; 33int FlatProfiler::extra_ticks = 0; 34int FlatProfiler::blocked_ticks = 0; 35int FlatProfiler::deopt_ticks = 0; 36int FlatProfiler::unknown_ticks = 0; 37int FlatProfiler::interpreter_ticks = 0; 38int FlatProfiler::compiler_ticks = 0; 39int FlatProfiler::received_ticks = 0; 40int FlatProfiler::delivered_ticks = 0; 41int* FlatProfiler::bytecode_ticks = NULL; 42int* FlatProfiler::bytecode_ticks_stub = NULL; 43int FlatProfiler::all_int_ticks = 0; 44int FlatProfiler::all_comp_ticks = 0; 45int FlatProfiler::all_ticks = 0; 46bool FlatProfiler::full_profile_flag = false; 47ThreadProfiler* FlatProfiler::thread_profiler = NULL; 48ThreadProfiler* FlatProfiler::vm_thread_profiler = NULL; 49FlatProfilerTask* FlatProfiler::task = NULL; 50elapsedTimer FlatProfiler::timer; 51int FlatProfiler::interval_ticks_previous = 0; 52IntervalData* FlatProfiler::interval_data = NULL; 53 54ThreadProfiler::ThreadProfiler() { 55 // Space for the ProfilerNodes 56 const int area_size = 1 * ProfilerNodeSize * 1024; 57 area_bottom = AllocateHeap(area_size, "fprofiler"); 58 area_top = area_bottom; 59 area_limit = area_bottom + area_size; 60 61 // ProfilerNode pointer table 62 table = NEW_C_HEAP_ARRAY(ProfilerNode*, table_size); 63 initialize(); 64 engaged = false; 65} 66 67ThreadProfiler::~ThreadProfiler() { 68 FreeHeap(area_bottom); 69 area_bottom = NULL; 70 area_top = NULL; 71 area_limit = NULL; 72 FreeHeap(table); 73 table = NULL; 74} 75 76// Statics for ThreadProfiler 77int ThreadProfiler::table_size = 1024; 78 79int ThreadProfiler::entry(int value) { 80 value = (value > 0) ? value : -value; 81 return value % table_size; 82} 83 84ThreadProfilerMark::ThreadProfilerMark(ThreadProfilerMark::Region r) { 85 _r = r; 86 _pp = NULL; 87 assert(((r > ThreadProfilerMark::noRegion) && (r < ThreadProfilerMark::maxRegion)), "ThreadProfilerMark::Region out of bounds"); 88 Thread* tp = Thread::current(); 89 if (tp != NULL && tp->is_Java_thread()) { 90 JavaThread* jtp = (JavaThread*) tp; 91 ThreadProfiler* pp = jtp->get_thread_profiler(); 92 _pp = pp; 93 if (pp != NULL) { 94 pp->region_flag[r] = true; 95 } 96 } 97} 98 99ThreadProfilerMark::~ThreadProfilerMark() { 100 if (_pp != NULL) { 101 _pp->region_flag[_r] = false; 102 } 103 _pp = NULL; 104} 105 106// Random other statics 107static const int col1 = 2; // position of output column 1 108static const int col2 = 11; // position of output column 2 109static const int col3 = 25; // position of output column 3 110static const int col4 = 55; // position of output column 4 111 112 113// Used for detailed profiling of nmethods. 114class PCRecorder : AllStatic { 115 private: 116 static int* counters; 117 static address base; 118 enum { 119 bucket_size = 16 120 }; 121 static int index_for(address pc) { return (pc - base)/bucket_size; } 122 static address pc_for(int index) { return base + (index * bucket_size); } 123 static int size() { 124 return ((int)CodeCache::max_capacity())/bucket_size * BytesPerWord; 125 } 126 public: 127 static address bucket_start_for(address pc) { 128 if (counters == NULL) return NULL; 129 return pc_for(index_for(pc)); 130 } 131 static int bucket_count_for(address pc) { return counters[index_for(pc)]; } 132 static void init(); 133 static void record(address pc); 134 static void print(); 135 static void print_blobs(CodeBlob* cb); 136}; 137 138int* PCRecorder::counters = NULL; 139address PCRecorder::base = NULL; 140 141void PCRecorder::init() { 142 MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag); 143 int s = size(); 144 counters = NEW_C_HEAP_ARRAY(int, s); 145 for (int index = 0; index < s; index++) { 146 counters[index] = 0; 147 } 148 base = CodeCache::first_address(); 149} 150 151void PCRecorder::record(address pc) { 152 if (counters == NULL) return; 153 assert(CodeCache::contains(pc), "must be in CodeCache"); 154 counters[index_for(pc)]++; 155} 156 157 158address FlatProfiler::bucket_start_for(address pc) { 159 return PCRecorder::bucket_start_for(pc); 160} 161 162int FlatProfiler::bucket_count_for(address pc) { 163 return PCRecorder::bucket_count_for(pc); 164} 165 166void PCRecorder::print() { 167 if (counters == NULL) return; 168 169 tty->cr(); 170 tty->print_cr("Printing compiled methods with PC buckets having more than %d ticks", ProfilerPCTickThreshold); 171 tty->print_cr("==================================================================="); 172 tty->cr(); 173 174 GrowableArray<CodeBlob*>* candidates = new GrowableArray<CodeBlob*>(20); 175 176 177 int s; 178 { 179 MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag); 180 s = size(); 181 } 182 183 for (int index = 0; index < s; index++) { 184 int count = counters[index]; 185 if (count > ProfilerPCTickThreshold) { 186 address pc = pc_for(index); 187 CodeBlob* cb = CodeCache::find_blob_unsafe(pc); 188 if (cb != NULL && candidates->find(cb) < 0) { 189 candidates->push(cb); 190 } 191 } 192 } 193 for (int i = 0; i < candidates->length(); i++) { 194 print_blobs(candidates->at(i)); 195 } 196} 197 198void PCRecorder::print_blobs(CodeBlob* cb) { 199 if (cb != NULL) { 200 cb->print(); 201 if (cb->is_nmethod()) { 202 ((nmethod*)cb)->print_code(); 203 } 204 tty->cr(); 205 } else { 206 tty->print_cr("stub code"); 207 } 208} 209 210class tick_counter { // holds tick info for one node 211 public: 212 int ticks_in_code; 213 int ticks_in_native; 214 215 tick_counter() { ticks_in_code = ticks_in_native = 0; } 216 tick_counter(int code, int native) { ticks_in_code = code; ticks_in_native = native; } 217 218 int total() const { 219 return (ticks_in_code + ticks_in_native); 220 } 221 222 void add(tick_counter* a) { 223 ticks_in_code += a->ticks_in_code; 224 ticks_in_native += a->ticks_in_native; 225 } 226 227 void update(TickPosition where) { 228 switch(where) { 229 case tp_code: ticks_in_code++; break; 230 case tp_native: ticks_in_native++; break; 231 } 232 } 233 234 void print_code(outputStream* st, int total_ticks) { 235 st->print("%5.1f%% %5d ", total() * 100.0 / total_ticks, ticks_in_code); 236 } 237 238 void print_native(outputStream* st) { 239 st->print(" + %5d ", ticks_in_native); 240 } 241}; 242 243class ProfilerNode { 244 private: 245 ProfilerNode* _next; 246 public: 247 tick_counter ticks; 248 249 public: 250 251 void* operator new(size_t size, ThreadProfiler* tp); 252 void operator delete(void* p); 253 254 ProfilerNode() { 255 _next = NULL; 256 } 257 258 virtual ~ProfilerNode() { 259 if (_next) 260 delete _next; 261 } 262 263 void set_next(ProfilerNode* n) { _next = n; } 264 ProfilerNode* next() { return _next; } 265 266 void update(TickPosition where) { ticks.update(where);} 267 int total_ticks() { return ticks.total(); } 268 269 virtual bool is_interpreted() const { return false; } 270 virtual bool is_compiled() const { return false; } 271 virtual bool is_stub() const { return false; } 272 virtual bool is_runtime_stub() const{ return false; } 273 virtual void oops_do(OopClosure* f) = 0; 274 275 virtual bool interpreted_match(methodOop m) const { return false; } 276 virtual bool compiled_match(methodOop m ) const { return false; } 277 virtual bool stub_match(methodOop m, const char* name) const { return false; } 278 virtual bool adapter_match() const { return false; } 279 virtual bool runtimeStub_match(const CodeBlob* stub, const char* name) const { return false; } 280 virtual bool unknown_compiled_match(const CodeBlob* cb) const { return false; } 281 282 static void print_title(outputStream* st) { 283 st->print(" + native"); 284 st->fill_to(col3); 285 st->print("Method"); 286 st->fill_to(col4); 287 st->cr(); 288 } 289 290 static void print_total(outputStream* st, tick_counter* t, int total, const char* msg) { 291 t->print_code(st, total); 292 st->fill_to(col2); 293 t->print_native(st); 294 st->fill_to(col3); 295 st->print(msg); 296 st->cr(); 297 } 298 299 virtual methodOop method() = 0; 300 301 virtual void print_method_on(outputStream* st) { 302 int limit; 303 int i; 304 methodOop m = method(); 305 symbolOop k = m->klass_name(); 306 // Print the class name with dots instead of slashes 307 limit = k->utf8_length(); 308 for (i = 0 ; i < limit ; i += 1) { 309 char c = (char) k->byte_at(i); 310 if (c == '/') { 311 c = '.'; 312 } 313 st->print("%c", c); 314 } 315 if (limit > 0) { 316 st->print("."); 317 } 318 symbolOop n = m->name(); 319 limit = n->utf8_length(); 320 for (i = 0 ; i < limit ; i += 1) { 321 char c = (char) n->byte_at(i); 322 st->print("%c", c); 323 } 324 if( Verbose ) { 325 // Disambiguate overloaded methods 326 symbolOop sig = m->signature(); 327 sig->print_symbol_on(st); 328 } 329 } 330 331 virtual void print(outputStream* st, int total_ticks) { 332 ticks.print_code(st, total_ticks); 333 st->fill_to(col2); 334 ticks.print_native(st); 335 st->fill_to(col3); 336 print_method_on(st); 337 st->cr(); 338 } 339 340 // for hashing into the table 341 static int hash(methodOop method) { 342 // The point here is to try to make something fairly unique 343 // out of the fields we can read without grabbing any locks 344 // since the method may be locked when we need the hash. 345 return ( 346 method->code_size() ^ 347 method->max_stack() ^ 348 method->max_locals() ^ 349 method->size_of_parameters()); 350 } 351 352 // for sorting 353 static int compare(ProfilerNode** a, ProfilerNode** b) { 354 return (*b)->total_ticks() - (*a)->total_ticks(); 355 } 356}; 357 358void* ProfilerNode::operator new(size_t size, ThreadProfiler* tp){ 359 void* result = (void*) tp->area_top; 360 tp->area_top += size; 361 362 if (tp->area_top > tp->area_limit) { 363 fatal("flat profiler buffer overflow"); 364 } 365 return result; 366} 367 368void ProfilerNode::operator delete(void* p){ 369} 370 371class interpretedNode : public ProfilerNode { 372 private: 373 methodOop _method; 374 public: 375 interpretedNode(methodOop method, TickPosition where) : ProfilerNode() { 376 _method = method; 377 update(where); 378 } 379 380 bool is_interpreted() const { return true; } 381 382 bool interpreted_match(methodOop m) const { 383 return _method == m; 384 } 385 386 void oops_do(OopClosure* f) { 387 f->do_oop((oop*)&_method); 388 } 389 390 methodOop method() { return _method; } 391 392 static void print_title(outputStream* st) { 393 st->fill_to(col1); 394 st->print("%11s", "Interpreted"); 395 ProfilerNode::print_title(st); 396 } 397 398 void print(outputStream* st, int total_ticks) { 399 ProfilerNode::print(st, total_ticks); 400 } 401 402 void print_method_on(outputStream* st) { 403 ProfilerNode::print_method_on(st); 404 if (Verbose) method()->invocation_counter()->print_short(); 405 } 406}; 407 408class compiledNode : public ProfilerNode { 409 private: 410 methodOop _method; 411 public: 412 compiledNode(methodOop method, TickPosition where) : ProfilerNode() { 413 _method = method; 414 update(where); 415 } 416 bool is_compiled() const { return true; } 417 418 bool compiled_match(methodOop m) const { 419 return _method == m; 420 } 421 422 methodOop method() { return _method; } 423 424 void oops_do(OopClosure* f) { 425 f->do_oop((oop*)&_method); 426 } 427 428 static void print_title(outputStream* st) { 429 st->fill_to(col1); 430 st->print("%11s", "Compiled"); 431 ProfilerNode::print_title(st); 432 } 433 434 void print(outputStream* st, int total_ticks) { 435 ProfilerNode::print(st, total_ticks); 436 } 437 438 void print_method_on(outputStream* st) { 439 ProfilerNode::print_method_on(st); 440 } 441}; 442 443class stubNode : public ProfilerNode { 444 private: 445 methodOop _method; 446 const char* _symbol; // The name of the nearest VM symbol (for +ProfileVM). Points to a unique string 447 public: 448 stubNode(methodOop method, const char* name, TickPosition where) : ProfilerNode() { 449 _method = method; 450 _symbol = name; 451 update(where); 452 } 453 454 bool is_stub() const { return true; } 455 456 bool stub_match(methodOop m, const char* name) const { 457 return (_method == m) && (_symbol == name); 458 } 459 460 void oops_do(OopClosure* f) { 461 f->do_oop((oop*)&_method); 462 } 463 464 methodOop method() { return _method; } 465 466 static void print_title(outputStream* st) { 467 st->fill_to(col1); 468 st->print("%11s", "Stub"); 469 ProfilerNode::print_title(st); 470 } 471 472 void print(outputStream* st, int total_ticks) { 473 ProfilerNode::print(st, total_ticks); 474 } 475 476 void print_method_on(outputStream* st) { 477 ProfilerNode::print_method_on(st); 478 print_symbol_on(st); 479 } 480 481 void print_symbol_on(outputStream* st) { 482 if(_symbol) { 483 st->print(" (%s)", _symbol); 484 } 485 } 486}; 487 488class adapterNode : public ProfilerNode { 489 public: 490 adapterNode(TickPosition where) : ProfilerNode() { 491 update(where); 492 } 493 bool is_compiled() const { return true; } 494 495 bool adapter_match() const { return true; } 496 497 methodOop method() { return NULL; } 498 499 void oops_do(OopClosure* f) { 500 ; 501 } 502 503 void print(outputStream* st, int total_ticks) { 504 ProfilerNode::print(st, total_ticks); 505 } 506 507 void print_method_on(outputStream* st) { 508 st->print("%s", "adapters"); 509 } 510}; 511 512class runtimeStubNode : public ProfilerNode { 513 private: 514 const CodeBlob* _stub; 515 const char* _symbol; // The name of the nearest VM symbol when ProfileVM is on. Points to a unique string. 516 public: 517 runtimeStubNode(const CodeBlob* stub, const char* name, TickPosition where) : ProfilerNode(), _stub(stub), _symbol(name) { 518 assert(stub->is_runtime_stub(), "wrong code blob"); 519 update(where); 520 } 521 522 bool is_runtime_stub() const { return true; } 523 524 bool runtimeStub_match(const CodeBlob* stub, const char* name) const { 525 assert(stub->is_runtime_stub(), "wrong code blob"); 526 return ((RuntimeStub*)_stub)->entry_point() == ((RuntimeStub*)stub)->entry_point() && 527 (_symbol == name); 528 } 529 530 methodOop method() { return NULL; } 531 532 static void print_title(outputStream* st) { 533 st->fill_to(col1); 534 st->print("%11s", "Runtime stub"); 535 ProfilerNode::print_title(st); 536 } 537 538 void oops_do(OopClosure* f) { 539 ; 540 } 541 542 void print(outputStream* st, int total_ticks) { 543 ProfilerNode::print(st, total_ticks); 544 } 545 546 void print_method_on(outputStream* st) { 547 st->print("%s", ((RuntimeStub*)_stub)->name()); 548 print_symbol_on(st); 549 } 550 551 void print_symbol_on(outputStream* st) { 552 if(_symbol) { 553 st->print(" (%s)", _symbol); 554 } 555 } 556}; 557 558 559class unknown_compiledNode : public ProfilerNode { 560 const char *_name; 561 public: 562 unknown_compiledNode(const CodeBlob* cb, TickPosition where) : ProfilerNode() { 563 if ( cb->is_buffer_blob() ) 564 _name = ((BufferBlob*)cb)->name(); 565 else 566 _name = ((SingletonBlob*)cb)->name(); 567 update(where); 568 } 569 bool is_compiled() const { return true; } 570 571 bool unknown_compiled_match(const CodeBlob* cb) const { 572 if ( cb->is_buffer_blob() ) 573 return !strcmp(((BufferBlob*)cb)->name(), _name); 574 else 575 return !strcmp(((SingletonBlob*)cb)->name(), _name); 576 } 577 578 methodOop method() { return NULL; } 579 580 void oops_do(OopClosure* f) { 581 ; 582 } 583 584 void print(outputStream* st, int total_ticks) { 585 ProfilerNode::print(st, total_ticks); 586 } 587 588 void print_method_on(outputStream* st) { 589 st->print("%s", _name); 590 } 591}; 592 593class vmNode : public ProfilerNode { 594 private: 595 const char* _name; // "optional" name obtained by os means such as dll lookup 596 public: 597 vmNode(const TickPosition where) : ProfilerNode() { 598 _name = NULL; 599 update(where); 600 } 601 602 vmNode(const char* name, const TickPosition where) : ProfilerNode() { 603 _name = name; 604 update(where); 605 } 606 607 const char *name() const { return _name; } 608 bool is_compiled() const { return true; } 609 610 bool vm_match(const char* name) const { return strcmp(name, _name) == 0; } 611 612 methodOop method() { return NULL; } 613 614 static int hash(const char* name){ 615 // Compute a simple hash 616 const char* cp = name; 617 int h = 0; 618 619 if(name != NULL){ 620 while(*cp != '\0'){ 621 h = (h << 1) ^ *cp; 622 cp++; 623 } 624 } 625 return h; 626 } 627 628 void oops_do(OopClosure* f) { 629 ; 630 } 631 632 void print(outputStream* st, int total_ticks) { 633 ProfilerNode::print(st, total_ticks); 634 } 635 636 void print_method_on(outputStream* st) { 637 if(_name==NULL){ 638 st->print("%s", "unknown code"); 639 } 640 else { 641 st->print("%s", _name); 642 } 643 } 644}; 645 646void ThreadProfiler::interpreted_update(methodOop method, TickPosition where) { 647 int index = entry(ProfilerNode::hash(method)); 648 if (!table[index]) { 649 table[index] = new (this) interpretedNode(method, where); 650 } else { 651 ProfilerNode* prev = table[index]; 652 for(ProfilerNode* node = prev; node; node = node->next()) { 653 if (node->interpreted_match(method)) { 654 node->update(where); 655 return; 656 } 657 prev = node; 658 } 659 prev->set_next(new (this) interpretedNode(method, where)); 660 } 661} 662 663void ThreadProfiler::compiled_update(methodOop method, TickPosition where) { 664 int index = entry(ProfilerNode::hash(method)); 665 if (!table[index]) { 666 table[index] = new (this) compiledNode(method, where); 667 } else { 668 ProfilerNode* prev = table[index]; 669 for(ProfilerNode* node = prev; node; node = node->next()) { 670 if (node->compiled_match(method)) { 671 node->update(where); 672 return; 673 } 674 prev = node; 675 } 676 prev->set_next(new (this) compiledNode(method, where)); 677 } 678} 679 680void ThreadProfiler::stub_update(methodOop method, const char* name, TickPosition where) { 681 int index = entry(ProfilerNode::hash(method)); 682 if (!table[index]) { 683 table[index] = new (this) stubNode(method, name, where); 684 } else { 685 ProfilerNode* prev = table[index]; 686 for(ProfilerNode* node = prev; node; node = node->next()) { 687 if (node->stub_match(method, name)) { 688 node->update(where); 689 return; 690 } 691 prev = node; 692 } 693 prev->set_next(new (this) stubNode(method, name, where)); 694 } 695} 696 697void ThreadProfiler::adapter_update(TickPosition where) { 698 int index = 0; 699 if (!table[index]) { 700 table[index] = new (this) adapterNode(where); 701 } else { 702 ProfilerNode* prev = table[index]; 703 for(ProfilerNode* node = prev; node; node = node->next()) { 704 if (node->adapter_match()) { 705 node->update(where); 706 return; 707 } 708 prev = node; 709 } 710 prev->set_next(new (this) adapterNode(where)); 711 } 712} 713 714void ThreadProfiler::runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where) { 715 int index = 0; 716 if (!table[index]) { 717 table[index] = new (this) runtimeStubNode(stub, name, where); 718 } else { 719 ProfilerNode* prev = table[index]; 720 for(ProfilerNode* node = prev; node; node = node->next()) { 721 if (node->runtimeStub_match(stub, name)) { 722 node->update(where); 723 return; 724 } 725 prev = node; 726 } 727 prev->set_next(new (this) runtimeStubNode(stub, name, where)); 728 } 729} 730 731 732void ThreadProfiler::unknown_compiled_update(const CodeBlob* cb, TickPosition where) { 733 int index = 0; 734 if (!table[index]) { 735 table[index] = new (this) unknown_compiledNode(cb, where); 736 } else { 737 ProfilerNode* prev = table[index]; 738 for(ProfilerNode* node = prev; node; node = node->next()) { 739 if (node->unknown_compiled_match(cb)) { 740 node->update(where); 741 return; 742 } 743 prev = node; 744 } 745 prev->set_next(new (this) unknown_compiledNode(cb, where)); 746 } 747} 748 749void ThreadProfiler::vm_update(TickPosition where) { 750 vm_update(NULL, where); 751} 752 753void ThreadProfiler::vm_update(const char* name, TickPosition where) { 754 int index = entry(vmNode::hash(name)); 755 assert(index >= 0, "Must be positive"); 756 // Note that we call strdup below since the symbol may be resource allocated 757 if (!table[index]) { 758 table[index] = new (this) vmNode(os::strdup(name), where); 759 } else { 760 ProfilerNode* prev = table[index]; 761 for(ProfilerNode* node = prev; node; node = node->next()) { 762 if (((vmNode *)node)->vm_match(name)) { 763 node->update(where); 764 return; 765 } 766 prev = node; 767 } 768 prev->set_next(new (this) vmNode(os::strdup(name), where)); 769 } 770} 771 772 773class FlatProfilerTask : public PeriodicTask { 774public: 775 FlatProfilerTask(int interval_time) : PeriodicTask(interval_time) {} 776 void task(); 777}; 778 779void FlatProfiler::record_vm_operation() { 780 if (Universe::heap()->is_gc_active()) { 781 FlatProfiler::received_gc_ticks += 1; 782 return; 783 } 784 785 if (DeoptimizationMarker::is_active()) { 786 FlatProfiler::deopt_ticks += 1; 787 return; 788 } 789 790 FlatProfiler::vm_operation_ticks += 1; 791} 792 793void FlatProfiler::record_vm_tick() { 794 // Profile the VM Thread itself if needed 795 // This is done without getting the Threads_lock and we can go deep 796 // inside Safepoint, etc. 797 if( ProfileVM ) { 798 ResourceMark rm; 799 ExtendedPC epc; 800 const char *name = NULL; 801 char buf[256]; 802 buf[0] = '\0'; 803 804 vm_thread_profiler->inc_thread_ticks(); 805 806 // Get a snapshot of a current VMThread pc (and leave it running!) 807 // The call may fail if, for instance the VM thread is interrupted while 808 // holding the Interrupt_lock or for other reasons. 809 epc = os::get_thread_pc(VMThread::vm_thread()); 810 if(epc.pc() != NULL) { 811 if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) { 812 name = buf; 813 } 814 } 815 if (name != NULL) { 816 vm_thread_profiler->vm_update(name, tp_native); 817 } 818 } 819} 820 821void FlatProfiler::record_thread_ticks() { 822 823 int maxthreads, suspendedthreadcount; 824 JavaThread** threadsList; 825 bool interval_expired = false; 826 827 if (ProfileIntervals && 828 (FlatProfiler::received_ticks >= interval_ticks_previous + ProfileIntervalsTicks)) { 829 interval_expired = true; 830 interval_ticks_previous = FlatProfiler::received_ticks; 831 } 832 833 // Try not to wait for the Threads_lock 834 if (Threads_lock->try_lock()) { 835 { // Threads_lock scope 836 maxthreads = Threads::number_of_threads(); 837 threadsList = NEW_C_HEAP_ARRAY(JavaThread *, maxthreads); 838 suspendedthreadcount = 0; 839 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { 840 if (tp->is_Compiler_thread()) { 841 // Only record ticks for active compiler threads 842 CompilerThread* cthread = (CompilerThread*)tp; 843 if (cthread->task() != NULL) { 844 // The compiler is active. If we need to access any of the fields 845 // of the compiler task we should suspend the CompilerThread first. 846 FlatProfiler::compiler_ticks += 1; 847 continue; 848 } 849 } 850 851 // First externally suspend all threads by marking each for 852 // external suspension - so it will stop at its next transition 853 // Then do a safepoint 854 ThreadProfiler* pp = tp->get_thread_profiler(); 855 if (pp != NULL && pp->engaged) { 856 MutexLockerEx ml(tp->SR_lock(), Mutex::_no_safepoint_check_flag); 857 if (!tp->is_external_suspend() && !tp->is_exiting()) { 858 tp->set_external_suspend(); 859 threadsList[suspendedthreadcount++] = tp; 860 } 861 } 862 } 863 Threads_lock->unlock(); 864 } 865 // Suspend each thread. This call should just return 866 // for any threads that have already self-suspended 867 // Net result should be one safepoint 868 for (int j = 0; j < suspendedthreadcount; j++) { 869 JavaThread *tp = threadsList[j]; 870 if (tp) { 871 tp->java_suspend(); 872 } 873 } 874 875 // We are responsible for resuming any thread on this list 876 for (int i = 0; i < suspendedthreadcount; i++) { 877 JavaThread *tp = threadsList[i]; 878 if (tp) { 879 ThreadProfiler* pp = tp->get_thread_profiler(); 880 if (pp != NULL && pp->engaged) { 881 HandleMark hm; 882 FlatProfiler::delivered_ticks += 1; 883 if (interval_expired) { 884 FlatProfiler::interval_record_thread(pp); 885 } 886 // This is the place where we check to see if a user thread is 887 // blocked waiting for compilation. 888 if (tp->blocked_on_compilation()) { 889 pp->compiler_ticks += 1; 890 pp->interval_data_ref()->inc_compiling(); 891 } else { 892 pp->record_tick(tp); 893 } 894 } 895 MutexLocker ml(Threads_lock); 896 tp->java_resume(); 897 } 898 } 899 if (interval_expired) { 900 FlatProfiler::interval_print(); 901 FlatProfiler::interval_reset(); 902 } 903 } else { 904 // Couldn't get the threads lock, just record that rather than blocking 905 FlatProfiler::threads_lock_ticks += 1; 906 } 907 908} 909 910void FlatProfilerTask::task() { 911 FlatProfiler::received_ticks += 1; 912 913 if (ProfileVM) { 914 FlatProfiler::record_vm_tick(); 915 } 916 917 VM_Operation* op = VMThread::vm_operation(); 918 if (op != NULL) { 919 FlatProfiler::record_vm_operation(); 920 if (SafepointSynchronize::is_at_safepoint()) { 921 return; 922 } 923 } 924 FlatProfiler::record_thread_ticks(); 925} 926 927void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) { 928 FlatProfiler::all_int_ticks++; 929 if (!FlatProfiler::full_profile()) { 930 return; 931 } 932 933 if (!fr.is_interpreted_frame_valid(thread)) { 934 // tick came at a bad time 935 interpreter_ticks += 1; 936 FlatProfiler::interpreter_ticks += 1; 937 return; 938 } 939 940 // The frame has been fully validated so we can trust the method and bci 941 942 methodOop method = *fr.interpreter_frame_method_addr(); 943 944 interpreted_update(method, where); 945 946 // update byte code table 947 InterpreterCodelet* desc = Interpreter::codelet_containing(fr.pc()); 948 if (desc != NULL && desc->bytecode() >= 0) { 949 ticks[desc->bytecode()]++; 950 } 951} 952 953void ThreadProfiler::record_compiled_tick(JavaThread* thread, frame fr, TickPosition where) { 954 const char *name = NULL; 955 TickPosition localwhere = where; 956 957 FlatProfiler::all_comp_ticks++; 958 if (!FlatProfiler::full_profile()) return; 959 960 CodeBlob* cb = fr.cb(); 961 962// For runtime stubs, record as native rather than as compiled 963 if (cb->is_runtime_stub()) { 964 RegisterMap map(thread, false); 965 fr = fr.sender(&map); 966 cb = fr.cb(); 967 localwhere = tp_native; 968 } 969 methodOop method = (cb->is_nmethod()) ? ((nmethod *)cb)->method() : 970 (methodOop)NULL; 971 972 if (method == NULL) { 973 if (cb->is_runtime_stub()) 974 runtime_stub_update(cb, name, localwhere); 975 else 976 unknown_compiled_update(cb, localwhere); 977 } 978 else { 979 if (method->is_native()) { 980 stub_update(method, name, localwhere); 981 } else { 982 compiled_update(method, localwhere); 983 } 984 } 985} 986 987extern "C" void find(int x); 988 989 990void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr) { 991 // The tick happened in real code -> non VM code 992 if (fr.is_interpreted_frame()) { 993 interval_data_ref()->inc_interpreted(); 994 record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks); 995 return; 996 } 997 998 if (CodeCache::contains(fr.pc())) { 999 interval_data_ref()->inc_compiled(); 1000 PCRecorder::record(fr.pc()); 1001 record_compiled_tick(thread, fr, tp_code); 1002 return; 1003 } 1004 1005 if (VtableStubs::stub_containing(fr.pc()) != NULL) { 1006 unknown_ticks_array[ut_vtable_stubs] += 1; 1007 return; 1008 } 1009 1010 frame caller = fr.profile_find_Java_sender_frame(thread); 1011 1012 if (caller.sp() != NULL && caller.pc() != NULL) { 1013 record_tick_for_calling_frame(thread, caller); 1014 return; 1015 } 1016 1017 unknown_ticks_array[ut_running_frame] += 1; 1018 FlatProfiler::unknown_ticks += 1; 1019} 1020 1021void ThreadProfiler::record_tick_for_calling_frame(JavaThread* thread, frame fr) { 1022 // The tick happened in VM code 1023 interval_data_ref()->inc_native(); 1024 if (fr.is_interpreted_frame()) { 1025 record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub); 1026 return; 1027 } 1028 if (CodeCache::contains(fr.pc())) { 1029 record_compiled_tick(thread, fr, tp_native); 1030 return; 1031 } 1032 1033 frame caller = fr.profile_find_Java_sender_frame(thread); 1034 1035 if (caller.sp() != NULL && caller.pc() != NULL) { 1036 record_tick_for_calling_frame(thread, caller); 1037 return; 1038 } 1039 1040 unknown_ticks_array[ut_calling_frame] += 1; 1041 FlatProfiler::unknown_ticks += 1; 1042} 1043 1044void ThreadProfiler::record_tick(JavaThread* thread) { 1045 FlatProfiler::all_ticks++; 1046 thread_ticks += 1; 1047 1048 // Here's another way to track global state changes. 1049 // When the class loader starts it marks the ThreadProfiler to tell it it is in the class loader 1050 // and we check that here. 1051 // This is more direct, and more than one thread can be in the class loader at a time, 1052 // but it does mean the class loader has to know about the profiler. 1053 if (region_flag[ThreadProfilerMark::classLoaderRegion]) { 1054 class_loader_ticks += 1; 1055 FlatProfiler::class_loader_ticks += 1; 1056 return; 1057 } else if (region_flag[ThreadProfilerMark::extraRegion]) { 1058 extra_ticks += 1; 1059 FlatProfiler::extra_ticks += 1; 1060 return; 1061 } 1062 // Note that the WatcherThread can now stop for safepoints 1063 uint32_t debug_bits = 0; 1064 if (!thread->wait_for_ext_suspend_completion(SuspendRetryCount, 1065 SuspendRetryDelay, &debug_bits)) { 1066 unknown_ticks_array[ut_unknown_thread_state] += 1; 1067 FlatProfiler::unknown_ticks += 1; 1068 return; 1069 } 1070 1071 frame fr; 1072 1073 switch (thread->thread_state()) { 1074 case _thread_in_native: 1075 case _thread_in_native_trans: 1076 case _thread_in_vm: 1077 case _thread_in_vm_trans: 1078 if (thread->profile_last_Java_frame(&fr)) { 1079 if (fr.is_runtime_frame()) { 1080 RegisterMap map(thread, false); 1081 fr = fr.sender(&map); 1082 } 1083 record_tick_for_calling_frame(thread, fr); 1084 } else { 1085 unknown_ticks_array[ut_no_last_Java_frame] += 1; 1086 FlatProfiler::unknown_ticks += 1; 1087 } 1088 break; 1089 // handle_special_runtime_exit_condition self-suspends threads in Java 1090 case _thread_in_Java: 1091 case _thread_in_Java_trans: 1092 if (thread->profile_last_Java_frame(&fr)) { 1093 if (fr.is_safepoint_blob_frame()) { 1094 RegisterMap map(thread, false); 1095 fr = fr.sender(&map); 1096 } 1097 record_tick_for_running_frame(thread, fr); 1098 } else { 1099 unknown_ticks_array[ut_no_last_Java_frame] += 1; 1100 FlatProfiler::unknown_ticks += 1; 1101 } 1102 break; 1103 case _thread_blocked: 1104 case _thread_blocked_trans: 1105 if (thread->osthread() && thread->osthread()->get_state() == RUNNABLE) { 1106 if (thread->profile_last_Java_frame(&fr)) { 1107 if (fr.is_safepoint_blob_frame()) { 1108 RegisterMap map(thread, false); 1109 fr = fr.sender(&map); 1110 record_tick_for_running_frame(thread, fr); 1111 } else { 1112 record_tick_for_calling_frame(thread, fr); 1113 } 1114 } else { 1115 unknown_ticks_array[ut_no_last_Java_frame] += 1; 1116 FlatProfiler::unknown_ticks += 1; 1117 } 1118 } else { 1119 blocked_ticks += 1; 1120 FlatProfiler::blocked_ticks += 1; 1121 } 1122 break; 1123 case _thread_uninitialized: 1124 case _thread_new: 1125 // not used, included for completeness 1126 case _thread_new_trans: 1127 unknown_ticks_array[ut_no_last_Java_frame] += 1; 1128 FlatProfiler::unknown_ticks += 1; 1129 break; 1130 default: 1131 unknown_ticks_array[ut_unknown_thread_state] += 1; 1132 FlatProfiler::unknown_ticks += 1; 1133 break; 1134 } 1135 return; 1136} 1137 1138void ThreadProfiler::engage() { 1139 engaged = true; 1140 timer.start(); 1141} 1142 1143void ThreadProfiler::disengage() { 1144 engaged = false; 1145 timer.stop(); 1146} 1147 1148void ThreadProfiler::initialize() { 1149 for (int index = 0; index < table_size; index++) { 1150 table[index] = NULL; 1151 } 1152 thread_ticks = 0; 1153 blocked_ticks = 0; 1154 compiler_ticks = 0; 1155 interpreter_ticks = 0; 1156 for (int ut = 0; ut < ut_end; ut += 1) { 1157 unknown_ticks_array[ut] = 0; 1158 } 1159 region_flag[ThreadProfilerMark::classLoaderRegion] = false; 1160 class_loader_ticks = 0; 1161 region_flag[ThreadProfilerMark::extraRegion] = false; 1162 extra_ticks = 0; 1163 timer.start(); 1164 interval_data_ref()->reset(); 1165} 1166 1167void ThreadProfiler::reset() { 1168 timer.stop(); 1169 if (table != NULL) { 1170 for (int index = 0; index < table_size; index++) { 1171 ProfilerNode* n = table[index]; 1172 if (n != NULL) { 1173 delete n; 1174 } 1175 } 1176 } 1177 initialize(); 1178} 1179 1180void FlatProfiler::allocate_table() { 1181 { // Bytecode table 1182 bytecode_ticks = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes); 1183 bytecode_ticks_stub = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes); 1184 for(int index = 0; index < Bytecodes::number_of_codes; index++) { 1185 bytecode_ticks[index] = 0; 1186 bytecode_ticks_stub[index] = 0; 1187 } 1188 } 1189 1190 if (ProfilerRecordPC) PCRecorder::init(); 1191 1192 interval_data = NEW_C_HEAP_ARRAY(IntervalData, interval_print_size); 1193 FlatProfiler::interval_reset(); 1194} 1195 1196void FlatProfiler::engage(JavaThread* mainThread, bool fullProfile) { 1197 full_profile_flag = fullProfile; 1198 if (bytecode_ticks == NULL) { 1199 allocate_table(); 1200 } 1201 if(ProfileVM && (vm_thread_profiler == NULL)){ 1202 vm_thread_profiler = new ThreadProfiler(); 1203 } 1204 if (task == NULL) { 1205 task = new FlatProfilerTask(WatcherThread::delay_interval); 1206 task->enroll(); 1207 } 1208 timer.start(); 1209 if (mainThread != NULL) { 1210 // When mainThread was created, it might not have a ThreadProfiler 1211 ThreadProfiler* pp = mainThread->get_thread_profiler(); 1212 if (pp == NULL) { 1213 mainThread->set_thread_profiler(new ThreadProfiler()); 1214 } else { 1215 pp->reset(); 1216 } 1217 mainThread->get_thread_profiler()->engage(); 1218 } 1219 // This is where we would assign thread_profiler 1220 // if we wanted only one thread_profiler for all threads. 1221 thread_profiler = NULL; 1222} 1223 1224void FlatProfiler::disengage() { 1225 if (!task) { 1226 return; 1227 } 1228 timer.stop(); 1229 task->disenroll(); 1230 delete task; 1231 task = NULL; 1232 if (thread_profiler != NULL) { 1233 thread_profiler->disengage(); 1234 } else { 1235 MutexLocker tl(Threads_lock); 1236 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { 1237 ThreadProfiler* pp = tp->get_thread_profiler(); 1238 if (pp != NULL) { 1239 pp->disengage(); 1240 } 1241 } 1242 } 1243} 1244 1245void FlatProfiler::reset() { 1246 if (task) { 1247 disengage(); 1248 } 1249 1250 class_loader_ticks = 0; 1251 extra_ticks = 0; 1252 received_gc_ticks = 0; 1253 vm_operation_ticks = 0; 1254 compiler_ticks = 0; 1255 deopt_ticks = 0; 1256 interpreter_ticks = 0; 1257 blocked_ticks = 0; 1258 unknown_ticks = 0; 1259 received_ticks = 0; 1260 delivered_ticks = 0; 1261 timer.stop(); 1262} 1263 1264bool FlatProfiler::is_active() { 1265 return task != NULL; 1266} 1267 1268void FlatProfiler::print_byte_code_statistics() { 1269 GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200); 1270 1271 tty->print_cr(" Bytecode ticks:"); 1272 for (int index = 0; index < Bytecodes::number_of_codes; index++) { 1273 if (FlatProfiler::bytecode_ticks[index] > 0 || FlatProfiler::bytecode_ticks_stub[index] > 0) { 1274 tty->print_cr(" %4d %4d = %s", 1275 FlatProfiler::bytecode_ticks[index], 1276 FlatProfiler::bytecode_ticks_stub[index], 1277 Bytecodes::name( (Bytecodes::Code) index)); 1278 } 1279 } 1280 tty->cr(); 1281} 1282 1283void print_ticks(const char* title, int ticks, int total) { 1284 if (ticks > 0) { 1285 tty->print("%5.1f%% %5d", ticks * 100.0 / total, ticks); 1286 tty->fill_to(col3); 1287 tty->print("%s", title); 1288 tty->cr(); 1289 } 1290} 1291 1292void ThreadProfiler::print(const char* thread_name) { 1293 ResourceMark rm; 1294 MutexLocker ppl(ProfilePrint_lock); 1295 int index = 0; // Declared outside for loops for portability 1296 1297 if (table == NULL) { 1298 return; 1299 } 1300 1301 if (thread_ticks <= 0) { 1302 return; 1303 } 1304 1305 const char* title = "too soon to tell"; 1306 double secs = timer.seconds(); 1307 1308 GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200); 1309 for(index = 0; index < table_size; index++) { 1310 for(ProfilerNode* node = table[index]; node; node = node->next()) 1311 array->append(node); 1312 } 1313 1314 array->sort(&ProfilerNode::compare); 1315 1316 // compute total (sanity check) 1317 int active = 1318 class_loader_ticks + 1319 compiler_ticks + 1320 interpreter_ticks + 1321 unknown_ticks(); 1322 for (index = 0; index < array->length(); index++) { 1323 active += array->at(index)->ticks.total(); 1324 } 1325 int total = active + blocked_ticks; 1326 1327 tty->cr(); 1328 tty->print_cr("Flat profile of %3.2f secs (%d total ticks): %s", secs, total, thread_name); 1329 if (total != thread_ticks) { 1330 print_ticks("Lost ticks", thread_ticks-total, thread_ticks); 1331 } 1332 tty->cr(); 1333 1334 // print interpreted methods 1335 tick_counter interpreted_ticks; 1336 bool has_interpreted_ticks = false; 1337 int print_count = 0; 1338 for (index = 0; index < array->length(); index++) { 1339 ProfilerNode* n = array->at(index); 1340 if (n->is_interpreted()) { 1341 interpreted_ticks.add(&n->ticks); 1342 if (!has_interpreted_ticks) { 1343 interpretedNode::print_title(tty); 1344 has_interpreted_ticks = true; 1345 } 1346 if (print_count++ < ProfilerNumberOfInterpretedMethods) { 1347 n->print(tty, active); 1348 } 1349 } 1350 } 1351 if (has_interpreted_ticks) { 1352 if (print_count <= ProfilerNumberOfInterpretedMethods) { 1353 title = "Total interpreted"; 1354 } else { 1355 title = "Total interpreted (including elided)"; 1356 } 1357 interpretedNode::print_total(tty, &interpreted_ticks, active, title); 1358 tty->cr(); 1359 } 1360 1361 // print compiled methods 1362 tick_counter compiled_ticks; 1363 bool has_compiled_ticks = false; 1364 print_count = 0; 1365 for (index = 0; index < array->length(); index++) { 1366 ProfilerNode* n = array->at(index); 1367 if (n->is_compiled()) { 1368 compiled_ticks.add(&n->ticks); 1369 if (!has_compiled_ticks) { 1370 compiledNode::print_title(tty); 1371 has_compiled_ticks = true; 1372 } 1373 if (print_count++ < ProfilerNumberOfCompiledMethods) { 1374 n->print(tty, active); 1375 } 1376 } 1377 } 1378 if (has_compiled_ticks) { 1379 if (print_count <= ProfilerNumberOfCompiledMethods) { 1380 title = "Total compiled"; 1381 } else { 1382 title = "Total compiled (including elided)"; 1383 } 1384 compiledNode::print_total(tty, &compiled_ticks, active, title); 1385 tty->cr(); 1386 } 1387 1388 // print stub methods 1389 tick_counter stub_ticks; 1390 bool has_stub_ticks = false; 1391 print_count = 0; 1392 for (index = 0; index < array->length(); index++) { 1393 ProfilerNode* n = array->at(index); 1394 if (n->is_stub()) { 1395 stub_ticks.add(&n->ticks); 1396 if (!has_stub_ticks) { 1397 stubNode::print_title(tty); 1398 has_stub_ticks = true; 1399 } 1400 if (print_count++ < ProfilerNumberOfStubMethods) { 1401 n->print(tty, active); 1402 } 1403 } 1404 } 1405 if (has_stub_ticks) { 1406 if (print_count <= ProfilerNumberOfStubMethods) { 1407 title = "Total stub"; 1408 } else { 1409 title = "Total stub (including elided)"; 1410 } 1411 stubNode::print_total(tty, &stub_ticks, active, title); 1412 tty->cr(); 1413 } 1414 1415 // print runtime stubs 1416 tick_counter runtime_stub_ticks; 1417 bool has_runtime_stub_ticks = false; 1418 print_count = 0; 1419 for (index = 0; index < array->length(); index++) { 1420 ProfilerNode* n = array->at(index); 1421 if (n->is_runtime_stub()) { 1422 runtime_stub_ticks.add(&n->ticks); 1423 if (!has_runtime_stub_ticks) { 1424 runtimeStubNode::print_title(tty); 1425 has_runtime_stub_ticks = true; 1426 } 1427 if (print_count++ < ProfilerNumberOfRuntimeStubNodes) { 1428 n->print(tty, active); 1429 } 1430 } 1431 } 1432 if (has_runtime_stub_ticks) { 1433 if (print_count <= ProfilerNumberOfRuntimeStubNodes) { 1434 title = "Total runtime stubs"; 1435 } else { 1436 title = "Total runtime stubs (including elided)"; 1437 } 1438 runtimeStubNode::print_total(tty, &runtime_stub_ticks, active, title); 1439 tty->cr(); 1440 } 1441 1442 if (blocked_ticks + class_loader_ticks + interpreter_ticks + compiler_ticks + unknown_ticks() != 0) { 1443 tty->fill_to(col1); 1444 tty->print_cr("Thread-local ticks:"); 1445 print_ticks("Blocked (of total)", blocked_ticks, total); 1446 print_ticks("Class loader", class_loader_ticks, active); 1447 print_ticks("Extra", extra_ticks, active); 1448 print_ticks("Interpreter", interpreter_ticks, active); 1449 print_ticks("Compilation", compiler_ticks, active); 1450 print_ticks("Unknown: vtable stubs", unknown_ticks_array[ut_vtable_stubs], active); 1451 print_ticks("Unknown: null method", unknown_ticks_array[ut_null_method], active); 1452 print_ticks("Unknown: running frame", unknown_ticks_array[ut_running_frame], active); 1453 print_ticks("Unknown: calling frame", unknown_ticks_array[ut_calling_frame], active); 1454 print_ticks("Unknown: no pc", unknown_ticks_array[ut_no_pc], active); 1455 print_ticks("Unknown: no last frame", unknown_ticks_array[ut_no_last_Java_frame], active); 1456 print_ticks("Unknown: thread_state", unknown_ticks_array[ut_unknown_thread_state], active); 1457 tty->cr(); 1458 } 1459 1460 if (WizardMode) { 1461 tty->print_cr("Node area used: %dKb", (area_top - area_bottom) / 1024); 1462 } 1463 reset(); 1464} 1465 1466/* 1467ThreadProfiler::print_unknown(){ 1468 if (table == NULL) { 1469 return; 1470 } 1471 1472 if (thread_ticks <= 0) { 1473 return; 1474 } 1475} */ 1476 1477void FlatProfiler::print(int unused) { 1478 ResourceMark rm; 1479 if (thread_profiler != NULL) { 1480 thread_profiler->print("All threads"); 1481 } else { 1482 MutexLocker tl(Threads_lock); 1483 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { 1484 ThreadProfiler* pp = tp->get_thread_profiler(); 1485 if (pp != NULL) { 1486 pp->print(tp->get_thread_name()); 1487 } 1488 } 1489 } 1490 1491 if (ProfilerPrintByteCodeStatistics) { 1492 print_byte_code_statistics(); 1493 } 1494 1495 if (non_method_ticks() > 0) { 1496 tty->cr(); 1497 tty->print_cr("Global summary of %3.2f seconds:", timer.seconds()); 1498 print_ticks("Received ticks", received_ticks, received_ticks); 1499 print_ticks("Received GC ticks", received_gc_ticks, received_ticks); 1500 print_ticks("Compilation", compiler_ticks, received_ticks); 1501 print_ticks("Deoptimization", deopt_ticks, received_ticks); 1502 print_ticks("Other VM operations", vm_operation_ticks, received_ticks); 1503#ifndef PRODUCT 1504 print_ticks("Blocked ticks", blocked_ticks, received_ticks); 1505 print_ticks("Threads_lock blocks", threads_lock_ticks, received_ticks); 1506 print_ticks("Delivered ticks", delivered_ticks, received_ticks); 1507 print_ticks("All ticks", all_ticks, received_ticks); 1508#endif 1509 print_ticks("Class loader", class_loader_ticks, received_ticks); 1510 print_ticks("Extra ", extra_ticks, received_ticks); 1511 print_ticks("Interpreter", interpreter_ticks, received_ticks); 1512 print_ticks("Unknown code", unknown_ticks, received_ticks); 1513 } 1514 1515 PCRecorder::print(); 1516 1517 if(ProfileVM){ 1518 tty->cr(); 1519 vm_thread_profiler->print("VM Thread"); 1520 } 1521} 1522 1523void IntervalData::print_header(outputStream* st) { 1524 st->print("i/c/n/g"); 1525} 1526 1527void IntervalData::print_data(outputStream* st) { 1528 st->print("%d/%d/%d/%d", interpreted(), compiled(), native(), compiling()); 1529} 1530 1531void FlatProfiler::interval_record_thread(ThreadProfiler* tp) { 1532 IntervalData id = tp->interval_data(); 1533 int total = id.total(); 1534 tp->interval_data_ref()->reset(); 1535 1536 // Insertion sort the data, if it's relevant. 1537 for (int i = 0; i < interval_print_size; i += 1) { 1538 if (total > interval_data[i].total()) { 1539 for (int j = interval_print_size - 1; j > i; j -= 1) { 1540 interval_data[j] = interval_data[j-1]; 1541 } 1542 interval_data[i] = id; 1543 break; 1544 } 1545 } 1546} 1547 1548void FlatProfiler::interval_print() { 1549 if ((interval_data[0].total() > 0)) { 1550 tty->stamp(); 1551 tty->print("\t"); 1552 IntervalData::print_header(tty); 1553 for (int i = 0; i < interval_print_size; i += 1) { 1554 if (interval_data[i].total() > 0) { 1555 tty->print("\t"); 1556 interval_data[i].print_data(tty); 1557 } 1558 } 1559 tty->cr(); 1560 } 1561} 1562 1563void FlatProfiler::interval_reset() { 1564 for (int i = 0; i < interval_print_size; i += 1) { 1565 interval_data[i].reset(); 1566 } 1567} 1568 1569void ThreadProfiler::oops_do(OopClosure* f) { 1570 if (table == NULL) return; 1571 1572 for(int index = 0; index < table_size; index++) { 1573 for(ProfilerNode* node = table[index]; node; node = node->next()) 1574 node->oops_do(f); 1575 } 1576} 1577 1578void FlatProfiler::oops_do(OopClosure* f) { 1579 if (thread_profiler != NULL) { 1580 thread_profiler->oops_do(f); 1581 } else { 1582 for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { 1583 ThreadProfiler* pp = tp->get_thread_profiler(); 1584 if (pp != NULL) { 1585 pp->oops_do(f); 1586 } 1587 } 1588 } 1589} 1590