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/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 { | |
|
srdjan
2014/05/02 18:20:29
Make SampleVisitor a ValueObject if possible so th
Cutch
2014/05/02 18:37:03
Done.
| |
| 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) { | |
| 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 FixMissingDartFrame(sample); | |
| 937 } | |
| 938 } | |
| 939 | |
| 940 private: | |
| 941 void FixMissingDartFrame(Sample* sample) { | |
|
srdjan
2014/05/02 18:20:29
s/FixMissingDartFrame/CheckForMissingDartFrame/
Cutch
2014/05/02 18:37:03
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)) { | |
| 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) { | |
| 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) { | |
| 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_; | |
|
srdjan
2014/05/02 18:20:29
Code*. We try to use reference with const.
| |
| 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->VisitSamplesByReference(&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 |