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

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

Issue 264933006: Fix edge case where profiler would miss the caller of the top frame (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 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
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/reusable_handles.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/reusable_handles.h"
16 #include "vm/signal_handler.h" 17 #include "vm/signal_handler.h"
17 #include "vm/simulator.h" 18 #include "vm/simulator.h"
18 #include "vm/stack_frame.h" 19 #include "vm/stack_frame.h"
19 20
20 namespace dart { 21 namespace dart {
21 22
22 23
23 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \ 24 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
24 defined(TARGET_OS_ANDROID) 25 defined(TARGET_OS_ANDROID)
25 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler"); 26 DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
(...skipping 877 matching lines...) Expand 10 before | Expand all | Expand 10 after
903 !b->contains(a->end() - 1)); 904 !b->contains(a->end() - 1));
904 } 905 }
905 } 906 }
906 } 907 }
907 #endif 908 #endif
908 909
909 ZoneGrowableArray<CodeRegion*>* code_region_table_; 910 ZoneGrowableArray<CodeRegion*>* code_region_table_;
910 }; 911 };
911 912
912 913
914 class FixTopFrameVisitor : public SampleVisitor {
915 public:
916 explicit FixTopFrameVisitor(Isolate* isolate)
917 : SampleVisitor(isolate),
918 vm_isolate_(Dart::vm_isolate()) {
919 }
920
921 void VisitSample(Sample* sample) {
922 if (sample->processed()) {
923 // Already processed.
924 return;
925 }
926 REUSABLE_CODE_HANDLESCOPE(isolate());
927 // Mark that we've processed this sample.
928 sample->set_processed(true);
929 // Lookup code object for leaf frame.
930 Code& code = reused_code_handle.Handle();
931 code = FindCodeForPC(sample->At(0));
932 sample->set_leaf_frame_is_dart(!code.IsNull());
933 if (sample->pc_marker() == 0) {
934 // No pc marker. Nothing to do.
935 return;
936 }
937 if (!code.IsNull() && (code.compile_timestamp() > sample->timestamp())) {
938 // Code compiled after sample. Ignore.
939 return;
940 }
941 if (sample->leaf_frame_is_dart()) {
942 CheckForMissingDartFrame(code, sample);
943 }
944 }
945
946 private:
947 void CheckForMissingDartFrame(const Code& code, Sample* sample) const {
948 // Some stubs (and intrinsics) do not push a frame onto the stack leaving
949 // the frame pointer in the caller.
950 //
951 // PC -> STUB
952 // FP -> DART3 <-+
953 // DART2 <-| <- TOP FRAME RETURN ADDRESS.
954 // DART1 <-|
955 // .....
956 //
957 // In this case, traversing the linked stack frames will not collect a PC
958 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1.
959 // In Dart code, after pushing the FP onto the stack, an IP in the current
960 // function is pushed onto the stack as well. This stack slot is called
961 // the PC marker. We can use the PC marker to insert DART3 into the stack
962 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the
963 // inserted PC may not accurately reflect the true return address from STUB.
964 ASSERT(!code.IsNull());
965 if (sample->sp() == sample->fp()) {
966 // Haven't pushed pc marker yet.
967 return;
968 }
969 uword pc_marker = sample->pc_marker();
970 if (code.ContainsInstructionAt(pc_marker)) {
971 // PC marker is in the same code as pc, no missing frame.
972 return;
973 }
974 if (!ContainedInDartCodeHeaps(pc_marker)) {
975 // Not a valid PC marker.
976 return;
977 }
978 sample->InsertCallerForTopFrame(pc_marker);
979 }
980
981 bool ContainedInDartCodeHeaps(uword pc) const {
982 return isolate()->heap()->CodeContains(pc) ||
983 vm_isolate()->heap()->CodeContains(pc);
984 }
985
986 Isolate* vm_isolate() const {
987 return vm_isolate_;
988 }
989
990 RawCode* FindCodeForPC(uword pc) const {
991 // Check current isolate for pc.
992 if (isolate()->heap()->CodeContains(pc)) {
993 return Code::LookupCode(pc);
994 }
995 // Check VM isolate for pc.
996 if (vm_isolate()->heap()->CodeContains(pc)) {
997 return Code::LookupCodeInVmIsolate(pc);
998 }
999 return Code::null();
1000 }
1001
1002 Isolate* vm_isolate_;
1003 };
1004
1005
913 class CodeRegionTableBuilder : public SampleVisitor { 1006 class CodeRegionTableBuilder : public SampleVisitor {
914 public: 1007 public:
915 CodeRegionTableBuilder(Isolate* isolate, 1008 CodeRegionTableBuilder(Isolate* isolate,
916 CodeRegionTable* live_code_table, 1009 CodeRegionTable* live_code_table,
917 CodeRegionTable* dead_code_table, 1010 CodeRegionTable* dead_code_table,
918 CodeRegionTable* tag_code_table) 1011 CodeRegionTable* tag_code_table)
919 : SampleVisitor(isolate), 1012 : SampleVisitor(isolate),
920 live_code_table_(live_code_table), 1013 live_code_table_(live_code_table),
921 dead_code_table_(dead_code_table), 1014 dead_code_table_(dead_code_table),
922 tag_code_table_(tag_code_table), 1015 tag_code_table_(tag_code_table),
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after
1349 CodeRegionTable live_code_table; 1442 CodeRegionTable live_code_table;
1350 // Dead code holds Overwritten CodeRegions. 1443 // Dead code holds Overwritten CodeRegions.
1351 CodeRegionTable dead_code_table; 1444 CodeRegionTable dead_code_table;
1352 // Tag code holds Tag CodeRegions. 1445 // Tag code holds Tag CodeRegions.
1353 CodeRegionTable tag_code_table; 1446 CodeRegionTable tag_code_table;
1354 CodeRegionTableBuilder builder(isolate, 1447 CodeRegionTableBuilder builder(isolate,
1355 &live_code_table, 1448 &live_code_table,
1356 &dead_code_table, 1449 &dead_code_table,
1357 &tag_code_table); 1450 &tag_code_table);
1358 { 1451 {
1452 // Preprocess samples and fix the caller when the top PC is in a
1453 // stub or intrinsic without a frame.
1454 FixTopFrameVisitor fixTopFrame(isolate);
1455 sample_buffer->VisitSamples(&fixTopFrame);
1456 }
1457 {
1359 // Build CodeRegion tables. 1458 // Build CodeRegion tables.
1360 ScopeStopwatch sw("CodeRegionTableBuilder"); 1459 ScopeStopwatch sw("CodeRegionTableBuilder");
1361 sample_buffer->VisitSamples(&builder); 1460 sample_buffer->VisitSamples(&builder);
1362 } 1461 }
1363 intptr_t samples = builder.visited(); 1462 intptr_t samples = builder.visited();
1364 intptr_t frames = builder.frames(); 1463 intptr_t frames = builder.frames();
1365 if (FLAG_trace_profiled_isolates) { 1464 if (FLAG_trace_profiled_isolates) {
1366 intptr_t total_live_code_objects = live_code_table.Length(); 1465 intptr_t total_live_code_objects = live_code_table.Length();
1367 intptr_t total_dead_code_objects = dead_code_table.Length(); 1466 intptr_t total_dead_code_objects = dead_code_table.Length();
1368 intptr_t total_tag_code_objects = tag_code_table.Length(); 1467 intptr_t total_tag_code_objects = tag_code_table.Length();
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after
1593 if (gap >= kMaxStep) { 1692 if (gap >= kMaxStep) {
1594 // Gap between frame pointer and stack pointer is 1693 // Gap between frame pointer and stack pointer is
1595 // too large. 1694 // too large.
1596 return 1; 1695 return 1;
1597 } 1696 }
1598 if (original_sp_ < lower_bound_) { 1697 if (original_sp_ < lower_bound_) {
1599 // The stack pointer gives us a better lower bound than 1698 // The stack pointer gives us a better lower bound than
1600 // the isolates stack limit. 1699 // the isolates stack limit.
1601 lower_bound_ = original_sp_; 1700 lower_bound_ = original_sp_;
1602 } 1701 }
1702 // Store the PC marker for the top frame.
1703 sample_->set_pc_marker(GetCurrentFramePcMarker(fp));
1603 int i = 0; 1704 int i = 0;
1604 for (; i < FLAG_profile_depth; i++) { 1705 for (; i < FLAG_profile_depth; i++) {
1605 if (FLAG_profile_verify_stack_walk) { 1706 if (FLAG_profile_verify_stack_walk) {
1606 VerifyCodeAddress(heap, i, reinterpret_cast<uword>(pc)); 1707 VerifyCodeAddress(heap, i, reinterpret_cast<uword>(pc));
1607 } 1708 }
1608 sample_->SetAt(i, reinterpret_cast<uword>(pc)); 1709 sample_->SetAt(i, reinterpret_cast<uword>(pc));
1609 if (fp == NULL) { 1710 if (fp == NULL) {
1610 return i + 1; 1711 return i + 1;
1611 } 1712 }
1612 if (!ValidFramePointer(fp)) { 1713 if (!ValidFramePointer(fp)) {
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1655 uword* CallerPC(uword* fp) const { 1756 uword* CallerPC(uword* fp) const {
1656 ASSERT(fp != NULL); 1757 ASSERT(fp != NULL);
1657 return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp)); 1758 return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp));
1658 } 1759 }
1659 1760
1660 uword* CallerFP(uword* fp) const { 1761 uword* CallerFP(uword* fp) const {
1661 ASSERT(fp != NULL); 1762 ASSERT(fp != NULL);
1662 return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp)); 1763 return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp));
1663 } 1764 }
1664 1765
1766 uword GetCurrentFramePcMarker(uword* fp) const {
1767 if (!ValidFramePointer(fp)) {
1768 return 0;
1769 }
1770 return *(fp + kPcMarkerSlotFromFp);
1771 }
1772
1665 bool ValidFramePointer(uword* fp) const { 1773 bool ValidFramePointer(uword* fp) const {
1666 if (fp == NULL) { 1774 if (fp == NULL) {
1667 return false; 1775 return false;
1668 } 1776 }
1669 uword cursor = reinterpret_cast<uword>(fp); 1777 uword cursor = reinterpret_cast<uword>(fp);
1670 cursor += sizeof(fp); 1778 cursor += sizeof(fp);
1671 bool r = cursor >= lower_bound_ && cursor < stack_upper_; 1779 bool r = cursor >= lower_bound_ && cursor < stack_upper_;
1672 return r; 1780 return r;
1673 } 1781 }
1674 1782
1675
1676 Sample* sample_; 1783 Sample* sample_;
1677 const uword stack_upper_; 1784 const uword stack_upper_;
1678 const uword original_pc_; 1785 const uword original_pc_;
1679 const uword original_fp_; 1786 const uword original_fp_;
1680 const uword original_sp_; 1787 const uword original_sp_;
1681 uword lower_bound_; 1788 uword lower_bound_;
1682 }; 1789 };
1683 1790
1684 1791
1685 void Profiler::RecordSampleInterruptCallback( 1792 void Profiler::RecordSampleInterruptCallback(
(...skipping 12 matching lines...) Expand all
1698 return; 1805 return;
1699 } 1806 }
1700 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); 1807 SampleBuffer* sample_buffer = profiler_data->sample_buffer();
1701 if (sample_buffer == NULL) { 1808 if (sample_buffer == NULL) {
1702 return; 1809 return;
1703 } 1810 }
1704 Sample* sample = sample_buffer->ReserveSample(); 1811 Sample* sample = sample_buffer->ReserveSample();
1705 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); 1812 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid);
1706 sample->set_vm_tag(isolate->vm_tag()); 1813 sample->set_vm_tag(isolate->vm_tag());
1707 sample->set_user_tag(isolate->user_tag()); 1814 sample->set_user_tag(isolate->user_tag());
1815 sample->set_sp(state.sp);
1816 sample->set_fp(state.fp);
1708 if (FLAG_profile_native_stack) { 1817 if (FLAG_profile_native_stack) {
1709 // Collect native and Dart frames. 1818 // Collect native and Dart frames.
1710 uword stack_lower = 0; 1819 uword stack_lower = 0;
1711 uword stack_upper = 0; 1820 uword stack_upper = 0;
1712 isolate->GetStackBounds(&stack_lower, &stack_upper); 1821 isolate->GetStackBounds(&stack_lower, &stack_upper);
1713 if ((stack_lower == 0) || (stack_upper == 0)) { 1822 if ((stack_lower == 0) || (stack_upper == 0)) {
1714 stack_lower = 0; 1823 stack_lower = 0;
1715 stack_upper = 0; 1824 stack_upper = 0;
1716 } 1825 }
1717 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, 1826 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper,
1718 state.pc, state.fp, state.sp); 1827 state.pc, state.fp, state.sp);
1719 stackWalker.walk(isolate->heap()); 1828 stackWalker.walk(isolate->heap());
1720 } else { 1829 } else {
1721 if ((isolate->top_exit_frame_info() != 0) && 1830 if ((isolate->top_exit_frame_info() != 0) &&
1722 (isolate->stub_code() != NULL)) { 1831 (isolate->stub_code() != NULL)) {
1723 ProfilerDartStackWalker stackWalker(sample); 1832 ProfilerDartStackWalker stackWalker(sample);
1724 stackWalker.walk(); 1833 stackWalker.walk();
1725 } else { 1834 } else {
1726 // TODO(johnmccutchan): Support collecting only Dart frames with 1835 // TODO(johnmccutchan): Support collecting only Dart frames with
1727 // ProfilerNativeStackWalker. 1836 // ProfilerNativeStackWalker.
1728 } 1837 }
1729 } 1838 }
1730 } 1839 }
1731 1840
1732 } // namespace dart 1841 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/profiler.h ('k') | runtime/vm/reusable_handles.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698