Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(658)

Side by Side Diff: runtime/vm/profiler.cc

Issue 131853007: Add flag to control number of stack frames collected by profiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "platform/utils.h" 5 #include "platform/utils.h"
6 6
7 #include "vm/allocation.h" 7 #include "vm/allocation.h"
8 #include "vm/atomic.h" 8 #include "vm/atomic.h"
9 #include "vm/code_patcher.h" 9 #include "vm/code_patcher.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
11 #include "vm/json_stream.h" 11 #include "vm/json_stream.h"
12 #include "vm/native_symbol.h" 12 #include "vm/native_symbol.h"
13 #include "vm/object.h" 13 #include "vm/object.h"
14 #include "vm/os.h" 14 #include "vm/os.h"
15 #include "vm/profiler.h" 15 #include "vm/profiler.h"
16 #include "vm/signal_handler.h" 16 #include "vm/signal_handler.h"
17 #include "vm/simulator.h" 17 #include "vm/simulator.h"
18 18
19 namespace dart { 19 namespace dart {
20 20
21 21
22 // Notes on stack frame walking:
23 //
24 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames
25 // The stack frame walking code uses the frame pointer to traverse the stack.
26 // If the VM is compiled without frame pointers (which is the default on
27 // recent GCC versions with optimizing enabled) the stack walking code may
28 // fail (sometimes leading to a crash).
29 //
30
31 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \ 22 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
32 defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID) 23 defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID)
33 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); 24 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
34 #else 25 #else
35 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); 26 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
36 #endif 27 #endif
37 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); 28 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
38 DEFINE_FLAG(charp, profile_dir, NULL, 29 DEFINE_FLAG(charp, profile_dir, NULL,
39 "Enable writing profile data into specified directory."); 30 "Enable writing profile data into specified directory.");
40 DEFINE_FLAG(int, profile_period, 1000, 31 DEFINE_FLAG(int, profile_period, 1000,
41 "Time between profiler samples in microseconds. Minimum 250."); 32 "Time between profiler samples in microseconds. Minimum 250.");
33 DEFINE_FLAG(int, profile_frames, 8,
34 "Maximum number stack frames walked. Minimum 1.");
siva 2014/01/16 23:34:23 maybe profile_frames_depth
Cutch 2014/01/17 16:02:25 profile_depth.
42 35
43 bool Profiler::initialized_ = false; 36 bool Profiler::initialized_ = false;
44 Monitor* Profiler::monitor_ = NULL;
45 SampleBuffer* Profiler::sample_buffer_ = NULL; 37 SampleBuffer* Profiler::sample_buffer_ = NULL;
46 38
47 void Profiler::InitOnce() { 39 void Profiler::InitOnce() {
48 const int kMinimumProfilePeriod = 250; 40 const int kMinimumProfilePeriod = 250;
41 const int kMinimumFrames = 1;
siva 2014/01/16 23:34:23 We probably also want a max (not letting people ar
Cutch 2014/01/17 16:02:25 Max of 128.
49 if (!FLAG_profile) { 42 if (!FLAG_profile) {
50 return; 43 return;
51 } 44 }
52 ASSERT(!initialized_); 45 ASSERT(!initialized_);
53 initialized_ = true; 46 if (FLAG_profile_period < kMinimumProfilePeriod) {
54 monitor_ = new Monitor(); 47 FLAG_profile_period = kMinimumProfilePeriod;
48 }
49 if (FLAG_profile_frames < kMinimumFrames) {
50 FLAG_profile_frames = kMinimumFrames;
51 }
55 sample_buffer_ = new SampleBuffer(); 52 sample_buffer_ = new SampleBuffer();
56 NativeSymbolResolver::InitOnce(); 53 NativeSymbolResolver::InitOnce();
57 ThreadInterrupter::InitOnce(); 54 ThreadInterrupter::InitOnce();
58 if (FLAG_profile_period < kMinimumProfilePeriod) {
59 FLAG_profile_period = kMinimumProfilePeriod;
60 }
61 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); 55 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period);
56 initialized_ = true;
62 } 57 }
63 58
64 59
65 void Profiler::Shutdown() { 60 void Profiler::Shutdown() {
66 if (!FLAG_profile) { 61 if (!FLAG_profile) {
67 return; 62 return;
68 } 63 }
69 ASSERT(initialized_); 64 ASSERT(initialized_);
70 ThreadInterrupter::Shutdown(); 65 ThreadInterrupter::Shutdown();
71 NativeSymbolResolver::ShutdownOnce(); 66 NativeSymbolResolver::ShutdownOnce();
72 } 67 }
73 68
74 69
75 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) { 70 void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
76 if (!FLAG_profile) { 71 if (!FLAG_profile) {
77 return; 72 return;
78 } 73 }
79 ASSERT(isolate != NULL); 74 ASSERT(isolate != NULL);
80 ASSERT(sample_buffer_ != NULL); 75 ASSERT(sample_buffer_ != NULL);
81 MonitorLocker ml(monitor_);
82 { 76 {
83 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 77 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
84 SampleBuffer* sample_buffer = sample_buffer_; 78 SampleBuffer* sample_buffer = sample_buffer_;
85 if (!shared_buffer) { 79 if (!shared_buffer) {
86 sample_buffer = new SampleBuffer(); 80 sample_buffer = new SampleBuffer();
87 } 81 }
88 IsolateProfilerData* profiler_data = 82 IsolateProfilerData* profiler_data =
89 new IsolateProfilerData(sample_buffer, !shared_buffer); 83 new IsolateProfilerData(sample_buffer, !shared_buffer);
90 ASSERT(profiler_data != NULL); 84 ASSERT(profiler_data != NULL);
91 isolate->set_profiler_data(profiler_data); 85 isolate->set_profiler_data(profiler_data);
92 if (FLAG_trace_profiled_isolates) { 86 if (FLAG_trace_profiled_isolates) {
93 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name()); 87 OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
94 } 88 }
95 } 89 }
96 } 90 }
97 91
98 92
99 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) { 93 void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
100 ASSERT(isolate != NULL); 94 ASSERT(isolate != NULL);
101 if (!FLAG_profile) { 95 if (!FLAG_profile) {
102 return; 96 return;
103 } 97 }
104 // We do not have a current isolate. 98 // We do not have a current isolate.
105 ASSERT(Isolate::Current() == NULL); 99 ASSERT(Isolate::Current() == NULL);
106 MonitorLocker ml(monitor_);
107 { 100 {
108 MutexLocker profiler_data_lock(isolate->profiler_data_mutex()); 101 MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
109 IsolateProfilerData* profiler_data = isolate->profiler_data(); 102 IsolateProfilerData* profiler_data = isolate->profiler_data();
110 if (profiler_data == NULL) { 103 if (profiler_data == NULL) {
111 // Already freed. 104 // Already freed.
112 return; 105 return;
113 } 106 }
114 isolate->set_profiler_data(NULL); 107 isolate->set_profiler_data(NULL);
115 delete profiler_data; 108 delete profiler_data;
116 if (FLAG_trace_profiled_isolates) { 109 if (FLAG_trace_profiled_isolates) {
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 // Enable profile interrupts. 526 // Enable profile interrupts.
534 BeginExecution(isolate); 527 BeginExecution(isolate);
535 } 528 }
536 529
537 530
538 intptr_t Profiler::ProcessSamples(Isolate* isolate, 531 intptr_t Profiler::ProcessSamples(Isolate* isolate,
539 ProfilerCodeRegionTable* code_region_table, 532 ProfilerCodeRegionTable* code_region_table,
540 SampleBuffer* sample_buffer) { 533 SampleBuffer* sample_buffer) {
541 int64_t start = OS::GetCurrentTimeMillis(); 534 int64_t start = OS::GetCurrentTimeMillis();
542 intptr_t samples = 0; 535 intptr_t samples = 0;
536 Sample* sample = Sample::Allocate();
543 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) { 537 for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
544 Sample sample = sample_buffer->GetSample(i); 538 sample_buffer->CopySample(i, sample);
545 if (sample.isolate != isolate) { 539 if (sample->isolate != isolate) {
546 continue; 540 continue;
547 } 541 }
548 if (sample.timestamp == 0) { 542 if (sample->timestamp == 0) {
549 continue; 543 continue;
550 } 544 }
551 samples += ProcessSample(isolate, code_region_table, &sample); 545 samples += ProcessSample(isolate, code_region_table, sample);
552 } 546 }
547 free(sample);
553 int64_t end = OS::GetCurrentTimeMillis(); 548 int64_t end = OS::GetCurrentTimeMillis();
554 if (FLAG_trace_profiled_isolates) { 549 if (FLAG_trace_profiled_isolates) {
555 int64_t delta = end - start; 550 int64_t delta = end - start;
556 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n", 551 OS::Print("Processed %" Pd " samples from %s in %" Pd64 " milliseconds.\n",
557 samples, 552 samples,
558 isolate->name(), 553 isolate->name(),
559 delta); 554 delta);
560 } 555 }
561 return samples; 556 return samples;
562 } 557 }
563 558
564 559
565 intptr_t Profiler::ProcessSample(Isolate* isolate, 560 intptr_t Profiler::ProcessSample(Isolate* isolate,
566 ProfilerCodeRegionTable* code_region_table, 561 ProfilerCodeRegionTable* code_region_table,
567 Sample* sample) { 562 Sample* sample) {
568 Sample::SampleType type = sample->type; 563 Sample::SampleType type = sample->type;
569 if (type != Sample::kIsolateSample) { 564 if (type != Sample::kIsolateSample) {
570 return 0; 565 return 0;
571 } 566 }
572 if (sample->pcs[0] == 0) { 567 if (sample->pcs[0] == 0) {
573 // No frames in this sample. 568 // No frames in this sample.
574 return 0; 569 return 0;
575 } 570 }
576 intptr_t i = 0; 571 intptr_t i = 0;
577 // i points to the leaf (exclusive) PC sample. Do not tick the address. 572 // i points to the leaf (exclusive) PC sample. Do not tick the address.
578 code_region_table->AddTick(sample->pcs[i], true, false); 573 code_region_table->AddTick(sample->pcs[i], true, false);
579 // Give all frames an inclusive tick and tick the address. 574 // Give all frames an inclusive tick and tick the address.
580 for (; i < Sample::kNumStackFrames; i++) { 575 for (; i < FLAG_profile_frames; i++) {
581 if (sample->pcs[i] == 0) { 576 if (sample->pcs[i] == 0) {
582 break; 577 break;
583 } 578 }
584 code_region_table->AddTick(sample->pcs[i], false, true); 579 code_region_table->AddTick(sample->pcs[i], false, true);
585 } 580 }
586 return 1; 581 return 1;
587 } 582 }
588 583
589 584
590 void Profiler::WriteProfile(Isolate* isolate) { 585 void Profiler::WriteProfile(Isolate* isolate) {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 633
639 IsolateProfilerData::~IsolateProfilerData() { 634 IsolateProfilerData::~IsolateProfilerData() {
640 if (own_sample_buffer_) { 635 if (own_sample_buffer_) {
641 delete sample_buffer_; 636 delete sample_buffer_;
642 sample_buffer_ = NULL; 637 sample_buffer_ = NULL;
643 own_sample_buffer_ = false; 638 own_sample_buffer_ = false;
644 } 639 }
645 } 640 }
646 641
647 642
643 void Sample::CopyInto(Sample* dst) const {
644 ASSERT(dst != NULL);
645 dst->timestamp = timestamp;
646 dst->tid = tid;
647 dst->isolate = isolate;
648 dst->type = type;
649 dst->vm_tags = vm_tags;
650 dst->runtime_tags = runtime_tags;
651 for (intptr_t i = 0; i < FLAG_profile_frames; i++) {
652 dst->pcs[i] = pcs[i];
653 }
654 }
655
656
657 Sample* Sample::Allocate() {
658 return reinterpret_cast<Sample*>(malloc(InstanceSize()));
659 }
660
661
662 intptr_t Sample::InstanceSize() {
663 ASSERT(FLAG_profile_frames >= 1);
664 return sizeof(Sample) + (sizeof(intptr_t) * FLAG_profile_frames); // NOLINT.
siva 2014/01/16 23:34:23 Why did you choose this to be a function instead o
Cutch 2014/01/17 16:02:25 Done.
665 }
666
667
648 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp, 668 void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp,
649 ThreadId tid) { 669 ThreadId tid) {
650 this->timestamp = timestamp; 670 this->timestamp = timestamp;
651 this->tid = tid; 671 this->tid = tid;
652 this->isolate = isolate; 672 this->isolate = isolate;
653 for (intptr_t i = 0; i < kNumStackFrames; i++) {
654 pcs[i] = 0;
655 }
656 this->type = type; 673 this->type = type;
657 vm_tags = 0; 674 vm_tags = 0;
658 runtime_tags = 0; 675 runtime_tags = 0;
676 for (int i = 0; i < FLAG_profile_frames; i++) {
677 pcs[i] = 0;
678 }
659 } 679 }
660 680
681
661 SampleBuffer::SampleBuffer(intptr_t capacity) { 682 SampleBuffer::SampleBuffer(intptr_t capacity) {
662 capacity_ = capacity; 683 capacity_ = capacity;
663 samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample))); 684 samples_ = reinterpret_cast<Sample*>(
685 calloc(capacity, Sample::InstanceSize()));
664 cursor_ = 0; 686 cursor_ = 0;
665 } 687 }
666 688
667 689
668 SampleBuffer::~SampleBuffer() { 690 SampleBuffer::~SampleBuffer() {
669 if (samples_ != NULL) { 691 if (samples_ != NULL) {
670 free(samples_); 692 free(samples_);
671 samples_ = NULL; 693 samples_ = NULL;
672 cursor_ = 0; 694 cursor_ = 0;
673 capacity_ = 0; 695 capacity_ = 0;
674 } 696 }
675 } 697 }
676 698
677 699
678 Sample* SampleBuffer::ReserveSample() { 700 Sample* SampleBuffer::ReserveSample() {
679 ASSERT(samples_ != NULL); 701 ASSERT(samples_ != NULL);
680 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); 702 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
681 // Map back into sample buffer range. 703 // Map back into sample buffer range.
682 cursor = cursor % capacity_; 704 cursor = cursor % capacity_;
683 return &samples_[cursor]; 705 return At(cursor);
684 } 706 }
685 707
686 708
709 void SampleBuffer::CopySample(intptr_t i, Sample* sample) const {
710 At(i)->CopyInto(sample);
711 }
712
713
714 Sample* SampleBuffer::At(intptr_t idx) const {
715 ASSERT(idx >= 0);
716 ASSERT(idx < capacity_);
717 intptr_t offset = idx * Sample::InstanceSize();
718 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_);
719 return reinterpret_cast<Sample*>(samples + offset);
720 }
721
722
687 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample, 723 ProfilerSampleStackWalker::ProfilerSampleStackWalker(Sample* sample,
688 uintptr_t stack_lower, 724 uintptr_t stack_lower,
689 uintptr_t stack_upper, 725 uintptr_t stack_upper,
690 uintptr_t pc, 726 uintptr_t pc,
691 uintptr_t fp, 727 uintptr_t fp,
692 uintptr_t sp) : 728 uintptr_t sp) :
693 sample_(sample), 729 sample_(sample),
694 stack_lower_(stack_lower), 730 stack_lower_(stack_lower),
695 stack_upper_(stack_upper), 731 stack_upper_(stack_upper),
696 original_pc_(pc), 732 original_pc_(pc),
697 original_fp_(fp), 733 original_fp_(fp),
698 original_sp_(sp), 734 original_sp_(sp),
699 lower_bound_(stack_lower) { 735 lower_bound_(stack_lower) {
700 ASSERT(sample_ != NULL); 736 ASSERT(sample_ != NULL);
701 // Zero out the PCs before (re)using the sample.
702 for (int i = 0; i < Sample::kNumStackFrames; i++) {
703 sample_->pcs[i] = 0;
704 }
705 } 737 }
706 738
707 739
740 // Notes on stack frame walking:
741 //
742 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames
743 // The stack frame walking code uses the frame pointer to traverse the stack.
744 // If the VM is compiled without frame pointers (which is the default on
745 // recent GCC versions with optimizing enabled) the stack walking code may
746 // fail (sometimes leading to a crash).
747 //
748
708 int ProfilerSampleStackWalker::walk() { 749 int ProfilerSampleStackWalker::walk() {
709 const intptr_t kMaxStep = 0x1000; // 4K. 750 const intptr_t kMaxStep = 0x1000; // 4K.
710 uword* pc = reinterpret_cast<uword*>(original_pc_); 751 uword* pc = reinterpret_cast<uword*>(original_pc_);
711 // Always store the exclusive PC. 752 // Always store the exclusive PC.
712 sample_->pcs[0] = original_pc_; 753 sample_->pcs[0] = original_pc_;
713 #define WALK_STACK 754 #define WALK_STACK
714 #if defined(WALK_STACK) 755 #if defined(WALK_STACK)
715 uword* fp = reinterpret_cast<uword*>(original_fp_); 756 uword* fp = reinterpret_cast<uword*>(original_fp_);
716 uword* previous_fp = fp; 757 uword* previous_fp = fp;
717 if (original_sp_ > original_fp_) { 758 if (original_sp_ > original_fp_) {
718 // Stack pointer should not be above frame pointer. 759 // Stack pointer should not be above frame pointer.
719 return 1; 760 return 1;
720 } 761 }
721 intptr_t gap = original_fp_ - original_sp_; 762 intptr_t gap = original_fp_ - original_sp_;
722 if (gap >= kMaxStep) { 763 if (gap >= kMaxStep) {
723 // Gap between frame pointer and stack pointer is 764 // Gap between frame pointer and stack pointer is
724 // too large. 765 // too large.
725 return 1; 766 return 1;
726 } 767 }
727 if (original_sp_ < lower_bound_) { 768 if (original_sp_ < lower_bound_) {
728 // The stack pointer gives us a better lower bound than 769 // The stack pointer gives us a better lower bound than
729 // the isolates stack limit. 770 // the isolates stack limit.
730 lower_bound_ = original_sp_; 771 lower_bound_ = original_sp_;
731 } 772 }
732 int i = 0; 773 int i = 0;
733 for (; i < Sample::kNumStackFrames; i++) { 774 for (; i < FLAG_profile_frames; i++) {
734 sample_->pcs[i] = reinterpret_cast<uintptr_t>(pc); 775 sample_->pcs[i] = reinterpret_cast<uintptr_t>(pc);
735 if (!ValidFramePointer(fp)) { 776 if (!ValidFramePointer(fp)) {
736 return i + 1; 777 return i + 1;
737 } 778 }
738 pc = CallerPC(fp); 779 pc = CallerPC(fp);
739 previous_fp = fp; 780 previous_fp = fp;
740 fp = CallerFP(fp); 781 fp = CallerFP(fp);
741 intptr_t step = fp - previous_fp; 782 intptr_t step = fp - previous_fp;
742 if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) { 783 if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) {
743 // Frame pointer step is too large. 784 // Frame pointer step is too large.
(...skipping 29 matching lines...) Expand all
773 return false; 814 return false;
774 } 815 }
775 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp); 816 uintptr_t cursor = reinterpret_cast<uintptr_t>(fp);
776 cursor += sizeof(fp); 817 cursor += sizeof(fp);
777 bool r = cursor >= lower_bound_ && cursor < stack_upper_; 818 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
778 return r; 819 return r;
779 } 820 }
780 821
781 822
782 } // namespace dart 823 } // namespace dart
OLDNEW
« runtime/vm/profiler.h ('K') | « runtime/vm/profiler.h ('k') | runtime/vm/profiler_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698