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/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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |