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 1666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1677 if ((sample->fp() & kPageMask) == 0) { | 1677 if ((sample->fp() & kPageMask) == 0) { |
1678 return; | 1678 return; |
1679 } | 1679 } |
1680 #endif | 1680 #endif |
1681 const uword pc_marker = *(fp + kPcMarkerSlotFromFp); | 1681 const uword pc_marker = *(fp + kPcMarkerSlotFromFp); |
1682 sample->set_pc_marker(pc_marker); | 1682 sample->set_pc_marker(pc_marker); |
1683 } | 1683 } |
1684 } | 1684 } |
1685 | 1685 |
1686 | 1686 |
1687 class ProfilerDartStackWalker : public ValueObject { | 1687 // Given an exit frame, walk the Dart stack. |
1688 class ProfilerDartExitStackWalker : public ValueObject { | |
1688 public: | 1689 public: |
1689 ProfilerDartStackWalker(Isolate* isolate, Sample* sample) | 1690 ProfilerDartExitStackWalker(Isolate* isolate, Sample* sample) |
1690 : sample_(sample), | 1691 : sample_(sample), |
1691 frame_iterator_(isolate) { | 1692 frame_iterator_(isolate) { |
1692 ASSERT(sample_ != NULL); | 1693 ASSERT(sample_ != NULL); |
1693 } | 1694 } |
1694 | 1695 |
1695 ProfilerDartStackWalker(Isolate* isolate, Sample* sample, uword fp) | 1696 void walk() { |
1696 : sample_(sample), | |
1697 frame_iterator_(fp, isolate) { | |
1698 ASSERT(sample_ != NULL); | |
1699 } | |
1700 | |
1701 int walk() { | |
1702 intptr_t frame_index = 0; | 1697 intptr_t frame_index = 0; |
1703 StackFrame* frame = frame_iterator_.NextFrame(); | 1698 StackFrame* frame = frame_iterator_.NextFrame(); |
1704 while (frame != NULL) { | 1699 while (frame != NULL) { |
1705 sample_->SetAt(frame_index, frame->pc()); | 1700 sample_->SetAt(frame_index, frame->pc()); |
1706 frame_index++; | 1701 frame_index++; |
1707 if (frame_index >= FLAG_profile_depth) { | 1702 if (frame_index >= FLAG_profile_depth) { |
1708 break; | 1703 break; |
1709 } | 1704 } |
1710 frame = frame_iterator_.NextFrame(); | 1705 frame = frame_iterator_.NextFrame(); |
1711 } | 1706 } |
1712 return frame_index; | |
1713 } | 1707 } |
1714 | 1708 |
1715 private: | 1709 private: |
1716 Sample* sample_; | 1710 Sample* sample_; |
1717 DartFrameIterator frame_iterator_; | 1711 DartFrameIterator frame_iterator_; |
1718 }; | 1712 }; |
1719 | 1713 |
1720 | 1714 |
1721 // Notes on stack frame walking: | 1715 // Executing Dart code, walk the stack. |
1722 // | 1716 class ProfilerDartStackWalker : public ValueObject { |
1723 // The sampling profiler will collect up to Sample::kNumStackFrames stack frames | 1717 public: |
1724 // The stack frame walking code uses the frame pointer to traverse the stack. | 1718 ProfilerDartStackWalker(Isolate* isolate, |
1719 Sample* sample, | |
1720 uword stack_lower, | |
1721 uword stack_upper, | |
1722 uword pc, | |
1723 uword fp, | |
1724 uword sp) | |
1725 : isolate_(isolate), | |
1726 sample_(sample), | |
1727 stack_upper_(stack_upper), | |
1728 stack_lower_(stack_lower) { | |
1729 ASSERT(sample_ != NULL); | |
1730 pc_ = reinterpret_cast<uword*>(pc); | |
1731 fp_ = reinterpret_cast<uword*>(fp); | |
1732 sp_ = reinterpret_cast<uword*>(sp); | |
1733 } | |
1734 | |
1735 void walk() { | |
1736 if (!ValidFramePointer()) { | |
1737 sample_->set_ignore_sample(true); | |
1738 return; | |
1739 } | |
1740 ASSERT(ValidFramePointer()); | |
1741 uword return_pc = InitialReturnAddress(); | |
1742 if (StubCode::InInvocationStubForIsolate(isolate_, return_pc)) { | |
1743 // Edge case- we have called out from the Invocation Stub but have not | |
1744 // created the stack frame of the callee. Attempt to locate the exit | |
1745 // frame before walking the stack. | |
1746 if (!NextExit() || !ValidFramePointer()) { | |
1747 // Nothing to sample. | |
1748 sample_->set_ignore_sample(true); | |
1749 return; | |
1750 } | |
1751 } | |
1752 for (int i = 0; i < FLAG_profile_depth; i++) { | |
1753 sample_->SetAt(i, reinterpret_cast<uword>(pc_)); | |
1754 if (!Next()) { | |
1755 return; | |
1756 } | |
1757 } | |
1758 } | |
1759 | |
1760 private: | |
1761 bool Next() { | |
1762 if (!ValidFramePointer()) { | |
1763 return false; | |
1764 } | |
1765 uword pc = reinterpret_cast<uword>(pc_); | |
1766 if (StubCode::InInvocationStubForIsolate(isolate_, pc)) { | |
1767 // In invocation stub. | |
1768 return NextExit(); | |
1769 } | |
1770 // In regular Dart frame. | |
1771 pc_ = CallerPC(); | |
1772 // Check if we've moved into the invocation stub. | |
1773 pc = reinterpret_cast<uword>(pc_); | |
1774 if (StubCode::InInvocationStubForIsolate(isolate_, pc)) { | |
1775 // New PC is inside invocation stub, skip. | |
1776 return NextExit(); | |
1777 } | |
1778 uword* old_fp = fp_; | |
1779 fp_ = CallerFP(); | |
1780 if (fp_ <= old_fp) { | |
1781 // FP didn't move to a higher address. | |
1782 return false; | |
1783 } | |
siva
2014/07/22 20:31:12
set pc_ only after determining that you are about
Cutch
2014/07/22 20:50:12
Done.
| |
1784 return true; | |
1785 } | |
1786 | |
1787 bool NextExit() { | |
1788 if (!ValidFramePointer()) { | |
1789 return false; | |
1790 } | |
1791 uword* old_fp = fp_; | |
1792 fp_ = ExitLink(); | |
1793 if (fp_ == NULL) { | |
1794 // No exit link. | |
1795 return false; | |
1796 } | |
1797 if (!ValidFramePointer()) { | |
1798 return false; | |
1799 } | |
1800 if (fp_ <= old_fp) { | |
1801 // FP didn't move to a higher address. | |
1802 return false; | |
1803 } | |
siva
2014/07/22 20:31:12
In all the case where you return false, I feel you
Cutch
2014/07/22 20:50:12
Done.
| |
1804 pc_ = CallerPC(); | |
1805 return true; | |
1806 } | |
1807 | |
1808 uword InitialReturnAddress() const { | |
1809 ASSERT(sp_ != NULL); | |
siva
2014/07/22 20:31:12
Probably need to assert
ASSERT(FindCodeForPC(*sp
Cutch
2014/07/22 20:50:12
It's not guaranteed that we are reading a PC from
| |
1810 return *(sp_); | |
1811 } | |
1812 | |
1813 uword* CallerPC() const { | |
1814 ASSERT(fp_ != NULL); | |
1815 return reinterpret_cast<uword*>(*(fp_ + kSavedCallerPcSlotFromFp)); | |
1816 } | |
1817 | |
1818 uword* CallerFP() const { | |
1819 ASSERT(fp_ != NULL); | |
1820 return reinterpret_cast<uword*>(*(fp_ + kSavedCallerFpSlotFromFp)); | |
1821 } | |
1822 | |
1823 uword* ExitLink() const { | |
1824 ASSERT(fp_ != NULL); | |
1825 return reinterpret_cast<uword*>(*(fp_ + kExitLinkSlotFromEntryFp)); | |
1826 } | |
1827 | |
1828 bool ValidFramePointer() const { | |
1829 if (fp_ == NULL) { | |
1830 return false; | |
1831 } | |
1832 uword cursor = reinterpret_cast<uword>(fp_); | |
1833 cursor += sizeof(fp_); | |
1834 return (cursor >= stack_lower_) && (cursor < stack_upper_); | |
1835 } | |
1836 | |
1837 uword* pc_; | |
1838 uword* fp_; | |
1839 uword* sp_; | |
1840 Isolate* isolate_; | |
1841 Sample* sample_; | |
1842 const uword stack_upper_; | |
1843 uword stack_lower_; | |
1844 }; | |
1845 | |
1846 | |
1725 // If the VM is compiled without frame pointers (which is the default on | 1847 // If the VM is compiled without frame pointers (which is the default on |
1726 // recent GCC versions with optimizing enabled) the stack walking code may | 1848 // recent GCC versions with optimizing enabled) the stack walking code may |
1727 // fail (sometimes leading to a crash). | 1849 // fail. |
1728 // | 1850 // |
1729 class ProfilerNativeStackWalker : public ValueObject { | 1851 class ProfilerNativeStackWalker : public ValueObject { |
1730 public: | 1852 public: |
1731 ProfilerNativeStackWalker(Sample* sample, | 1853 ProfilerNativeStackWalker(Sample* sample, |
1732 uword stack_lower, | 1854 uword stack_lower, |
1733 uword stack_upper, | 1855 uword stack_upper, |
1734 uword pc, | 1856 uword pc, |
1735 uword fp, | 1857 uword fp, |
1736 uword sp) | 1858 uword sp) |
1737 : sample_(sample), | 1859 : sample_(sample), |
1738 stack_upper_(stack_upper), | 1860 stack_upper_(stack_upper), |
1739 original_pc_(pc), | 1861 original_pc_(pc), |
1740 original_fp_(fp), | 1862 original_fp_(fp), |
1741 original_sp_(sp), | 1863 original_sp_(sp), |
1742 lower_bound_(stack_lower) { | 1864 lower_bound_(stack_lower) { |
1743 ASSERT(sample_ != NULL); | 1865 ASSERT(sample_ != NULL); |
1744 } | 1866 } |
1745 | 1867 |
1746 void walk(Heap* heap) { | 1868 void walk() { |
1747 const uword kMaxStep = VirtualMemory::PageSize(); | 1869 const uword kMaxStep = VirtualMemory::PageSize(); |
1748 | 1870 |
1749 sample_->SetAt(0, original_pc_); | 1871 sample_->SetAt(0, original_pc_); |
1750 | 1872 |
1751 uword* pc = reinterpret_cast<uword*>(original_pc_); | 1873 uword* pc = reinterpret_cast<uword*>(original_pc_); |
1752 uword* fp = reinterpret_cast<uword*>(original_fp_); | 1874 uword* fp = reinterpret_cast<uword*>(original_fp_); |
1753 uword* previous_fp = fp; | 1875 uword* previous_fp = fp; |
1754 | 1876 |
1755 uword gap = original_fp_ - original_sp_; | 1877 uword gap = original_fp_ - original_sp_; |
1756 if (gap >= kMaxStep) { | 1878 if (gap >= kMaxStep) { |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1907 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); | 2029 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
1908 sample->set_vm_tag(isolate->vm_tag()); | 2030 sample->set_vm_tag(isolate->vm_tag()); |
1909 sample->set_user_tag(isolate->user_tag()); | 2031 sample->set_user_tag(isolate->user_tag()); |
1910 sample->set_sp(state.sp); | 2032 sample->set_sp(state.sp); |
1911 sample->set_fp(state.fp); | 2033 sample->set_fp(state.fp); |
1912 SetPCMarkerIfSafe(sample); | 2034 SetPCMarkerIfSafe(sample); |
1913 | 2035 |
1914 // Walk the call stack. | 2036 // Walk the call stack. |
1915 if (FLAG_profile_vm) { | 2037 if (FLAG_profile_vm) { |
1916 // Always walk the native stack collecting both native and Dart frames. | 2038 // Always walk the native stack collecting both native and Dart frames. |
1917 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | 2039 ProfilerNativeStackWalker stackWalker(sample, |
1918 state.pc, state.fp, state.sp); | 2040 stack_lower, |
1919 stackWalker.walk(isolate->heap()); | 2041 stack_upper, |
2042 state.pc, | |
2043 state.fp, | |
2044 state.sp); | |
2045 stackWalker.walk(); | |
1920 } else { | 2046 } else { |
1921 // Attempt to walk only the Dart call stack, falling back to walking | 2047 // Attempt to walk only the Dart call stack, falling back to walking |
1922 // the native stack. | 2048 // the native stack. |
1923 if ((isolate->stub_code() != NULL) && | 2049 if ((isolate->stub_code() != NULL) && |
1924 (isolate->top_exit_frame_info() != 0) && | 2050 (isolate->top_exit_frame_info() != 0) && |
1925 (isolate->vm_tag() != VMTag::kScriptTagId)) { | 2051 (isolate->vm_tag() != VMTag::kScriptTagId)) { |
1926 // We have a valid exit frame info, use the Dart stack walker. | 2052 // We have a valid exit frame info, use the Dart stack walker. |
1927 ProfilerDartStackWalker stackWalker(isolate, sample); | 2053 ProfilerDartExitStackWalker stackWalker(isolate, sample); |
2054 stackWalker.walk(); | |
2055 } else if ((isolate->stub_code() != NULL) && | |
2056 (isolate->top_exit_frame_info() == 0) && | |
2057 (isolate->vm_tag() == VMTag::kScriptTagId)) { | |
2058 // We are executing Dart code. We have frame pointers. | |
2059 ProfilerDartStackWalker stackWalker(isolate, | |
2060 sample, | |
2061 stack_lower, | |
2062 stack_upper, | |
2063 state.pc, | |
2064 state.fp, | |
2065 state.sp); | |
1928 stackWalker.walk(); | 2066 stackWalker.walk(); |
1929 } else { | 2067 } else { |
1930 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | 2068 // Fall back to an extremely conservative stack walker. |
1931 state.pc, state.fp, state.sp); | 2069 ProfilerNativeStackWalker stackWalker(sample, |
1932 stackWalker.walk(isolate->heap()); | 2070 stack_lower, |
2071 stack_upper, | |
2072 state.pc, | |
2073 state.fp, | |
2074 state.sp); | |
2075 stackWalker.walk(); | |
1933 } | 2076 } |
1934 } | 2077 } |
1935 } | 2078 } |
1936 | 2079 |
1937 } // namespace dart | 2080 } // namespace dart |
OLD | NEW |