OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/profiler/profile-generator.h" | 5 #include "src/profiler/profile-generator.h" |
6 | 6 |
7 #include "src/ast/scopeinfo.h" | 7 #include "src/ast/scopeinfo.h" |
8 #include "src/base/adapters.h" | 8 #include "src/base/adapters.h" |
9 #include "src/debug/debug.h" | 9 #include "src/debug/debug.h" |
10 #include "src/deoptimizer.h" | 10 #include "src/deoptimizer.h" |
(...skipping 29 matching lines...) Expand all Loading... |
40 } | 40 } |
41 return it->second; | 41 return it->second; |
42 } | 42 } |
43 | 43 |
44 | 44 |
45 const char* const CodeEntry::kEmptyNamePrefix = ""; | 45 const char* const CodeEntry::kEmptyNamePrefix = ""; |
46 const char* const CodeEntry::kEmptyResourceName = ""; | 46 const char* const CodeEntry::kEmptyResourceName = ""; |
47 const char* const CodeEntry::kEmptyBailoutReason = ""; | 47 const char* const CodeEntry::kEmptyBailoutReason = ""; |
48 const char* const CodeEntry::kNoDeoptReason = ""; | 48 const char* const CodeEntry::kNoDeoptReason = ""; |
49 | 49 |
| 50 const char* const CodeEntry::kProgramEntryName = "(program)"; |
| 51 const char* const CodeEntry::kIdleEntryName = "(idle)"; |
| 52 const char* const CodeEntry::kGarbageCollectorEntryName = "(garbage collector)"; |
| 53 const char* const CodeEntry::kUnresolvedFunctionName = "(unresolved function)"; |
| 54 |
| 55 base::LazyDynamicInstance<CodeEntry, CodeEntry::ProgramEntryCreateTrait>::type |
| 56 CodeEntry::kProgramEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |
| 57 |
| 58 base::LazyDynamicInstance<CodeEntry, CodeEntry::IdleEntryCreateTrait>::type |
| 59 CodeEntry::kIdleEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |
| 60 |
| 61 base::LazyDynamicInstance<CodeEntry, CodeEntry::GCEntryCreateTrait>::type |
| 62 CodeEntry::kGCEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |
| 63 |
| 64 base::LazyDynamicInstance<CodeEntry, |
| 65 CodeEntry::UnresolvedEntryCreateTrait>::type |
| 66 CodeEntry::kUnresolvedEntry = LAZY_DYNAMIC_INSTANCE_INITIALIZER; |
| 67 |
| 68 CodeEntry* CodeEntry::ProgramEntryCreateTrait::Create() { |
| 69 return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kProgramEntryName); |
| 70 } |
| 71 |
| 72 CodeEntry* CodeEntry::IdleEntryCreateTrait::Create() { |
| 73 return new CodeEntry(Logger::FUNCTION_TAG, CodeEntry::kIdleEntryName); |
| 74 } |
| 75 |
| 76 CodeEntry* CodeEntry::GCEntryCreateTrait::Create() { |
| 77 return new CodeEntry(Logger::BUILTIN_TAG, |
| 78 CodeEntry::kGarbageCollectorEntryName); |
| 79 } |
| 80 |
| 81 CodeEntry* CodeEntry::UnresolvedEntryCreateTrait::Create() { |
| 82 return new CodeEntry(Logger::FUNCTION_TAG, |
| 83 CodeEntry::kUnresolvedFunctionName); |
| 84 } |
50 | 85 |
51 CodeEntry::~CodeEntry() { | 86 CodeEntry::~CodeEntry() { |
52 delete line_info_; | 87 delete line_info_; |
53 for (auto location : inline_locations_) { | 88 for (auto location : inline_locations_) { |
54 for (auto entry : location.second) { | 89 for (auto entry : location.second) { |
55 delete entry; | 90 delete entry; |
56 } | 91 } |
57 } | 92 } |
58 } | 93 } |
59 | 94 |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 } | 461 } |
427 | 462 |
428 void CodeMap::Print() { | 463 void CodeMap::Print() { |
429 for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { | 464 for (auto it = code_map_.begin(); it != code_map_.end(); ++it) { |
430 base::OS::Print("%p %5d %s\n", static_cast<void*>(it->first), | 465 base::OS::Print("%p %5d %s\n", static_cast<void*>(it->first), |
431 it->second.size, it->second.entry->name()); | 466 it->second.size, it->second.entry->name()); |
432 } | 467 } |
433 } | 468 } |
434 | 469 |
435 CpuProfilesCollection::CpuProfilesCollection(Heap* heap) | 470 CpuProfilesCollection::CpuProfilesCollection(Heap* heap) |
436 : function_and_resource_names_(heap), | 471 : resource_names_(heap), |
437 isolate_(heap->isolate()), | 472 isolate_(heap->isolate()), |
438 current_profiles_semaphore_(1) {} | 473 current_profiles_semaphore_(1) {} |
439 | 474 |
440 | |
441 static void DeleteCodeEntry(CodeEntry** entry_ptr) { | |
442 delete *entry_ptr; | |
443 } | |
444 | |
445 | |
446 static void DeleteCpuProfile(CpuProfile** profile_ptr) { | 475 static void DeleteCpuProfile(CpuProfile** profile_ptr) { |
447 delete *profile_ptr; | 476 delete *profile_ptr; |
448 } | 477 } |
449 | 478 |
450 | 479 |
451 CpuProfilesCollection::~CpuProfilesCollection() { | 480 CpuProfilesCollection::~CpuProfilesCollection() { |
452 finished_profiles_.Iterate(DeleteCpuProfile); | 481 finished_profiles_.Iterate(DeleteCpuProfile); |
453 current_profiles_.Iterate(DeleteCpuProfile); | 482 current_profiles_.Iterate(DeleteCpuProfile); |
454 code_entries_.Iterate(DeleteCodeEntry); | |
455 } | 483 } |
456 | 484 |
457 | 485 |
458 bool CpuProfilesCollection::StartProfiling(const char* title, | 486 bool CpuProfilesCollection::StartProfiling(const char* title, |
459 bool record_samples) { | 487 bool record_samples) { |
460 current_profiles_semaphore_.Wait(); | 488 current_profiles_semaphore_.Wait(); |
461 if (current_profiles_.length() >= kMaxSimultaneousProfiles) { | 489 if (current_profiles_.length() >= kMaxSimultaneousProfiles) { |
462 current_profiles_semaphore_.Signal(); | 490 current_profiles_semaphore_.Signal(); |
463 return false; | 491 return false; |
464 } | 492 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
521 // As starting / stopping profiles is rare relatively to this | 549 // As starting / stopping profiles is rare relatively to this |
522 // method, we don't bother minimizing the duration of lock holding, | 550 // method, we don't bother minimizing the duration of lock holding, |
523 // e.g. copying contents of the list to a local vector. | 551 // e.g. copying contents of the list to a local vector. |
524 current_profiles_semaphore_.Wait(); | 552 current_profiles_semaphore_.Wait(); |
525 for (int i = 0; i < current_profiles_.length(); ++i) { | 553 for (int i = 0; i < current_profiles_.length(); ++i) { |
526 current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); | 554 current_profiles_[i]->AddPath(timestamp, path, src_line, update_stats); |
527 } | 555 } |
528 current_profiles_semaphore_.Signal(); | 556 current_profiles_semaphore_.Signal(); |
529 } | 557 } |
530 | 558 |
531 | |
532 CodeEntry* CpuProfilesCollection::NewCodeEntry( | |
533 Logger::LogEventsAndTags tag, const char* name, const char* name_prefix, | |
534 const char* resource_name, int line_number, int column_number, | |
535 JITLineInfoTable* line_info, Address instruction_start) { | |
536 CodeEntry* code_entry = | |
537 new CodeEntry(tag, name, name_prefix, resource_name, line_number, | |
538 column_number, line_info, instruction_start); | |
539 code_entries_.Add(code_entry); | |
540 return code_entry; | |
541 } | |
542 | |
543 | |
544 const char* const ProfileGenerator::kProgramEntryName = | |
545 "(program)"; | |
546 const char* const ProfileGenerator::kIdleEntryName = | |
547 "(idle)"; | |
548 const char* const ProfileGenerator::kGarbageCollectorEntryName = | |
549 "(garbage collector)"; | |
550 const char* const ProfileGenerator::kUnresolvedFunctionName = | |
551 "(unresolved function)"; | |
552 | |
553 | |
554 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 559 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |
555 : profiles_(profiles), | 560 : profiles_(profiles) {} |
556 program_entry_( | |
557 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)), | |
558 idle_entry_( | |
559 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kIdleEntryName)), | |
560 gc_entry_( | |
561 profiles->NewCodeEntry(Logger::BUILTIN_TAG, | |
562 kGarbageCollectorEntryName)), | |
563 unresolved_entry_( | |
564 profiles->NewCodeEntry(Logger::FUNCTION_TAG, | |
565 kUnresolvedFunctionName)) { | |
566 } | |
567 | |
568 | 561 |
569 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 562 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
570 std::vector<CodeEntry*> entries; | 563 std::vector<CodeEntry*> entries; |
571 // Conservatively reserve space for stack frames + pc + function + vm-state. | 564 // Conservatively reserve space for stack frames + pc + function + vm-state. |
572 // There could in fact be more of them because of inlined entries. | 565 // There could in fact be more of them because of inlined entries. |
573 entries.reserve(sample.frames_count + 3); | 566 entries.reserve(sample.frames_count + 3); |
574 | 567 |
575 // The ProfileNode knows nothing about all versions of generated code for | 568 // The ProfileNode knows nothing about all versions of generated code for |
576 // the same JS function. The line number information associated with | 569 // the same JS function. The line number information associated with |
577 // the latest version of generated code is used to find a source line number | 570 // the latest version of generated code is used to find a source line number |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
610 | 603 |
611 if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || | 604 if (pc_entry->builtin_id() == Builtins::kFunctionPrototypeApply || |
612 pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { | 605 pc_entry->builtin_id() == Builtins::kFunctionPrototypeCall) { |
613 // When current function is either the Function.prototype.apply or the | 606 // When current function is either the Function.prototype.apply or the |
614 // Function.prototype.call builtin the top frame is either frame of | 607 // Function.prototype.call builtin the top frame is either frame of |
615 // the calling JS function or internal frame. | 608 // the calling JS function or internal frame. |
616 // In the latter case we know the caller for sure but in the | 609 // In the latter case we know the caller for sure but in the |
617 // former case we don't so we simply replace the frame with | 610 // former case we don't so we simply replace the frame with |
618 // 'unresolved' entry. | 611 // 'unresolved' entry. |
619 if (!sample.has_external_callback) { | 612 if (!sample.has_external_callback) { |
620 entries.push_back(unresolved_entry_); | 613 entries.push_back(CodeEntry::unresolved_entry()); |
621 } | 614 } |
622 } | 615 } |
623 } | 616 } |
624 } | 617 } |
625 | 618 |
626 for (const Address *stack_pos = sample.stack, | 619 for (const Address *stack_pos = sample.stack, |
627 *stack_end = stack_pos + sample.frames_count; | 620 *stack_end = stack_pos + sample.frames_count; |
628 stack_pos != stack_end; ++stack_pos) { | 621 stack_pos != stack_end; ++stack_pos) { |
629 CodeEntry* entry = code_map_.FindEntry(*stack_pos); | 622 CodeEntry* entry = code_map_.FindEntry(*stack_pos); |
630 | 623 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
667 } | 660 } |
668 | 661 |
669 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, | 662 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line, |
670 sample.update_stats); | 663 sample.update_stats); |
671 } | 664 } |
672 | 665 |
673 | 666 |
674 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { | 667 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { |
675 switch (tag) { | 668 switch (tag) { |
676 case GC: | 669 case GC: |
677 return gc_entry_; | 670 return CodeEntry::gc_entry(); |
678 case JS: | 671 case JS: |
679 case COMPILER: | 672 case COMPILER: |
680 // DOM events handlers are reported as OTHER / EXTERNAL entries. | 673 // DOM events handlers are reported as OTHER / EXTERNAL entries. |
681 // To avoid confusing people, let's put all these entries into | 674 // To avoid confusing people, let's put all these entries into |
682 // one bucket. | 675 // one bucket. |
683 case OTHER: | 676 case OTHER: |
684 case EXTERNAL: | 677 case EXTERNAL: |
685 return program_entry_; | 678 return CodeEntry::program_entry(); |
686 case IDLE: | 679 case IDLE: |
687 return idle_entry_; | 680 return CodeEntry::idle_entry(); |
688 default: return NULL; | 681 default: return NULL; |
689 } | 682 } |
690 } | 683 } |
691 | 684 |
692 } // namespace internal | 685 } // namespace internal |
693 } // namespace v8 | 686 } // namespace v8 |
OLD | NEW |