Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/address_sanitizer.h" | 5 #include "platform/address_sanitizer.h" |
| 6 #include "platform/memory_sanitizer.h" | 6 #include "platform/memory_sanitizer.h" |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 | 8 |
| 9 #include "vm/allocation.h" | 9 #include "vm/allocation.h" |
| 10 #include "vm/atomic.h" | 10 #include "vm/atomic.h" |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 161 | 161 |
| 162 Sample* SampleBuffer::ReserveSample() { | 162 Sample* SampleBuffer::ReserveSample() { |
| 163 return At(ReserveSampleSlot()); | 163 return At(ReserveSampleSlot()); |
| 164 } | 164 } |
| 165 | 165 |
| 166 | 166 |
| 167 Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) { | 167 Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) { |
| 168 ASSERT(previous != NULL); | 168 ASSERT(previous != NULL); |
| 169 intptr_t next_index = ReserveSampleSlot(); | 169 intptr_t next_index = ReserveSampleSlot(); |
| 170 Sample* next = At(next_index); | 170 Sample* next = At(next_index); |
| 171 next->Init(previous->isolate(), previous->timestamp(), previous->tid()); | 171 next->Init(previous->port(), previous->timestamp(), previous->tid()); |
| 172 next->set_head_sample(false); | 172 next->set_head_sample(false); |
| 173 // Mark that previous continues at next. | 173 // Mark that previous continues at next. |
| 174 previous->SetContinuationIndex(next_index); | 174 previous->SetContinuationIndex(next_index); |
| 175 return next; | 175 return next; |
| 176 } | 176 } |
| 177 | 177 |
| 178 | 178 |
| 179 // Attempts to find the true return address when a Dart frame is being setup | 179 // Attempts to find the true return address when a Dart frame is being setup |
| 180 // or torn down. | 180 // or torn down. |
| 181 // NOTE: Architecture specific implementations below. | 181 // NOTE: Architecture specific implementations below. |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 314 } | 314 } |
| 315 | 315 |
| 316 | 316 |
| 317 bool SampleFilter::TaskFilterSample(Sample* sample) { | 317 bool SampleFilter::TaskFilterSample(Sample* sample) { |
| 318 const intptr_t task = static_cast<intptr_t>(sample->thread_task()); | 318 const intptr_t task = static_cast<intptr_t>(sample->thread_task()); |
| 319 return (task & thread_task_mask_) != 0; | 319 return (task & thread_task_mask_) != 0; |
| 320 } | 320 } |
| 321 | 321 |
| 322 | 322 |
| 323 ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate) | 323 ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate) |
| 324 : SampleVisitor(isolate) {} | 324 : SampleVisitor(isolate->main_port()) {} |
| 325 | 325 |
| 326 | 326 |
| 327 void ClearProfileVisitor::VisitSample(Sample* sample) { | 327 void ClearProfileVisitor::VisitSample(Sample* sample) { |
| 328 sample->Clear(); | 328 sample->Clear(); |
| 329 } | 329 } |
| 330 | 330 |
| 331 | 331 |
| 332 static void DumpStackFrame(intptr_t frame_index, uword pc) { | 332 static void DumpStackFrame(intptr_t frame_index, uword pc) { |
| 333 Isolate* isolate = Isolate::Current(); | 333 Isolate* isolate = Isolate::Current(); |
| 334 if ((isolate != NULL) && isolate->is_runnable()) { | 334 if ((isolate != NULL) && isolate->is_runnable()) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 350 OS::PrintErr(" [0x%" Pp "] Unknown symbol\n", pc); | 350 OS::PrintErr(" [0x%" Pp "] Unknown symbol\n", pc); |
| 351 } else { | 351 } else { |
| 352 OS::PrintErr(" [0x%" Pp "] %s\n", pc, native_symbol_name); | 352 OS::PrintErr(" [0x%" Pp "] %s\n", pc, native_symbol_name); |
| 353 NativeSymbolResolver::FreeSymbolName(native_symbol_name); | 353 NativeSymbolResolver::FreeSymbolName(native_symbol_name); |
| 354 } | 354 } |
| 355 } | 355 } |
| 356 | 356 |
| 357 | 357 |
| 358 class ProfilerStackWalker : public ValueObject { | 358 class ProfilerStackWalker : public ValueObject { |
| 359 public: | 359 public: |
| 360 ProfilerStackWalker(Isolate* isolate, | 360 ProfilerStackWalker(Dart_Port port_id, |
| 361 Sample* head_sample, | 361 Sample* head_sample, |
| 362 SampleBuffer* sample_buffer) | 362 SampleBuffer* sample_buffer, |
| 363 : isolate_(isolate), | 363 intptr_t skip_count = 0) |
| 364 : port_id_(port_id), | |
| 364 sample_(head_sample), | 365 sample_(head_sample), |
| 365 sample_buffer_(sample_buffer), | 366 sample_buffer_(sample_buffer), |
| 367 skip_count_(skip_count), | |
| 368 frames_skipped_(0), | |
| 366 frame_index_(0), | 369 frame_index_(0), |
| 367 total_frames_(0) { | 370 total_frames_(0) { |
| 368 ASSERT(isolate_ != NULL); | |
| 369 if (sample_ == NULL) { | 371 if (sample_ == NULL) { |
| 370 ASSERT(sample_buffer_ == NULL); | 372 ASSERT(sample_buffer_ == NULL); |
| 371 } else { | 373 } else { |
| 372 ASSERT(sample_buffer_ != NULL); | 374 ASSERT(sample_buffer_ != NULL); |
| 373 ASSERT(sample_->head_sample()); | 375 ASSERT(sample_->head_sample()); |
| 374 } | 376 } |
| 375 } | 377 } |
| 376 | 378 |
| 377 bool Append(uword pc) { | 379 bool Append(uword pc) { |
| 380 if (frames_skipped_ < skip_count_) { | |
| 381 frames_skipped_++; | |
| 382 return true; | |
| 383 } | |
| 384 | |
| 378 if (sample_ == NULL) { | 385 if (sample_ == NULL) { |
| 379 DumpStackFrame(frame_index_, pc); | 386 DumpStackFrame(frame_index_, pc); |
| 380 frame_index_++; | 387 frame_index_++; |
| 381 total_frames_++; | 388 total_frames_++; |
| 382 return true; | 389 return true; |
| 383 } | 390 } |
| 384 if (total_frames_ >= FLAG_max_profile_depth) { | 391 if (total_frames_ >= FLAG_max_profile_depth) { |
| 385 sample_->set_truncated_trace(true); | 392 sample_->set_truncated_trace(true); |
| 386 return false; | 393 return false; |
| 387 } | 394 } |
| 388 ASSERT(sample_ != NULL); | 395 ASSERT(sample_ != NULL); |
| 389 if (frame_index_ == kSampleSize) { | 396 if (frame_index_ == kSampleSize) { |
| 390 Sample* new_sample = sample_buffer_->ReserveSampleAndLink(sample_); | 397 Sample* new_sample = sample_buffer_->ReserveSampleAndLink(sample_); |
| 391 if (new_sample == NULL) { | 398 if (new_sample == NULL) { |
| 392 // Could not reserve new sample- mark this as truncated. | 399 // Could not reserve new sample- mark this as truncated. |
| 393 sample_->set_truncated_trace(true); | 400 sample_->set_truncated_trace(true); |
| 394 return false; | 401 return false; |
| 395 } | 402 } |
| 396 frame_index_ = 0; | 403 frame_index_ = 0; |
| 397 sample_ = new_sample; | 404 sample_ = new_sample; |
| 398 } | 405 } |
| 399 ASSERT(frame_index_ < kSampleSize); | 406 ASSERT(frame_index_ < kSampleSize); |
| 400 sample_->SetAt(frame_index_, pc); | 407 sample_->SetAt(frame_index_, pc); |
| 401 frame_index_++; | 408 frame_index_++; |
| 402 total_frames_++; | 409 total_frames_++; |
| 403 return true; | 410 return true; |
| 404 } | 411 } |
| 405 | 412 |
| 406 protected: | 413 protected: |
| 407 Isolate* isolate_; | 414 Dart_Port port_id_; |
| 408 Sample* sample_; | 415 Sample* sample_; |
| 409 SampleBuffer* sample_buffer_; | 416 SampleBuffer* sample_buffer_; |
| 417 intptr_t skip_count_; | |
| 418 intptr_t frames_skipped_; | |
| 410 intptr_t frame_index_; | 419 intptr_t frame_index_; |
| 411 intptr_t total_frames_; | 420 intptr_t total_frames_; |
| 412 }; | 421 }; |
| 413 | 422 |
| 414 | 423 |
| 415 // Executing Dart code, walk the stack. | 424 // Executing Dart code, walk the stack. |
| 416 class ProfilerDartStackWalker : public ProfilerStackWalker { | 425 class ProfilerDartStackWalker : public ProfilerStackWalker { |
| 417 public: | 426 public: |
| 418 ProfilerDartStackWalker(Thread* thread, | 427 ProfilerDartStackWalker(Thread* thread, |
| 419 Sample* sample, | 428 Sample* sample, |
| 420 SampleBuffer* sample_buffer, | 429 SampleBuffer* sample_buffer, |
| 421 uword stack_lower, | 430 uword stack_lower, |
| 422 uword stack_upper, | 431 uword stack_upper, |
| 423 uword pc, | 432 uword pc, |
| 424 uword fp, | 433 uword fp, |
| 425 uword sp, | 434 uword sp, |
| 426 bool exited_dart_code, | 435 bool exited_dart_code, |
| 427 bool allocation_sample) | 436 bool allocation_sample, |
| 428 : ProfilerStackWalker(thread->isolate(), sample, sample_buffer), | 437 intptr_t skip_count = 0) |
| 438 : ProfilerStackWalker((thread->isolate() != NULL) | |
| 439 ? thread->isolate()->main_port() | |
| 440 : ILLEGAL_PORT, | |
| 441 sample, | |
| 442 sample_buffer, | |
| 443 skip_count), | |
| 429 pc_(reinterpret_cast<uword*>(pc)), | 444 pc_(reinterpret_cast<uword*>(pc)), |
| 430 fp_(reinterpret_cast<uword*>(fp)), | 445 fp_(reinterpret_cast<uword*>(fp)), |
| 431 sp_(reinterpret_cast<uword*>(sp)), | 446 sp_(reinterpret_cast<uword*>(sp)), |
| 432 stack_upper_(stack_upper), | 447 stack_upper_(stack_upper), |
| 433 stack_lower_(stack_lower), | 448 stack_lower_(stack_lower), |
| 434 has_exit_frame_(exited_dart_code) { | 449 has_exit_frame_(exited_dart_code) { |
| 435 if (exited_dart_code) { | 450 if (exited_dart_code) { |
| 436 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, | 451 StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames, |
| 437 thread); | 452 thread); |
| 438 pc_ = NULL; | 453 pc_ = NULL; |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 bool has_exit_frame_; | 605 bool has_exit_frame_; |
| 591 }; | 606 }; |
| 592 | 607 |
| 593 | 608 |
| 594 // If the VM is compiled without frame pointers (which is the default on | 609 // If the VM is compiled without frame pointers (which is the default on |
| 595 // recent GCC versions with optimizing enabled) the stack walking code may | 610 // recent GCC versions with optimizing enabled) the stack walking code may |
| 596 // fail. | 611 // fail. |
| 597 // | 612 // |
| 598 class ProfilerNativeStackWalker : public ProfilerStackWalker { | 613 class ProfilerNativeStackWalker : public ProfilerStackWalker { |
| 599 public: | 614 public: |
| 600 ProfilerNativeStackWalker(Isolate* isolate, | 615 ProfilerNativeStackWalker(Dart_Port port_id, |
| 601 Sample* sample, | 616 Sample* sample, |
| 602 SampleBuffer* sample_buffer, | 617 SampleBuffer* sample_buffer, |
| 603 uword stack_lower, | 618 uword stack_lower, |
| 604 uword stack_upper, | 619 uword stack_upper, |
| 605 uword pc, | 620 uword pc, |
| 606 uword fp, | 621 uword fp, |
| 607 uword sp) | 622 uword sp, |
| 608 : ProfilerStackWalker(isolate, sample, sample_buffer), | 623 intptr_t skip_count = 0) |
| 624 : ProfilerStackWalker(port_id, sample, sample_buffer, skip_count), | |
| 609 stack_upper_(stack_upper), | 625 stack_upper_(stack_upper), |
| 610 original_pc_(pc), | 626 original_pc_(pc), |
| 611 original_fp_(fp), | 627 original_fp_(fp), |
| 612 original_sp_(sp), | 628 original_sp_(sp), |
| 613 lower_bound_(stack_lower) {} | 629 lower_bound_(stack_lower) {} |
| 614 | 630 |
| 615 void walk() { | 631 void walk() { |
| 616 const uword kMaxStep = VirtualMemory::PageSize(); | 632 const uword kMaxStep = VirtualMemory::PageSize(); |
| 633 | |
| 617 Append(original_pc_); | 634 Append(original_pc_); |
| 618 | 635 |
| 619 uword* pc = reinterpret_cast<uword*>(original_pc_); | 636 uword* pc = reinterpret_cast<uword*>(original_pc_); |
| 620 uword* fp = reinterpret_cast<uword*>(original_fp_); | 637 uword* fp = reinterpret_cast<uword*>(original_fp_); |
| 621 uword* previous_fp = fp; | 638 uword* previous_fp = fp; |
| 622 | 639 |
| 623 uword gap = original_fp_ - original_sp_; | 640 uword gap = original_fp_ - original_sp_; |
| 624 if (gap >= kMaxStep) { | 641 if (gap >= kMaxStep) { |
| 625 // Gap between frame pointer and stack pointer is | 642 // Gap between frame pointer and stack pointer is |
| 626 // too large. | 643 // too large. |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 VirtualProtect(reinterpret_cast<void*>(fault_address), | 806 VirtualProtect(reinterpret_cast<void*>(fault_address), |
| 790 sizeof(fault_address), new_protect, &old_protect); | 807 sizeof(fault_address), new_protect, &old_protect); |
| 791 USE(success); | 808 USE(success); |
| 792 ASSERT(success); | 809 ASSERT(success); |
| 793 ASSERT(old_protect == PAGE_READWRITE); | 810 ASSERT(old_protect == PAGE_READWRITE); |
| 794 } | 811 } |
| 795 #endif | 812 #endif |
| 796 } | 813 } |
| 797 | 814 |
| 798 | 815 |
| 816 static bool ValidateThreadStackBounds(uintptr_t fp, | |
| 817 uintptr_t sp, | |
| 818 uword stack_lower, | |
| 819 uword stack_upper) { | |
| 820 if (stack_lower >= stack_upper) { | |
| 821 // Stack boundary is invalid. | |
| 822 return false; | |
| 823 } | |
| 824 | |
| 825 if ((sp < stack_lower) || (sp >= stack_upper)) { | |
| 826 // Stack pointer is outside thread's stack boundary. | |
| 827 return false; | |
| 828 } | |
| 829 | |
| 830 if ((fp < stack_lower) || (fp >= stack_upper)) { | |
| 831 // Frame pointer is outside threads's stack boundary. | |
| 832 return false; | |
| 833 } | |
| 834 | |
| 835 return true; | |
| 836 } | |
| 837 | |
| 838 | |
| 799 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within | 839 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within |
| 800 // it. If |get_os_thread_bounds| is true then if |isolate| stackbounds are | 840 // it. If |get_os_thread_bounds| is true then if |isolate| stackbounds are |
| 801 // not available we fallback to using underlying OS thread bounds. This only | 841 // not available we fallback to using underlying OS thread bounds. This only |
| 802 // works for the current thread. | 842 // works for the current thread. |
| 803 // Return |false| if anything looks suspicious. | 843 // Return |false| if anything looks suspicious. |
| 804 static bool GetAndValidateThreadStackBounds(Thread* thread, | 844 static bool GetAndValidateThreadStackBounds(Thread* thread, |
| 805 uintptr_t fp, | 845 uintptr_t fp, |
| 806 uintptr_t sp, | 846 uintptr_t sp, |
| 807 uword* stack_lower, | 847 uword* stack_lower, |
| 808 uword* stack_upper, | 848 uword* stack_upper, |
| 809 bool get_os_thread_bounds = false) { | 849 bool get_os_thread_bounds = false) { |
| 810 ASSERT(thread != NULL); | 850 OSThread* os_thread = NULL; |
| 811 OSThread* os_thread = thread->os_thread(); | 851 if (thread != NULL) { |
| 852 os_thread = thread->os_thread(); | |
| 853 } else { | |
| 854 os_thread = OSThread::Current(); | |
| 855 } | |
| 812 ASSERT(os_thread != NULL); | 856 ASSERT(os_thread != NULL); |
| 813 ASSERT(stack_lower != NULL); | 857 ASSERT(stack_lower != NULL); |
| 814 ASSERT(stack_upper != NULL); | 858 ASSERT(stack_upper != NULL); |
| 815 ASSERT(!get_os_thread_bounds || (Thread::Current() == thread)); | 859 ASSERT(!get_os_thread_bounds || (Thread::Current() == thread)); |
| 816 | 860 |
| 817 #if defined(USING_SIMULATOR) | 861 #if defined(USING_SIMULATOR) |
| 818 const bool use_simulator_stack_bounds = thread->IsExecutingDartCode(); | 862 const bool use_simulator_stack_bounds = thread->IsExecutingDartCode(); |
| 819 if (use_simulator_stack_bounds) { | 863 if (use_simulator_stack_bounds) { |
| 820 Isolate* isolate = thread->isolate(); | 864 Isolate* isolate = thread->isolate(); |
| 821 ASSERT(isolate != NULL); | 865 ASSERT(isolate != NULL); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 837 | 881 |
| 838 if ((*stack_lower == 0) || (*stack_upper == 0)) { | 882 if ((*stack_lower == 0) || (*stack_upper == 0)) { |
| 839 return false; | 883 return false; |
| 840 } | 884 } |
| 841 | 885 |
| 842 if (!use_simulator_stack_bounds && (sp > *stack_lower)) { | 886 if (!use_simulator_stack_bounds && (sp > *stack_lower)) { |
| 843 // The stack pointer gives us a tighter lower bound. | 887 // The stack pointer gives us a tighter lower bound. |
| 844 *stack_lower = sp; | 888 *stack_lower = sp; |
| 845 } | 889 } |
| 846 | 890 |
| 847 if (*stack_lower >= *stack_upper) { | 891 return ValidateThreadStackBounds(fp, sp, *stack_lower, *stack_upper); |
| 848 // Stack boundary is invalid. | |
| 849 return false; | |
| 850 } | |
| 851 | |
| 852 if ((sp < *stack_lower) || (sp >= *stack_upper)) { | |
| 853 // Stack pointer is outside thread's stack boundary. | |
| 854 return false; | |
| 855 } | |
| 856 | |
| 857 if ((fp < *stack_lower) || (fp >= *stack_upper)) { | |
| 858 // Frame pointer is outside threads's stack boundary. | |
| 859 return false; | |
| 860 } | |
| 861 | |
| 862 return true; | |
| 863 } | 892 } |
| 864 | 893 |
| 865 | 894 |
| 866 // Some simple sanity checking of |pc|, |fp|, and |sp|. | 895 // Some simple sanity checking of |pc|, |fp|, and |sp|. |
| 867 static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) { | 896 static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) { |
| 868 if ((sp == 0) || (fp == 0) || (pc == 0)) { | 897 if ((sp == 0) || (fp == 0) || (pc == 0)) { |
| 869 // None of these registers should be zero. | 898 // None of these registers should be zero. |
| 870 return false; | 899 return false; |
| 871 } | 900 } |
| 872 | 901 |
| 873 if (sp > fp) { | 902 if (sp > fp) { |
| 874 // Assuming the stack grows down, we should never have a stack pointer above | 903 // Assuming the stack grows down, we should never have a stack pointer above |
| 875 // the frame pointer. | 904 // the frame pointer. |
| 876 return false; | 905 return false; |
| 877 } | 906 } |
| 878 | 907 |
| 879 return true; | 908 return true; |
| 880 } | 909 } |
| 881 | 910 |
| 882 | 911 |
| 883 static Sample* SetupSample(Thread* thread, | 912 static Sample* SetupSample(Thread* thread, |
| 884 SampleBuffer* sample_buffer, | 913 SampleBuffer* sample_buffer, |
| 885 ThreadId tid) { | 914 ThreadId tid) { |
| 886 ASSERT(thread != NULL); | 915 ASSERT(thread != NULL); |
| 887 Isolate* isolate = thread->isolate(); | 916 Isolate* isolate = thread->isolate(); |
| 888 ASSERT(sample_buffer != NULL); | 917 ASSERT(sample_buffer != NULL); |
| 889 Sample* sample = sample_buffer->ReserveSample(); | 918 Sample* sample = sample_buffer->ReserveSample(); |
| 890 sample->Init(isolate, OS::GetCurrentMonotonicMicros(), tid); | 919 sample->Init(isolate->main_port(), OS::GetCurrentMonotonicMicros(), tid); |
| 891 uword vm_tag = thread->vm_tag(); | 920 uword vm_tag = thread->vm_tag(); |
| 892 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) | 921 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) |
| 893 // When running in the simulator, the runtime entry function address | 922 // When running in the simulator, the runtime entry function address |
| 894 // (stored as the vm tag) is the address of a redirect function. | 923 // (stored as the vm tag) is the address of a redirect function. |
| 895 // Attempt to find the real runtime entry function address and use that. | 924 // Attempt to find the real runtime entry function address and use that. |
| 896 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); | 925 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); |
| 897 if (redirect_vm_tag != 0) { | 926 if (redirect_vm_tag != 0) { |
| 898 vm_tag = redirect_vm_tag; | 927 vm_tag = redirect_vm_tag; |
| 899 } | 928 } |
| 900 #endif | 929 #endif |
| 901 sample->set_vm_tag(vm_tag); | 930 sample->set_vm_tag(vm_tag); |
| 902 sample->set_user_tag(isolate->user_tag()); | 931 sample->set_user_tag(isolate->user_tag()); |
| 903 sample->set_thread_task(thread->task_kind()); | 932 sample->set_thread_task(thread->task_kind()); |
| 904 return sample; | 933 return sample; |
| 905 } | 934 } |
| 906 | 935 |
| 907 | 936 |
| 937 static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) { | |
| 938 Sample* sample = sample_buffer->ReserveSample(); | |
| 939 sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid); | |
| 940 | |
| 941 Thread* thread = Thread::Current(); | |
| 942 | |
| 943 // TODO(bkonyi) Any samples created while a current thread doesn't exist are | |
| 944 // ignored by the NativeAllocationSampleFilter since the default task is | |
| 945 // kUnknownTask. Is this what we want to do? | |
| 946 if (thread != NULL) { | |
| 947 sample->set_thread_task(thread->task_kind()); | |
| 948 } | |
| 949 return sample; | |
| 950 } | |
| 951 | |
| 952 | |
| 908 static bool CheckIsolate(Isolate* isolate) { | 953 static bool CheckIsolate(Isolate* isolate) { |
| 909 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { | 954 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| 910 // No isolate. | 955 // No isolate. |
| 911 return false; | 956 return false; |
| 912 } | 957 } |
| 913 return isolate != Dart::vm_isolate(); | 958 return isolate != Dart::vm_isolate(); |
| 914 } | 959 } |
| 915 | 960 |
| 916 | 961 |
| 917 #if defined(TARGET_OS_WINDOWS) | |
| 918 __declspec(noinline) static uintptr_t GetProgramCounter() { | |
| 919 return reinterpret_cast<uintptr_t>(_ReturnAddress()); | |
| 920 } | |
| 921 #else | |
| 922 static uintptr_t __attribute__((noinline)) GetProgramCounter() { | |
| 923 return reinterpret_cast<uintptr_t>( | |
| 924 __builtin_extract_return_addr(__builtin_return_address(0))); | |
| 925 } | |
| 926 #endif | |
| 927 | |
| 928 | |
| 929 void Profiler::DumpStackTrace(void* context) { | 962 void Profiler::DumpStackTrace(void* context) { |
| 930 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS) | 963 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS) |
| 931 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 964 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 932 mcontext_t mcontext = ucontext->uc_mcontext; | 965 mcontext_t mcontext = ucontext->uc_mcontext; |
| 933 uword pc = SignalHandler::GetProgramCounter(mcontext); | 966 uword pc = SignalHandler::GetProgramCounter(mcontext); |
| 934 uword fp = SignalHandler::GetFramePointer(mcontext); | 967 uword fp = SignalHandler::GetFramePointer(mcontext); |
| 935 uword sp = SignalHandler::GetCStackPointer(mcontext); | 968 uword sp = SignalHandler::GetCStackPointer(mcontext); |
| 936 DumpStackTrace(sp, fp, pc); | 969 DumpStackTrace(sp, fp, pc); |
| 937 #else | 970 #else |
| 938 // TODO(fschneider): Add support for more platforms. | 971 // TODO(fschneider): Add support for more platforms. |
| 939 // Do nothing on unsupported platforms. | 972 // Do nothing on unsupported platforms. |
| 940 #endif | 973 #endif |
| 941 } | 974 } |
| 942 | 975 |
| 943 | 976 |
| 944 void Profiler::DumpStackTrace() { | 977 void Profiler::DumpStackTrace() { |
| 945 uintptr_t sp = Thread::GetCurrentStackPointer(); | 978 uintptr_t sp = Thread::GetCurrentStackPointer(); |
| 946 uintptr_t fp = 0; | 979 uintptr_t fp = 0; |
| 947 uintptr_t pc = GetProgramCounter(); | 980 uintptr_t pc = OS::GetProgramCounter(); |
| 948 | 981 |
| 949 COPY_FP_REGISTER(fp); | 982 COPY_FP_REGISTER(fp); |
| 950 | 983 |
| 951 DumpStackTrace(sp, fp, pc); | 984 DumpStackTrace(sp, fp, pc); |
| 952 } | 985 } |
| 953 | 986 |
| 954 | 987 |
| 955 void Profiler::DumpStackTrace(uword sp, uword fp, uword pc) { | 988 void Profiler::DumpStackTrace(uword sp, uword fp, uword pc) { |
| 956 // Allow only one stack trace to prevent recursively printing stack traces if | 989 // Allow only one stack trace to prevent recursively printing stack traces if |
| 957 // we hit an assert while printing the stack. | 990 // we hit an assert while printing the stack. |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 985 | 1018 |
| 986 if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower, | 1019 if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower, |
| 987 &stack_upper, | 1020 &stack_upper, |
| 988 /*get_os_thread_bounds=*/true)) { | 1021 /*get_os_thread_bounds=*/true)) { |
| 989 OS::PrintErr( | 1022 OS::PrintErr( |
| 990 "Stack dump aborted because GetAndValidateThreadStackBounds.\n"); | 1023 "Stack dump aborted because GetAndValidateThreadStackBounds.\n"); |
| 991 return; | 1024 return; |
| 992 } | 1025 } |
| 993 | 1026 |
| 994 ProfilerNativeStackWalker native_stack_walker( | 1027 ProfilerNativeStackWalker native_stack_walker( |
| 995 isolate, NULL, NULL, stack_lower, stack_upper, pc, fp, sp); | 1028 (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, NULL, NULL, |
| 1029 stack_lower, stack_upper, pc, fp, sp); | |
| 996 native_stack_walker.walk(); | 1030 native_stack_walker.walk(); |
| 997 OS::PrintErr("-- End of DumpStackTrace\n"); | 1031 OS::PrintErr("-- End of DumpStackTrace\n"); |
| 998 } | 1032 } |
| 999 | 1033 |
| 1000 | 1034 |
| 1001 void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { | 1035 void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { |
| 1002 ASSERT(thread != NULL); | 1036 ASSERT(thread != NULL); |
| 1003 OSThread* os_thread = thread->os_thread(); | 1037 OSThread* os_thread = thread->os_thread(); |
| 1004 ASSERT(os_thread != NULL); | 1038 ASSERT(os_thread != NULL); |
| 1005 Isolate* isolate = thread->isolate(); | 1039 Isolate* isolate = thread->isolate(); |
| 1006 if (!CheckIsolate(isolate)) { | 1040 if (!CheckIsolate(isolate)) { |
| 1007 return; | 1041 return; |
| 1008 } | 1042 } |
| 1009 | 1043 |
| 1010 const bool exited_dart_code = thread->HasExitedDartCode(); | 1044 const bool exited_dart_code = thread->HasExitedDartCode(); |
| 1011 | 1045 |
| 1012 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 1046 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
| 1013 if (sample_buffer == NULL) { | 1047 if (sample_buffer == NULL) { |
| 1014 // Profiler not initialized. | 1048 // Profiler not initialized. |
| 1015 return; | 1049 return; |
| 1016 } | 1050 } |
| 1017 | 1051 |
| 1018 uintptr_t sp = Thread::GetCurrentStackPointer(); | 1052 uintptr_t sp = Thread::GetCurrentStackPointer(); |
| 1019 uintptr_t fp = 0; | 1053 uintptr_t fp = 0; |
| 1020 uintptr_t pc = GetProgramCounter(); | 1054 uintptr_t pc = OS::GetProgramCounter(); |
| 1021 | 1055 |
| 1022 COPY_FP_REGISTER(fp); | 1056 COPY_FP_REGISTER(fp); |
| 1023 | 1057 |
| 1024 uword stack_lower = 0; | 1058 uword stack_lower = 0; |
| 1025 uword stack_upper = 0; | 1059 uword stack_upper = 0; |
| 1026 | 1060 |
| 1027 if (!InitialRegisterCheck(pc, fp, sp)) { | 1061 if (!InitialRegisterCheck(pc, fp, sp)) { |
| 1028 return; | 1062 return; |
| 1029 } | 1063 } |
| 1030 | 1064 |
| 1031 if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower, | 1065 if (!GetAndValidateThreadStackBounds(thread, fp, sp, &stack_lower, |
| 1032 &stack_upper)) { | 1066 &stack_upper)) { |
| 1033 // Could not get stack boundary. | 1067 // Could not get stack boundary. |
| 1034 return; | 1068 return; |
| 1035 } | 1069 } |
| 1036 | 1070 |
| 1037 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); | 1071 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); |
| 1038 sample->SetAllocationCid(cid); | 1072 sample->SetAllocationCid(cid); |
| 1039 | 1073 |
| 1040 if (FLAG_profile_vm) { | 1074 if (FLAG_profile_vm) { |
| 1041 ProfilerNativeStackWalker native_stack_walker( | 1075 ProfilerNativeStackWalker native_stack_walker( |
| 1042 isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp); | 1076 (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, sample, |
| 1077 sample_buffer, stack_lower, stack_upper, pc, fp, sp); | |
| 1043 native_stack_walker.walk(); | 1078 native_stack_walker.walk(); |
| 1044 } else if (exited_dart_code) { | 1079 } else if (exited_dart_code) { |
| 1045 ProfilerDartStackWalker dart_exit_stack_walker( | 1080 ProfilerDartStackWalker dart_exit_stack_walker( |
| 1046 thread, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, | 1081 thread, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, |
| 1047 exited_dart_code, true); | 1082 exited_dart_code, true); |
| 1048 dart_exit_stack_walker.walk(); | 1083 dart_exit_stack_walker.walk(); |
| 1049 } else { | 1084 } else { |
| 1050 // Fall back. | 1085 // Fall back. |
| 1051 uintptr_t pc = GetProgramCounter(); | 1086 uintptr_t pc = OS::GetProgramCounter(); |
| 1052 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); | 1087 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); |
| 1053 sample->SetAllocationCid(cid); | 1088 sample->SetAllocationCid(cid); |
| 1054 sample->SetAt(0, pc); | 1089 sample->SetAt(0, pc); |
| 1055 } | 1090 } |
| 1056 } | 1091 } |
| 1057 | 1092 |
| 1058 | 1093 |
| 1094 Sample* Profiler::SampleNativeAllocation(intptr_t skip_count) { | |
| 1095 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | |
| 1096 if (sample_buffer == NULL) { | |
| 1097 return NULL; | |
| 1098 } | |
| 1099 | |
| 1100 uintptr_t sp = Thread::GetCurrentStackPointer(); | |
| 1101 uintptr_t fp = 0; | |
| 1102 uintptr_t pc = OS::GetProgramCounter(); | |
| 1103 | |
| 1104 COPY_FP_REGISTER(fp); | |
| 1105 | |
| 1106 uword stack_lower = 0; | |
| 1107 uword stack_upper = 0; | |
| 1108 if (!InitialRegisterCheck(pc, fp, sp)) { | |
| 1109 return NULL; | |
|
Cutch
2017/02/22 23:15:55
You might want to add some code like:
AtomicOpera
bkonyi
2017/02/23 00:25:20
Done (I think).
| |
| 1110 } | |
| 1111 | |
| 1112 if (!(OSThread::GetCurrentStackBounds(&stack_lower, &stack_upper) && | |
| 1113 ValidateThreadStackBounds(fp, sp, stack_lower, stack_upper))) { | |
| 1114 // Could not get stack boundary. | |
| 1115 return NULL; | |
| 1116 } | |
| 1117 | |
| 1118 OSThread* os_thread = OSThread::Current(); | |
| 1119 Sample* sample = SetupSampleNative(sample_buffer, os_thread->trace_id()); | |
| 1120 ProfilerNativeStackWalker native_stack_walker( | |
| 1121 ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, | |
| 1122 skip_count); | |
| 1123 native_stack_walker.walk(); | |
| 1124 return sample; | |
| 1125 } | |
| 1126 | |
| 1127 | |
| 1059 void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) { | 1128 void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) { |
| 1060 ASSERT(thread != NULL); | 1129 ASSERT(thread != NULL); |
| 1061 OSThread* os_thread = thread->os_thread(); | 1130 OSThread* os_thread = thread->os_thread(); |
| 1062 ASSERT(os_thread != NULL); | 1131 ASSERT(os_thread != NULL); |
| 1063 Isolate* isolate = thread->isolate(); | 1132 Isolate* isolate = thread->isolate(); |
| 1064 | 1133 |
| 1065 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 1134 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
| 1066 if (sample_buffer == NULL) { | 1135 if (sample_buffer == NULL) { |
| 1067 // Profiler not initialized. | 1136 // Profiler not initialized. |
| 1068 return; | 1137 return; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1174 // Setup sample. | 1243 // Setup sample. |
| 1175 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); | 1244 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); |
| 1176 // Increment counter for vm tag. | 1245 // Increment counter for vm tag. |
| 1177 VMTagCounters* counters = isolate->vm_tag_counters(); | 1246 VMTagCounters* counters = isolate->vm_tag_counters(); |
| 1178 ASSERT(counters != NULL); | 1247 ASSERT(counters != NULL); |
| 1179 if (thread->IsMutatorThread()) { | 1248 if (thread->IsMutatorThread()) { |
| 1180 counters->Increment(sample->vm_tag()); | 1249 counters->Increment(sample->vm_tag()); |
| 1181 } | 1250 } |
| 1182 | 1251 |
| 1183 ProfilerNativeStackWalker native_stack_walker( | 1252 ProfilerNativeStackWalker native_stack_walker( |
| 1184 isolate, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp); | 1253 (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, sample, |
| 1254 sample_buffer, stack_lower, stack_upper, pc, fp, sp); | |
| 1185 const bool exited_dart_code = thread->HasExitedDartCode(); | 1255 const bool exited_dart_code = thread->HasExitedDartCode(); |
| 1186 ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer, | 1256 ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer, |
| 1187 stack_lower, stack_upper, pc, fp, | 1257 stack_lower, stack_upper, pc, fp, |
| 1188 sp, exited_dart_code, false); | 1258 sp, exited_dart_code, false); |
| 1189 | 1259 |
| 1190 // All memory access is done inside CollectSample. | 1260 // All memory access is done inside CollectSample. |
| 1191 CollectSample(isolate, exited_dart_code, in_dart_code, sample, | 1261 CollectSample(isolate, exited_dart_code, in_dart_code, sample, |
| 1192 &native_stack_walker, &dart_stack_walker, pc, fp, sp, | 1262 &native_stack_walker, &dart_stack_walker, pc, fp, sp, |
| 1193 &counters_); | 1263 &counters_); |
| 1194 } | 1264 } |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1334 for (intptr_t i = 0; i < length; i++) { | 1404 for (intptr_t i = 0; i < length; i++) { |
| 1335 Sample* sample = At(i); | 1405 Sample* sample = At(i); |
| 1336 if (sample->ignore_sample()) { | 1406 if (sample->ignore_sample()) { |
| 1337 // Bad sample. | 1407 // Bad sample. |
| 1338 continue; | 1408 continue; |
| 1339 } | 1409 } |
| 1340 if (!sample->head_sample()) { | 1410 if (!sample->head_sample()) { |
| 1341 // An inner sample in a chain of samples. | 1411 // An inner sample in a chain of samples. |
| 1342 continue; | 1412 continue; |
| 1343 } | 1413 } |
| 1344 if (sample->isolate() != filter->isolate()) { | 1414 // If we're requesting all the native allocation samples, we don't care |
| 1415 // whether or not we're in the same isolate as the sample. | |
| 1416 if ((sample->port() != filter->port()) && | |
| 1417 !(sample->port() == ILLEGAL_PORT)) { | |
|
Cutch
2017/02/22 23:15:55
What I meant here was to write the code as follows
bkonyi
2017/02/23 00:25:20
Done.
| |
| 1345 // Another isolate. | 1418 // Another isolate. |
| 1346 continue; | 1419 continue; |
| 1347 } | 1420 } |
| 1348 if (sample->timestamp() == 0) { | 1421 if (sample->timestamp() == 0) { |
| 1349 // Empty. | 1422 // Empty. |
| 1350 continue; | 1423 continue; |
| 1351 } | 1424 } |
| 1352 if (sample->At(0) == 0) { | 1425 if (sample->At(0) == 0) { |
| 1353 // No frames. | 1426 // No frames. |
| 1354 continue; | 1427 continue; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1413 return processed_sample; | 1486 return processed_sample; |
| 1414 } | 1487 } |
| 1415 | 1488 |
| 1416 | 1489 |
| 1417 Sample* SampleBuffer::Next(Sample* sample) { | 1490 Sample* SampleBuffer::Next(Sample* sample) { |
| 1418 if (!sample->is_continuation_sample()) return NULL; | 1491 if (!sample->is_continuation_sample()) return NULL; |
| 1419 Sample* next_sample = At(sample->continuation_index()); | 1492 Sample* next_sample = At(sample->continuation_index()); |
| 1420 // Sanity check. | 1493 // Sanity check. |
| 1421 ASSERT(sample != next_sample); | 1494 ASSERT(sample != next_sample); |
| 1422 // Detect invalid chaining. | 1495 // Detect invalid chaining. |
| 1423 if (sample->isolate() != next_sample->isolate()) { | 1496 if (sample->port() != next_sample->port()) { |
| 1424 return NULL; | 1497 return NULL; |
| 1425 } | 1498 } |
| 1426 if (sample->timestamp() != next_sample->timestamp()) { | 1499 if (sample->timestamp() != next_sample->timestamp()) { |
| 1427 return NULL; | 1500 return NULL; |
| 1428 } | 1501 } |
| 1429 if (sample->tid() != next_sample->tid()) { | 1502 if (sample->tid() != next_sample->tid()) { |
| 1430 return NULL; | 1503 return NULL; |
| 1431 } | 1504 } |
| 1432 return next_sample; | 1505 return next_sample; |
| 1433 } | 1506 } |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1515 | 1588 |
| 1516 | 1589 |
| 1517 ProcessedSampleBuffer::ProcessedSampleBuffer() | 1590 ProcessedSampleBuffer::ProcessedSampleBuffer() |
| 1518 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { | 1591 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { |
| 1519 ASSERT(code_lookup_table_ != NULL); | 1592 ASSERT(code_lookup_table_ != NULL); |
| 1520 } | 1593 } |
| 1521 | 1594 |
| 1522 #endif // !PRODUCT | 1595 #endif // !PRODUCT |
| 1523 | 1596 |
| 1524 } // namespace dart | 1597 } // namespace dart |
| OLD | NEW |