| 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 if (StubCode::InInvocationStubForIsolate(isolate_, |
| 1766 reinterpret_cast<uword>(pc_))) { |
| 1767 // In invocation stub. |
| 1768 return NextExit(); |
| 1769 } |
| 1770 // In regular Dart frame. |
| 1771 uword* new_pc = CallerPC(); |
| 1772 // Check if we've moved into the invocation stub. |
| 1773 if (StubCode::InInvocationStubForIsolate(isolate_, |
| 1774 reinterpret_cast<uword>(new_pc))) { |
| 1775 // New PC is inside invocation stub, skip. |
| 1776 return NextExit(); |
| 1777 } |
| 1778 uword* new_fp = CallerFP(); |
| 1779 if (new_fp <= fp_) { |
| 1780 // FP didn't move to a higher address. |
| 1781 return false; |
| 1782 } |
| 1783 // Success, update fp and pc. |
| 1784 fp_ = new_fp; |
| 1785 pc_ = new_pc; |
| 1786 return true; |
| 1787 } |
| 1788 |
| 1789 bool NextExit() { |
| 1790 if (!ValidFramePointer()) { |
| 1791 return false; |
| 1792 } |
| 1793 uword* new_fp = ExitLink(); |
| 1794 if (new_fp == NULL) { |
| 1795 // No exit link. |
| 1796 return false; |
| 1797 } |
| 1798 if (new_fp <= fp_) { |
| 1799 // FP didn't move to a higher address. |
| 1800 return false; |
| 1801 } |
| 1802 if (!ValidFramePointer(new_fp)) { |
| 1803 return false; |
| 1804 } |
| 1805 // Success, update fp and pc. |
| 1806 fp_ = new_fp; |
| 1807 pc_ = CallerPC(); |
| 1808 return true; |
| 1809 } |
| 1810 |
| 1811 uword InitialReturnAddress() const { |
| 1812 ASSERT(sp_ != NULL); |
| 1813 return *(sp_); |
| 1814 } |
| 1815 |
| 1816 uword* CallerPC() const { |
| 1817 ASSERT(fp_ != NULL); |
| 1818 return reinterpret_cast<uword*>(*(fp_ + kSavedCallerPcSlotFromFp)); |
| 1819 } |
| 1820 |
| 1821 uword* CallerFP() const { |
| 1822 ASSERT(fp_ != NULL); |
| 1823 return reinterpret_cast<uword*>(*(fp_ + kSavedCallerFpSlotFromFp)); |
| 1824 } |
| 1825 |
| 1826 uword* ExitLink() const { |
| 1827 ASSERT(fp_ != NULL); |
| 1828 return reinterpret_cast<uword*>(*(fp_ + kExitLinkSlotFromEntryFp)); |
| 1829 } |
| 1830 |
| 1831 bool ValidFramePointer() const { |
| 1832 return ValidFramePointer(fp_); |
| 1833 } |
| 1834 |
| 1835 bool ValidFramePointer(uword* fp) const { |
| 1836 if (fp == NULL) { |
| 1837 return false; |
| 1838 } |
| 1839 uword cursor = reinterpret_cast<uword>(fp); |
| 1840 cursor += sizeof(fp); |
| 1841 return (cursor >= stack_lower_) && (cursor < stack_upper_); |
| 1842 } |
| 1843 |
| 1844 uword* pc_; |
| 1845 uword* fp_; |
| 1846 uword* sp_; |
| 1847 Isolate* isolate_; |
| 1848 Sample* sample_; |
| 1849 const uword stack_upper_; |
| 1850 uword stack_lower_; |
| 1851 }; |
| 1852 |
| 1853 |
| 1725 // If the VM is compiled without frame pointers (which is the default on | 1854 // 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 | 1855 // recent GCC versions with optimizing enabled) the stack walking code may |
| 1727 // fail (sometimes leading to a crash). | 1856 // fail. |
| 1728 // | 1857 // |
| 1729 class ProfilerNativeStackWalker : public ValueObject { | 1858 class ProfilerNativeStackWalker : public ValueObject { |
| 1730 public: | 1859 public: |
| 1731 ProfilerNativeStackWalker(Sample* sample, | 1860 ProfilerNativeStackWalker(Sample* sample, |
| 1732 uword stack_lower, | 1861 uword stack_lower, |
| 1733 uword stack_upper, | 1862 uword stack_upper, |
| 1734 uword pc, | 1863 uword pc, |
| 1735 uword fp, | 1864 uword fp, |
| 1736 uword sp) | 1865 uword sp) |
| 1737 : sample_(sample), | 1866 : sample_(sample), |
| 1738 stack_upper_(stack_upper), | 1867 stack_upper_(stack_upper), |
| 1739 original_pc_(pc), | 1868 original_pc_(pc), |
| 1740 original_fp_(fp), | 1869 original_fp_(fp), |
| 1741 original_sp_(sp), | 1870 original_sp_(sp), |
| 1742 lower_bound_(stack_lower) { | 1871 lower_bound_(stack_lower) { |
| 1743 ASSERT(sample_ != NULL); | 1872 ASSERT(sample_ != NULL); |
| 1744 } | 1873 } |
| 1745 | 1874 |
| 1746 void walk(Heap* heap) { | 1875 void walk() { |
| 1747 const uword kMaxStep = VirtualMemory::PageSize(); | 1876 const uword kMaxStep = VirtualMemory::PageSize(); |
| 1748 | 1877 |
| 1749 sample_->SetAt(0, original_pc_); | 1878 sample_->SetAt(0, original_pc_); |
| 1750 | 1879 |
| 1751 uword* pc = reinterpret_cast<uword*>(original_pc_); | 1880 uword* pc = reinterpret_cast<uword*>(original_pc_); |
| 1752 uword* fp = reinterpret_cast<uword*>(original_fp_); | 1881 uword* fp = reinterpret_cast<uword*>(original_fp_); |
| 1753 uword* previous_fp = fp; | 1882 uword* previous_fp = fp; |
| 1754 | 1883 |
| 1755 uword gap = original_fp_ - original_sp_; | 1884 uword gap = original_fp_ - original_sp_; |
| 1756 if (gap >= kMaxStep) { | 1885 if (gap >= kMaxStep) { |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1907 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); | 2036 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
| 1908 sample->set_vm_tag(isolate->vm_tag()); | 2037 sample->set_vm_tag(isolate->vm_tag()); |
| 1909 sample->set_user_tag(isolate->user_tag()); | 2038 sample->set_user_tag(isolate->user_tag()); |
| 1910 sample->set_sp(state.sp); | 2039 sample->set_sp(state.sp); |
| 1911 sample->set_fp(state.fp); | 2040 sample->set_fp(state.fp); |
| 1912 SetPCMarkerIfSafe(sample); | 2041 SetPCMarkerIfSafe(sample); |
| 1913 | 2042 |
| 1914 // Walk the call stack. | 2043 // Walk the call stack. |
| 1915 if (FLAG_profile_vm) { | 2044 if (FLAG_profile_vm) { |
| 1916 // Always walk the native stack collecting both native and Dart frames. | 2045 // Always walk the native stack collecting both native and Dart frames. |
| 1917 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | 2046 ProfilerNativeStackWalker stackWalker(sample, |
| 1918 state.pc, state.fp, state.sp); | 2047 stack_lower, |
| 1919 stackWalker.walk(isolate->heap()); | 2048 stack_upper, |
| 2049 state.pc, |
| 2050 state.fp, |
| 2051 state.sp); |
| 2052 stackWalker.walk(); |
| 1920 } else { | 2053 } else { |
| 1921 // Attempt to walk only the Dart call stack, falling back to walking | 2054 // Attempt to walk only the Dart call stack, falling back to walking |
| 1922 // the native stack. | 2055 // the native stack. |
| 1923 if ((isolate->stub_code() != NULL) && | 2056 if ((isolate->stub_code() != NULL) && |
| 1924 (isolate->top_exit_frame_info() != 0) && | 2057 (isolate->top_exit_frame_info() != 0) && |
| 1925 (isolate->vm_tag() != VMTag::kScriptTagId)) { | 2058 (isolate->vm_tag() != VMTag::kScriptTagId)) { |
| 1926 // We have a valid exit frame info, use the Dart stack walker. | 2059 // We have a valid exit frame info, use the Dart stack walker. |
| 1927 ProfilerDartStackWalker stackWalker(isolate, sample); | 2060 ProfilerDartExitStackWalker stackWalker(isolate, sample); |
| 2061 stackWalker.walk(); |
| 2062 } else if ((isolate->stub_code() != NULL) && |
| 2063 (isolate->top_exit_frame_info() == 0) && |
| 2064 (isolate->vm_tag() == VMTag::kScriptTagId)) { |
| 2065 // We are executing Dart code. We have frame pointers. |
| 2066 ProfilerDartStackWalker stackWalker(isolate, |
| 2067 sample, |
| 2068 stack_lower, |
| 2069 stack_upper, |
| 2070 state.pc, |
| 2071 state.fp, |
| 2072 state.sp); |
| 1928 stackWalker.walk(); | 2073 stackWalker.walk(); |
| 1929 } else { | 2074 } else { |
| 1930 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | 2075 // Fall back to an extremely conservative stack walker. |
| 1931 state.pc, state.fp, state.sp); | 2076 ProfilerNativeStackWalker stackWalker(sample, |
| 1932 stackWalker.walk(isolate->heap()); | 2077 stack_lower, |
| 2078 stack_upper, |
| 2079 state.pc, |
| 2080 state.fp, |
| 2081 state.sp); |
| 2082 stackWalker.walk(); |
| 1933 } | 2083 } |
| 1934 } | 2084 } |
| 1935 } | 2085 } |
| 1936 | 2086 |
| 1937 } // namespace dart | 2087 } // namespace dart |
| OLD | NEW |