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 16 matching lines...) Expand all Loading... |
27 #else | 27 #else |
28 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); | 28 DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler"); |
29 #endif | 29 #endif |
30 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); | 30 DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates."); |
31 DEFINE_FLAG(charp, profile_dir, NULL, | 31 DEFINE_FLAG(charp, profile_dir, NULL, |
32 "Enable writing profile data into specified directory."); | 32 "Enable writing profile data into specified directory."); |
33 DEFINE_FLAG(int, profile_period, 1000, | 33 DEFINE_FLAG(int, profile_period, 1000, |
34 "Time between profiler samples in microseconds. Minimum 50."); | 34 "Time between profiler samples in microseconds. Minimum 50."); |
35 DEFINE_FLAG(int, profile_depth, 8, | 35 DEFINE_FLAG(int, profile_depth, 8, |
36 "Maximum number stack frames walked. Minimum 1. Maximum 255."); | 36 "Maximum number stack frames walked. Minimum 1. Maximum 255."); |
37 DEFINE_FLAG(bool, profile_verify_stack_walk, false, | |
38 "Verify instruction addresses while walking the stack."); | |
39 DEFINE_FLAG(bool, profile_vm, false, | 37 DEFINE_FLAG(bool, profile_vm, false, |
40 "Always collect native stack traces."); | 38 "Always collect native stack traces."); |
41 | 39 |
42 bool Profiler::initialized_ = false; | 40 bool Profiler::initialized_ = false; |
43 SampleBuffer* Profiler::sample_buffer_ = NULL; | 41 SampleBuffer* Profiler::sample_buffer_ = NULL; |
44 | 42 |
45 void Profiler::InitOnce() { | 43 void Profiler::InitOnce() { |
46 // Place some sane restrictions on user controlled flags. | 44 // Place some sane restrictions on user controlled flags. |
47 SetSamplePeriod(FLAG_profile_period); | 45 SetSamplePeriod(FLAG_profile_period); |
48 SetSampleDepth(FLAG_profile_depth); | 46 SetSampleDepth(FLAG_profile_depth); |
(...skipping 1607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1656 | 1654 |
1657 Sample* SampleBuffer::ReserveSample() { | 1655 Sample* SampleBuffer::ReserveSample() { |
1658 ASSERT(samples_ != NULL); | 1656 ASSERT(samples_ != NULL); |
1659 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 1657 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); |
1660 // Map back into sample buffer range. | 1658 // Map back into sample buffer range. |
1661 cursor = cursor % capacity_; | 1659 cursor = cursor % capacity_; |
1662 return At(cursor); | 1660 return At(cursor); |
1663 } | 1661 } |
1664 | 1662 |
1665 | 1663 |
| 1664 static void SetPCMarkerIfSafe(Sample* sample) { |
| 1665 ASSERT(sample != NULL); |
| 1666 |
| 1667 uword* fp = reinterpret_cast<uword*>(sample->fp()); |
| 1668 uword* sp = reinterpret_cast<uword*>(sample->sp()); |
| 1669 |
| 1670 // If FP == SP, the pc marker hasn't been pushed. |
| 1671 if (fp > sp) { |
| 1672 #if defined(TARGET_OS_WINDOWS) |
| 1673 // If the fp is at the beginning of a page, it may be unsafe to access |
| 1674 // the pc marker, because we are reading it from a different thread on |
| 1675 // Windows. The next page may be a guard page. |
| 1676 const intptr_t kPageMask = VirtualMemory::PageSize() - 1; |
| 1677 if ((sample->fp() & kPageMask) == 0) { |
| 1678 return; |
| 1679 } |
| 1680 #endif |
| 1681 const uword pc_marker = *(fp + kPcMarkerSlotFromFp); |
| 1682 sample->set_pc_marker(pc_marker); |
| 1683 } |
| 1684 } |
| 1685 |
| 1686 |
1666 class ProfilerDartStackWalker : public ValueObject { | 1687 class ProfilerDartStackWalker : public ValueObject { |
1667 public: | 1688 public: |
1668 ProfilerDartStackWalker(Isolate* isolate, Sample* sample) | 1689 ProfilerDartStackWalker(Isolate* isolate, Sample* sample) |
1669 : sample_(sample), | 1690 : sample_(sample), |
1670 frame_iterator_(isolate) { | 1691 frame_iterator_(isolate) { |
1671 ASSERT(sample_ != NULL); | 1692 ASSERT(sample_ != NULL); |
1672 } | 1693 } |
1673 | 1694 |
1674 ProfilerDartStackWalker(Isolate* isolate, Sample* sample, uword fp) | 1695 ProfilerDartStackWalker(Isolate* isolate, Sample* sample, uword fp) |
1675 : sample_(sample), | 1696 : sample_(sample), |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1715 uword sp) | 1736 uword sp) |
1716 : sample_(sample), | 1737 : sample_(sample), |
1717 stack_upper_(stack_upper), | 1738 stack_upper_(stack_upper), |
1718 original_pc_(pc), | 1739 original_pc_(pc), |
1719 original_fp_(fp), | 1740 original_fp_(fp), |
1720 original_sp_(sp), | 1741 original_sp_(sp), |
1721 lower_bound_(stack_lower) { | 1742 lower_bound_(stack_lower) { |
1722 ASSERT(sample_ != NULL); | 1743 ASSERT(sample_ != NULL); |
1723 } | 1744 } |
1724 | 1745 |
1725 int walk(Heap* heap) { | 1746 void walk(Heap* heap) { |
1726 const intptr_t kMaxStep = 0x1000; // 4K. | 1747 const intptr_t kMaxStep = VirtualMemory::PageSize(); |
1727 const bool kWalkStack = true; // Walk the stack. | 1748 |
1728 // Always store the exclusive PC. | |
1729 sample_->SetAt(0, original_pc_); | 1749 sample_->SetAt(0, original_pc_); |
1730 if (!kWalkStack) { | 1750 |
1731 // Not walking the stack, only took exclusive sample. | |
1732 return 1; | |
1733 } | |
1734 uword* pc = reinterpret_cast<uword*>(original_pc_); | 1751 uword* pc = reinterpret_cast<uword*>(original_pc_); |
1735 uword* fp = reinterpret_cast<uword*>(original_fp_); | 1752 uword* fp = reinterpret_cast<uword*>(original_fp_); |
1736 uword* previous_fp = fp; | 1753 uword* previous_fp = fp; |
1737 if (original_sp_ > original_fp_) { | 1754 |
1738 // Stack pointer should not be above frame pointer. | 1755 if ((original_fp_ - original_sp_) >= kMaxStep) { |
1739 return 1; | |
1740 } | |
1741 const intptr_t gap = original_fp_ - original_sp_; | |
1742 if (gap >= kMaxStep) { | |
1743 // Gap between frame pointer and stack pointer is | 1756 // Gap between frame pointer and stack pointer is |
1744 // too large. | 1757 // too large. |
1745 return 1; | 1758 return; |
1746 } | 1759 } |
1747 if (original_sp_ < lower_bound_) { | 1760 |
1748 // The stack pointer gives us a better lower bound than | 1761 if (!ValidFramePointer(fp)) { |
1749 // the isolates stack limit. | 1762 return; |
1750 lower_bound_ = original_sp_; | |
1751 } | 1763 } |
1752 #if defined(TARGET_OS_WINDOWS) | 1764 |
1753 // If the original_fp_ is at the beginning of a page, it may be unsafe | 1765 for (int i = 0; i < FLAG_profile_depth; i++) { |
1754 // to access the pc marker, because we are reading it from a different | |
1755 // thread on Windows. The next page may be a guard page. | |
1756 const intptr_t kPageMask = kMaxStep - 1; | |
1757 bool safe_to_read_pc_marker = (original_fp_ & kPageMask) != 0; | |
1758 #else | |
1759 bool safe_to_read_pc_marker = true; | |
1760 #endif | |
1761 if (safe_to_read_pc_marker && (gap > 0)) { | |
1762 // Store the PC marker for the top frame. | |
1763 sample_->set_pc_marker(GetCurrentFramePcMarker(fp)); | |
1764 } | |
1765 int i = 0; | |
1766 for (; i < FLAG_profile_depth; i++) { | |
1767 if (FLAG_profile_verify_stack_walk) { | |
1768 VerifyCodeAddress(heap, i, reinterpret_cast<uword>(pc)); | |
1769 } | |
1770 sample_->SetAt(i, reinterpret_cast<uword>(pc)); | 1766 sample_->SetAt(i, reinterpret_cast<uword>(pc)); |
1771 if (fp == NULL) { | 1767 |
1772 return i + 1; | |
1773 } | |
1774 if (!ValidFramePointer(fp)) { | |
1775 return i + 1; | |
1776 } | |
1777 pc = CallerPC(fp); | 1768 pc = CallerPC(fp); |
1778 previous_fp = fp; | 1769 previous_fp = fp; |
1779 fp = CallerFP(fp); | 1770 fp = CallerFP(fp); |
1780 intptr_t step = fp - previous_fp; | 1771 |
1781 if (fp == NULL) { | 1772 if (fp == NULL) { |
1782 return i + 1; | 1773 return; |
1783 } | 1774 } |
1784 if ((step >= kMaxStep)) { | 1775 |
| 1776 if (fp <= previous_fp) { |
| 1777 // Frame pointer did not move to a higher address. |
| 1778 return; |
| 1779 } |
| 1780 |
| 1781 if ((fp - previous_fp) >= kMaxStep) { |
1785 // Frame pointer step is too large. | 1782 // Frame pointer step is too large. |
1786 return i + 1; | 1783 return; |
1787 } | 1784 } |
1788 if ((fp <= previous_fp)) { | 1785 |
1789 // Frame pointer did not move to a higher address. | 1786 if (!ValidFramePointer(fp)) { |
1790 return i + 1; | 1787 // Frame pointer is outside of isolate stack boundary. |
| 1788 return; |
1791 } | 1789 } |
1792 if (!ValidFramePointer(fp)) { | 1790 |
1793 // Frame pointer is outside of isolate stack bounds. | |
1794 return i + 1; | |
1795 } | |
1796 // Move the lower bound up. | 1791 // Move the lower bound up. |
1797 lower_bound_ = reinterpret_cast<uword>(fp); | 1792 lower_bound_ = reinterpret_cast<uword>(fp); |
1798 } | 1793 } |
1799 return i; | |
1800 } | 1794 } |
1801 | 1795 |
1802 private: | 1796 private: |
1803 void VerifyCodeAddress(Heap* heap, int i, uword pc) { | |
1804 if (heap != NULL) { | |
1805 if (heap->Contains(pc) && !heap->CodeContains(pc)) { | |
1806 for (int j = 0; j < i; j++) { | |
1807 OS::Print("%d %" Px "\n", j, sample_->At(j)); | |
1808 } | |
1809 OS::Print("%d %" Px " <--\n", i, pc); | |
1810 OS::Print("---ASSERT-FAILED---\n"); | |
1811 OS::Print("%" Px " %" Px "\n", original_pc_, original_fp_); | |
1812 UNREACHABLE(); | |
1813 } | |
1814 } | |
1815 } | |
1816 | |
1817 uword* CallerPC(uword* fp) const { | 1797 uword* CallerPC(uword* fp) const { |
1818 ASSERT(fp != NULL); | 1798 ASSERT(fp != NULL); |
1819 return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp)); | 1799 return reinterpret_cast<uword*>(*(fp + kSavedCallerPcSlotFromFp)); |
1820 } | 1800 } |
1821 | 1801 |
1822 uword* CallerFP(uword* fp) const { | 1802 uword* CallerFP(uword* fp) const { |
1823 ASSERT(fp != NULL); | 1803 ASSERT(fp != NULL); |
1824 return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp)); | 1804 return reinterpret_cast<uword*>(*(fp + kSavedCallerFpSlotFromFp)); |
1825 } | 1805 } |
1826 | 1806 |
1827 uword GetCurrentFramePcMarker(uword* fp) const { | |
1828 if (!ValidFramePointer(fp)) { | |
1829 return 0; | |
1830 } | |
1831 return *(fp + kPcMarkerSlotFromFp); | |
1832 } | |
1833 | |
1834 bool ValidFramePointer(uword* fp) const { | 1807 bool ValidFramePointer(uword* fp) const { |
1835 if (fp == NULL) { | 1808 if (fp == NULL) { |
1836 return false; | 1809 return false; |
1837 } | 1810 } |
1838 uword cursor = reinterpret_cast<uword>(fp); | 1811 uword cursor = reinterpret_cast<uword>(fp); |
1839 cursor += sizeof(fp); | 1812 cursor += sizeof(fp); |
1840 bool r = cursor >= lower_bound_ && cursor < stack_upper_; | 1813 bool r = (cursor >= lower_bound_) && (cursor < stack_upper_); |
1841 return r; | 1814 return r; |
1842 } | 1815 } |
1843 | 1816 |
1844 Sample* sample_; | 1817 Sample* sample_; |
1845 const uword stack_upper_; | 1818 const uword stack_upper_; |
1846 const uword original_pc_; | 1819 const uword original_pc_; |
1847 const uword original_fp_; | 1820 const uword original_fp_; |
1848 const uword original_sp_; | 1821 const uword original_sp_; |
1849 uword lower_bound_; | 1822 uword lower_bound_; |
1850 }; | 1823 }; |
1851 | 1824 |
1852 | 1825 |
1853 void Profiler::RecordSampleInterruptCallback( | 1826 void Profiler::RecordSampleInterruptCallback( |
1854 const InterruptedThreadState& state, | 1827 const InterruptedThreadState& state, |
1855 void* data) { | 1828 void* data) { |
1856 Isolate* isolate = reinterpret_cast<Isolate*>(data); | 1829 Isolate* isolate = reinterpret_cast<Isolate*>(data); |
1857 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { | 1830 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| 1831 // No isolate. |
1858 return; | 1832 return; |
1859 } | 1833 } |
| 1834 |
1860 ASSERT(isolate != Dart::vm_isolate()); | 1835 ASSERT(isolate != Dart::vm_isolate()); |
| 1836 |
| 1837 IsolateProfilerData* profiler_data = isolate->profiler_data(); |
| 1838 if (profiler_data == NULL) { |
| 1839 // Profiler not initialized. |
| 1840 return; |
| 1841 } |
| 1842 |
| 1843 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); |
| 1844 if (sample_buffer == NULL) { |
| 1845 // Profiler not initialized. |
| 1846 return; |
| 1847 } |
| 1848 |
| 1849 if ((state.sp == 0) || (state.fp == 0) || (state.pc == 0)) { |
| 1850 // None of these registers should be zero. |
| 1851 return; |
| 1852 } |
| 1853 |
| 1854 if (state.sp > state.fp) { |
| 1855 // Assuming the stack grows down, we should never have a stack pointer above |
| 1856 // the frame pointer. |
| 1857 return; |
| 1858 } |
| 1859 |
1861 if (StubCode::InJumpToExceptionHandlerStub(state.pc)) { | 1860 if (StubCode::InJumpToExceptionHandlerStub(state.pc)) { |
1862 // The JumpToExceptionHandler stub manually adjusts the stack pointer, | 1861 // The JumpToExceptionHandler stub manually adjusts the stack pointer, |
1863 // frame pointer, and some isolate state before jumping to a catch entry. | 1862 // frame pointer, and some isolate state before jumping to a catch entry. |
1864 // It is not safe to walk the stack when executing this stub. | 1863 // It is not safe to walk the stack when executing this stub. |
1865 return; | 1864 return; |
1866 } | 1865 } |
| 1866 |
| 1867 uword stack_lower = 0; |
| 1868 uword stack_upper = 0; |
| 1869 isolate->GetStackBounds(&stack_lower, &stack_upper); |
| 1870 if ((stack_lower == 0) || (stack_upper == 0)) { |
| 1871 // Could not get stack boundary. |
| 1872 return; |
| 1873 } |
| 1874 |
| 1875 if (state.sp > stack_lower) { |
| 1876 // The stack pointer gives us a tighter lower bound. |
| 1877 stack_lower = state.sp; |
| 1878 } |
| 1879 |
| 1880 if (stack_lower >= stack_upper) { |
| 1881 // Stack boundary is invalid. |
| 1882 return; |
| 1883 } |
| 1884 |
| 1885 if ((state.sp < stack_lower) || (state.sp >= stack_upper)) { |
| 1886 // Stack pointer is outside isolate stack boundary. |
| 1887 return; |
| 1888 } |
| 1889 |
| 1890 if ((state.fp < stack_lower) || (state.fp >= stack_upper)) { |
| 1891 // Frame pointer is outside isolate stack boundary. |
| 1892 return; |
| 1893 } |
| 1894 |
| 1895 // At this point we have a valid stack boundary for this isolate and |
| 1896 // know that our initial stack and frame pointers are within the boundary. |
| 1897 |
| 1898 // Increment counter for vm tag. |
1867 VMTagCounters* counters = isolate->vm_tag_counters(); | 1899 VMTagCounters* counters = isolate->vm_tag_counters(); |
1868 ASSERT(counters != NULL); | 1900 ASSERT(counters != NULL); |
1869 counters->Increment(isolate->vm_tag()); | 1901 counters->Increment(isolate->vm_tag()); |
1870 IsolateProfilerData* profiler_data = isolate->profiler_data(); | 1902 |
1871 if (profiler_data == NULL) { | 1903 // Setup sample. |
1872 return; | |
1873 } | |
1874 SampleBuffer* sample_buffer = profiler_data->sample_buffer(); | |
1875 if (sample_buffer == NULL) { | |
1876 return; | |
1877 } | |
1878 Sample* sample = sample_buffer->ReserveSample(); | 1904 Sample* sample = sample_buffer->ReserveSample(); |
1879 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); | 1905 sample->Init(isolate, OS::GetCurrentTimeMicros(), state.tid); |
1880 sample->set_vm_tag(isolate->vm_tag()); | 1906 sample->set_vm_tag(isolate->vm_tag()); |
1881 sample->set_user_tag(isolate->user_tag()); | 1907 sample->set_user_tag(isolate->user_tag()); |
1882 sample->set_sp(state.sp); | 1908 sample->set_sp(state.sp); |
1883 sample->set_fp(state.fp); | 1909 sample->set_fp(state.fp); |
| 1910 SetPCMarkerIfSafe(sample); |
1884 | 1911 |
1885 uword stack_lower = 0; | 1912 // Walk the call stack. |
1886 uword stack_upper = 0; | |
1887 isolate->GetStackBounds(&stack_lower, &stack_upper); | |
1888 if ((stack_lower == 0) || (stack_upper == 0)) { | |
1889 stack_lower = 0; | |
1890 stack_upper = 0; | |
1891 } | |
1892 if (FLAG_profile_vm) { | 1913 if (FLAG_profile_vm) { |
1893 // Collect native and Dart frames. | 1914 // Always walk the native stack collecting both native and Dart frames. |
1894 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | 1915 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, |
1895 state.pc, state.fp, state.sp); | 1916 state.pc, state.fp, state.sp); |
1896 stackWalker.walk(isolate->heap()); | 1917 stackWalker.walk(isolate->heap()); |
1897 } else { | 1918 } else { |
| 1919 // Attempt to walk only the Dart call stack, falling back to walking |
| 1920 // the native stack. |
1898 if ((isolate->stub_code() != NULL) && | 1921 if ((isolate->stub_code() != NULL) && |
1899 (isolate->top_exit_frame_info() != 0) && | 1922 (isolate->top_exit_frame_info() != 0) && |
1900 (isolate->vm_tag() != VMTag::kScriptTagId)) { | 1923 (isolate->vm_tag() != VMTag::kScriptTagId)) { |
1901 // We have a valid exit frame info, use the Dart stack walker. | 1924 // We have a valid exit frame info, use the Dart stack walker. |
1902 ProfilerDartStackWalker stackWalker(isolate, sample); | 1925 ProfilerDartStackWalker stackWalker(isolate, sample); |
1903 stackWalker.walk(); | 1926 stackWalker.walk(); |
1904 } else { | 1927 } else { |
1905 // Collect native and Dart frames. | |
1906 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, | 1928 ProfilerNativeStackWalker stackWalker(sample, stack_lower, stack_upper, |
1907 state.pc, state.fp, state.sp); | 1929 state.pc, state.fp, state.sp); |
1908 stackWalker.walk(isolate->heap()); | 1930 stackWalker.walk(isolate->heap()); |
1909 } | 1931 } |
1910 } | 1932 } |
1911 } | 1933 } |
1912 | 1934 |
1913 } // namespace dart | 1935 } // namespace dart |
OLD | NEW |