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