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/assert.h" | 5 #include "platform/assert.h" |
| 6 | 6 |
| 7 #include "vm/dart_api_impl.h" | 7 #include "vm/dart_api_impl.h" |
| 8 #include "vm/dart_api_state.h" | 8 #include "vm/dart_api_state.h" |
| 9 #include "vm/globals.h" | 9 #include "vm/globals.h" |
| 10 #include "vm/profiler.h" | 10 #include "vm/profiler.h" |
| 11 #include "vm/profiler_service.h" | 11 #include "vm/profiler_service.h" |
| 12 #include "vm/unit_test.h" | 12 #include "vm/unit_test.h" |
| 13 | 13 |
| 14 namespace dart { | 14 namespace dart { |
| 15 | 15 |
| 16 #ifndef PRODUCT | 16 #ifndef PRODUCT |
| 17 | 17 |
| 18 DECLARE_FLAG(bool, profile_vm); | 18 DECLARE_FLAG(bool, profile_vm); |
| 19 DECLARE_FLAG(int, max_profile_depth); | 19 DECLARE_FLAG(int, max_profile_depth); |
| 20 DECLARE_FLAG(bool, enable_inlining_annotations); | |
| 21 DECLARE_FLAG(int, optimization_counter_threshold); | |
| 22 | |
| 23 template<typename T> | |
| 24 class SetFlagScope : public ValueObject { | |
| 25 public: | |
| 26 SetFlagScope(T* flag, T value) | |
| 27 : flag_(flag), | |
| 28 original_value_(*flag) { | |
| 29 *flag_ = value; | |
| 30 } | |
| 31 | |
| 32 ~SetFlagScope() { | |
| 33 *flag_ = original_value_; | |
| 34 } | |
| 35 | |
| 36 private: | |
| 37 T* flag_; | |
| 38 T original_value_; | |
| 39 }; | |
| 20 | 40 |
| 21 // Some tests are written assuming native stack trace profiling is disabled. | 41 // Some tests are written assuming native stack trace profiling is disabled. |
| 22 class DisableNativeProfileScope : public ValueObject { | 42 class DisableNativeProfileScope : public ValueObject { |
| 23 public: | 43 public: |
| 24 DisableNativeProfileScope() | 44 DisableNativeProfileScope() |
| 25 : FLAG_profile_vm_(FLAG_profile_vm) { | 45 : FLAG_profile_vm_(FLAG_profile_vm) { |
| 26 FLAG_profile_vm = false; | 46 FLAG_profile_vm = false; |
| 27 } | 47 } |
| 28 | 48 |
| 29 ~DisableNativeProfileScope() { | 49 ~DisableNativeProfileScope() { |
| (...skipping 1621 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1651 EXPECT(walker.Down()); | 1671 EXPECT(walker.Down()); |
| 1652 EXPECT_STREQ("init", walker.CurrentName()); | 1672 EXPECT_STREQ("init", walker.CurrentName()); |
| 1653 EXPECT(walker.Down()); | 1673 EXPECT(walker.Down()); |
| 1654 EXPECT_STREQ("go", walker.CurrentName()); | 1674 EXPECT_STREQ("go", walker.CurrentName()); |
| 1655 EXPECT(walker.Down()); | 1675 EXPECT(walker.Down()); |
| 1656 EXPECT_STREQ("main", walker.CurrentName()); | 1676 EXPECT_STREQ("main", walker.CurrentName()); |
| 1657 EXPECT(!walker.Down()); | 1677 EXPECT(!walker.Down()); |
| 1658 } | 1678 } |
| 1659 } | 1679 } |
| 1660 | 1680 |
| 1681 | |
| 1682 TEST_CASE(Profiler_BasicSourcePosition) { | |
| 1683 DisableNativeProfileScope dnps; | |
| 1684 const char* kScript = | |
| 1685 "const AlwaysInline = 'AlwaysInline';\n" | |
| 1686 "const NeverInline = 'NeverInline';\n" | |
| 1687 "class A {\n" | |
| 1688 " var a;\n" | |
| 1689 " var b;\n" | |
| 1690 " @NeverInline A() { }\n" | |
| 1691 "}\n" | |
| 1692 "class B {\n" | |
| 1693 " @AlwaysInline\n" | |
| 1694 " static boo() {\n" | |
| 1695 " return new A();\n" | |
| 1696 " }\n" | |
| 1697 "}\n" | |
| 1698 "main() {\n" | |
| 1699 " B.boo();\n" | |
| 1700 "}\n"; | |
| 1701 | |
| 1702 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
| 1703 EXPECT_VALID(lib); | |
| 1704 Library& root_library = Library::Handle(); | |
| 1705 root_library ^= Api::UnwrapHandle(lib); | |
| 1706 | |
| 1707 const Class& class_a = Class::Handle(GetClass(root_library, "A")); | |
| 1708 EXPECT(!class_a.IsNull()); | |
| 1709 | |
| 1710 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1711 EXPECT_VALID(result); | |
| 1712 | |
| 1713 // Turn on allocation tracing for A. | |
| 1714 class_a.SetTraceAllocation(true); | |
| 1715 | |
| 1716 // Allocate one time. | |
| 1717 result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1718 EXPECT_VALID(result); | |
| 1719 | |
| 1720 { | |
| 1721 Thread* thread = Thread::Current(); | |
| 1722 Isolate* isolate = thread->isolate(); | |
| 1723 StackZone zone(thread); | |
| 1724 HANDLESCOPE(thread); | |
| 1725 Profile profile(isolate); | |
| 1726 AllocationFilter filter(isolate, class_a.id()); | |
| 1727 profile.Build(thread, &filter, Profile::kNoTags); | |
| 1728 // We should have one allocation samples. | |
| 1729 EXPECT_EQ(1, profile.sample_count()); | |
| 1730 ProfileTrieWalker walker(&profile); | |
| 1731 | |
| 1732 // Exclusive function: B.boo -> main. | |
| 1733 walker.Reset(Profile::kExclusiveFunction); | |
| 1734 // Move down from the root. | |
| 1735 EXPECT(walker.Down()); | |
| 1736 EXPECT_STREQ("B.boo", walker.CurrentName()); | |
| 1737 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1738 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1739 EXPECT_EQ(1, walker.CurrentExclusiveTicks()); | |
| 1740 EXPECT_STREQ("A", walker.CurrentToken()); | |
| 1741 EXPECT(walker.Down()); | |
| 1742 EXPECT_STREQ("main", walker.CurrentName()); | |
| 1743 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1744 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1745 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 1746 EXPECT_STREQ("boo", walker.CurrentToken()); | |
| 1747 EXPECT(!walker.Down()); | |
| 1748 } | |
| 1749 } | |
| 1750 | |
| 1751 | |
| 1752 TEST_CASE(Profiler_BasicSourcePositionOptimized) { | |
| 1753 DisableNativeProfileScope dnps; | |
| 1754 // We use the AlwaysInline and NeverInline annotations in this test. | |
| 1755 SetFlagScope<bool> sfs(&FLAG_enable_inlining_annotations, true); | |
| 1756 // Optimize quickly. | |
| 1757 SetFlagScope<int> sfs2(&FLAG_optimization_counter_threshold, 5); | |
| 1758 const char* kScript = | |
| 1759 "const AlwaysInline = 'AlwaysInline';\n" | |
| 1760 "const NeverInline = 'NeverInline';\n" | |
| 1761 "class A {\n" | |
| 1762 " var a;\n" | |
| 1763 " var b;\n" | |
| 1764 " @NeverInline A() { }\n" | |
| 1765 "}\n" | |
| 1766 "class B {\n" | |
| 1767 " @AlwaysInline\n" | |
| 1768 " static boo() {\n" | |
| 1769 " return new A();\n" | |
| 1770 " }\n" | |
| 1771 "}\n" | |
| 1772 "main() {\n" | |
| 1773 " B.boo();\n" | |
| 1774 "}\n"; | |
| 1775 | |
| 1776 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
| 1777 EXPECT_VALID(lib); | |
| 1778 Library& root_library = Library::Handle(); | |
| 1779 root_library ^= Api::UnwrapHandle(lib); | |
| 1780 | |
| 1781 const Class& class_a = Class::Handle(GetClass(root_library, "A")); | |
| 1782 EXPECT(!class_a.IsNull()); | |
| 1783 | |
| 1784 const Function& main = Function::Handle(GetFunction(root_library, "main")); | |
| 1785 EXPECT(!main.IsNull()); | |
| 1786 | |
| 1787 // Warm up function. | |
| 1788 while (true) { | |
| 1789 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1790 EXPECT_VALID(result); | |
| 1791 const Code& code = Code::Handle(main.CurrentCode()); | |
| 1792 if (code.is_optimized()) { | |
| 1793 // Warmed up. | |
| 1794 break; | |
| 1795 } | |
| 1796 } | |
| 1797 | |
| 1798 // Turn on allocation tracing for A. | |
| 1799 class_a.SetTraceAllocation(true); | |
| 1800 | |
| 1801 // Allocate one time. | |
| 1802 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1803 EXPECT_VALID(result); | |
| 1804 | |
| 1805 // Still optimized. | |
| 1806 const Code& code = Code::Handle(main.CurrentCode()); | |
| 1807 EXPECT(code.is_optimized()); | |
| 1808 | |
| 1809 { | |
| 1810 Thread* thread = Thread::Current(); | |
| 1811 Isolate* isolate = thread->isolate(); | |
| 1812 StackZone zone(thread); | |
| 1813 HANDLESCOPE(thread); | |
| 1814 Profile profile(isolate); | |
| 1815 AllocationFilter filter(isolate, class_a.id()); | |
| 1816 profile.Build(thread, &filter, Profile::kNoTags); | |
| 1817 // We should have one allocation samples. | |
| 1818 EXPECT_EQ(1, profile.sample_count()); | |
| 1819 ProfileTrieWalker walker(&profile); | |
| 1820 | |
| 1821 // Exclusive function: B.boo -> main. | |
| 1822 walker.Reset(Profile::kExclusiveFunction); | |
| 1823 // Move down from the root. | |
| 1824 EXPECT(walker.Down()); | |
| 1825 EXPECT_STREQ("B.boo", walker.CurrentName()); | |
| 1826 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1827 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1828 EXPECT_EQ(1, walker.CurrentExclusiveTicks()); | |
| 1829 EXPECT_STREQ("A", walker.CurrentToken()); | |
| 1830 EXPECT(walker.Down()); | |
| 1831 EXPECT_STREQ("main", walker.CurrentName()); | |
| 1832 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1833 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1834 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 1835 EXPECT_STREQ("boo", walker.CurrentToken()); | |
| 1836 EXPECT(!walker.Down()); | |
| 1837 } | |
| 1838 } | |
| 1839 | |
| 1840 | |
| 1841 TEST_CASE(Profiler_SourcePosition) { | |
| 1842 DisableNativeProfileScope dnps; | |
| 1843 const char* kScript = | |
| 1844 "const AlwaysInline = 'AlwaysInline';\n" | |
| 1845 "const NeverInline = 'NeverInline';\n" | |
| 1846 "class A {\n" | |
| 1847 " var a;\n" | |
| 1848 " var b;\n" | |
| 1849 " @NeverInline A() { }\n" | |
| 1850 "}\n" | |
| 1851 "class B {\n" | |
| 1852 " @NeverInline\n" | |
| 1853 " static oats() {\n" | |
| 1854 " return boo();\n" | |
| 1855 " }\n" | |
| 1856 " @AlwaysInline\n" | |
| 1857 " static boo() {\n" | |
| 1858 " return new A();\n" | |
| 1859 " }\n" | |
| 1860 "}\n" | |
| 1861 "class C {\n" | |
| 1862 " @NeverInline bacon() {\n" | |
| 1863 " return fox();\n" | |
| 1864 " }\n" | |
| 1865 " @AlwaysInline fox() {\n" | |
| 1866 " return B.oats();\n" | |
| 1867 " }\n" | |
| 1868 "}\n" | |
| 1869 "main() {\n" | |
| 1870 " new C()..bacon();\n" | |
| 1871 "}\n"; | |
| 1872 | |
| 1873 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
| 1874 EXPECT_VALID(lib); | |
| 1875 Library& root_library = Library::Handle(); | |
| 1876 root_library ^= Api::UnwrapHandle(lib); | |
| 1877 | |
| 1878 const Class& class_a = Class::Handle(GetClass(root_library, "A")); | |
| 1879 EXPECT(!class_a.IsNull()); | |
| 1880 | |
| 1881 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1882 EXPECT_VALID(result); | |
| 1883 | |
| 1884 // Turn on allocation tracing for A. | |
| 1885 class_a.SetTraceAllocation(true); | |
| 1886 | |
| 1887 // Allocate one time. | |
| 1888 result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1889 EXPECT_VALID(result); | |
| 1890 | |
| 1891 { | |
| 1892 Thread* thread = Thread::Current(); | |
| 1893 Isolate* isolate = thread->isolate(); | |
| 1894 StackZone zone(thread); | |
| 1895 HANDLESCOPE(thread); | |
| 1896 Profile profile(isolate); | |
| 1897 AllocationFilter filter(isolate, class_a.id()); | |
| 1898 profile.Build(thread, &filter, Profile::kNoTags); | |
| 1899 // We should have one allocation samples. | |
| 1900 EXPECT_EQ(1, profile.sample_count()); | |
| 1901 ProfileTrieWalker walker(&profile); | |
| 1902 | |
| 1903 // Exclusive function: B.boo -> main. | |
| 1904 walker.Reset(Profile::kExclusiveFunction); | |
| 1905 // Move down from the root. | |
| 1906 EXPECT(walker.Down()); | |
| 1907 EXPECT_STREQ("B.boo", walker.CurrentName()); | |
| 1908 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1909 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1910 EXPECT_EQ(1, walker.CurrentExclusiveTicks()); | |
| 1911 EXPECT_STREQ("A", walker.CurrentToken()); | |
| 1912 EXPECT(walker.Down()); | |
| 1913 EXPECT_STREQ("B.oats", walker.CurrentName()); | |
| 1914 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1915 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1916 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 1917 EXPECT_STREQ("boo", walker.CurrentToken()); | |
| 1918 EXPECT(walker.Down()); | |
| 1919 EXPECT_STREQ("C.fox", walker.CurrentName()); | |
| 1920 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1921 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1922 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 1923 EXPECT_STREQ("oats", walker.CurrentToken()); | |
| 1924 EXPECT(walker.Down()); | |
| 1925 EXPECT_STREQ("C.bacon", walker.CurrentName()); | |
| 1926 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1927 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1928 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 1929 EXPECT_STREQ("fox", walker.CurrentToken()); | |
| 1930 EXPECT(walker.Down()); | |
| 1931 EXPECT_STREQ("main", walker.CurrentName()); | |
| 1932 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 1933 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 1934 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 1935 EXPECT_STREQ("bacon", walker.CurrentToken()); | |
| 1936 EXPECT(!walker.Down()); | |
| 1937 } | |
| 1938 } | |
| 1939 | |
| 1940 | |
| 1941 TEST_CASE(Profiler_SourcePositionOptimized) { | |
|
srdjan
2016/03/02 19:02:56
Disable background compilation
Cutch
2016/03/02 19:14:08
Done here and elsewhere.
| |
| 1942 DisableNativeProfileScope dnps; | |
| 1943 // We use the AlwaysInline and NeverInline annotations in this test. | |
| 1944 SetFlagScope<bool> sfs(&FLAG_enable_inlining_annotations, true); | |
| 1945 // Optimize quickly. | |
| 1946 SetFlagScope<int> sfs2(&FLAG_optimization_counter_threshold, 5); | |
| 1947 | |
| 1948 const char* kScript = | |
| 1949 "const AlwaysInline = 'AlwaysInline';\n" | |
| 1950 "const NeverInline = 'NeverInline';\n" | |
| 1951 "class A {\n" | |
| 1952 " var a;\n" | |
| 1953 " var b;\n" | |
| 1954 " @NeverInline A() { }\n" | |
| 1955 "}\n" | |
| 1956 "class B {\n" | |
| 1957 " @NeverInline\n" | |
| 1958 " static oats() {\n" | |
| 1959 " return boo();\n" | |
| 1960 " }\n" | |
| 1961 " @AlwaysInline\n" | |
| 1962 " static boo() {\n" | |
| 1963 " return new A();\n" | |
| 1964 " }\n" | |
| 1965 "}\n" | |
| 1966 "class C {\n" | |
| 1967 " @NeverInline bacon() {\n" | |
| 1968 " return fox();\n" | |
| 1969 " }\n" | |
| 1970 " @AlwaysInline fox() {\n" | |
| 1971 " return B.oats();\n" | |
| 1972 " }\n" | |
| 1973 "}\n" | |
| 1974 "main() {\n" | |
| 1975 " new C()..bacon();\n" | |
| 1976 "}\n"; | |
| 1977 | |
| 1978 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
| 1979 EXPECT_VALID(lib); | |
| 1980 Library& root_library = Library::Handle(); | |
| 1981 root_library ^= Api::UnwrapHandle(lib); | |
| 1982 | |
| 1983 const Class& class_a = Class::Handle(GetClass(root_library, "A")); | |
| 1984 EXPECT(!class_a.IsNull()); | |
| 1985 | |
| 1986 const Function& main = Function::Handle(GetFunction(root_library, "main")); | |
| 1987 EXPECT(!main.IsNull()); | |
| 1988 | |
| 1989 // Warm up function. | |
| 1990 while (true) { | |
| 1991 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 1992 EXPECT_VALID(result); | |
| 1993 const Code& code = Code::Handle(main.CurrentCode()); | |
| 1994 if (code.is_optimized()) { | |
| 1995 // Warmed up. | |
| 1996 break; | |
| 1997 } | |
| 1998 } | |
| 1999 | |
| 2000 // Turn on allocation tracing for A. | |
| 2001 class_a.SetTraceAllocation(true); | |
| 2002 | |
| 2003 // Allocate one time. | |
| 2004 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 2005 EXPECT_VALID(result); | |
| 2006 | |
| 2007 // Still optimized. | |
| 2008 const Code& code = Code::Handle(main.CurrentCode()); | |
| 2009 EXPECT(code.is_optimized()); | |
| 2010 | |
| 2011 { | |
| 2012 Thread* thread = Thread::Current(); | |
| 2013 Isolate* isolate = thread->isolate(); | |
| 2014 StackZone zone(thread); | |
| 2015 HANDLESCOPE(thread); | |
| 2016 Profile profile(isolate); | |
| 2017 AllocationFilter filter(isolate, class_a.id()); | |
| 2018 profile.Build(thread, &filter, Profile::kNoTags); | |
| 2019 // We should have one allocation samples. | |
| 2020 EXPECT_EQ(1, profile.sample_count()); | |
| 2021 ProfileTrieWalker walker(&profile); | |
| 2022 | |
| 2023 // Exclusive function: B.boo -> main. | |
| 2024 walker.Reset(Profile::kExclusiveFunction); | |
| 2025 // Move down from the root. | |
| 2026 EXPECT(walker.Down()); | |
| 2027 EXPECT_STREQ("B.boo", walker.CurrentName()); | |
| 2028 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2029 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2030 EXPECT_EQ(1, walker.CurrentExclusiveTicks()); | |
| 2031 EXPECT_STREQ("A", walker.CurrentToken()); | |
| 2032 EXPECT(walker.Down()); | |
| 2033 EXPECT_STREQ("B.oats", walker.CurrentName()); | |
| 2034 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2035 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2036 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2037 EXPECT_STREQ("boo", walker.CurrentToken()); | |
| 2038 EXPECT(walker.Down()); | |
| 2039 EXPECT_STREQ("C.fox", walker.CurrentName()); | |
| 2040 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2041 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2042 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2043 EXPECT_STREQ("oats", walker.CurrentToken()); | |
| 2044 EXPECT(walker.Down()); | |
| 2045 EXPECT_STREQ("C.bacon", walker.CurrentName()); | |
| 2046 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2047 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2048 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2049 EXPECT_STREQ("fox", walker.CurrentToken()); | |
| 2050 EXPECT(walker.Down()); | |
| 2051 EXPECT_STREQ("main", walker.CurrentName()); | |
| 2052 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2053 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2054 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2055 EXPECT_STREQ("bacon", walker.CurrentToken()); | |
| 2056 EXPECT(!walker.Down()); | |
| 2057 } | |
| 2058 } | |
| 2059 | |
| 2060 | |
| 2061 TEST_CASE(Profiler_BinaryOperatorSourcePosition) { | |
| 2062 DisableNativeProfileScope dnps; | |
| 2063 const char* kScript = | |
| 2064 "const AlwaysInline = 'AlwaysInline';\n" | |
| 2065 "const NeverInline = 'NeverInline';\n" | |
| 2066 "class A {\n" | |
| 2067 " var a;\n" | |
| 2068 " var b;\n" | |
| 2069 " @NeverInline A() { }\n" | |
| 2070 "}\n" | |
| 2071 "class B {\n" | |
| 2072 " @NeverInline\n" | |
| 2073 " static oats() {\n" | |
| 2074 " return boo();\n" | |
| 2075 " }\n" | |
| 2076 " @AlwaysInline\n" | |
| 2077 " static boo() {\n" | |
| 2078 " return new A();\n" | |
| 2079 " }\n" | |
| 2080 "}\n" | |
| 2081 "class C {\n" | |
| 2082 " @NeverInline bacon() {\n" | |
| 2083 " return this + this;\n" | |
| 2084 " }\n" | |
| 2085 " @AlwaysInline operator+(C other) {\n" | |
| 2086 " return fox();\n" | |
| 2087 " }\n" | |
| 2088 " @AlwaysInline fox() {\n" | |
| 2089 " return B.oats();\n" | |
| 2090 " }\n" | |
| 2091 "}\n" | |
| 2092 "main() {\n" | |
| 2093 " new C()..bacon();\n" | |
| 2094 "}\n"; | |
| 2095 | |
| 2096 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
| 2097 EXPECT_VALID(lib); | |
| 2098 Library& root_library = Library::Handle(); | |
| 2099 root_library ^= Api::UnwrapHandle(lib); | |
| 2100 | |
| 2101 const Class& class_a = Class::Handle(GetClass(root_library, "A")); | |
| 2102 EXPECT(!class_a.IsNull()); | |
| 2103 | |
| 2104 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 2105 EXPECT_VALID(result); | |
| 2106 | |
| 2107 // Turn on allocation tracing for A. | |
| 2108 class_a.SetTraceAllocation(true); | |
| 2109 | |
| 2110 // Allocate one time. | |
| 2111 result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 2112 EXPECT_VALID(result); | |
| 2113 | |
| 2114 { | |
| 2115 Thread* thread = Thread::Current(); | |
| 2116 Isolate* isolate = thread->isolate(); | |
| 2117 StackZone zone(thread); | |
| 2118 HANDLESCOPE(thread); | |
| 2119 Profile profile(isolate); | |
| 2120 AllocationFilter filter(isolate, class_a.id()); | |
| 2121 profile.Build(thread, &filter, Profile::kNoTags); | |
| 2122 // We should have one allocation samples. | |
| 2123 EXPECT_EQ(1, profile.sample_count()); | |
| 2124 ProfileTrieWalker walker(&profile); | |
| 2125 | |
| 2126 // Exclusive function: B.boo -> main. | |
| 2127 walker.Reset(Profile::kExclusiveFunction); | |
| 2128 // Move down from the root. | |
| 2129 EXPECT(walker.Down()); | |
| 2130 EXPECT_STREQ("B.boo", walker.CurrentName()); | |
| 2131 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2132 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2133 EXPECT_EQ(1, walker.CurrentExclusiveTicks()); | |
| 2134 EXPECT_STREQ("A", walker.CurrentToken()); | |
| 2135 EXPECT(walker.Down()); | |
| 2136 EXPECT_STREQ("B.oats", walker.CurrentName()); | |
| 2137 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2138 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2139 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2140 EXPECT_STREQ("boo", walker.CurrentToken()); | |
| 2141 EXPECT(walker.Down()); | |
| 2142 EXPECT_STREQ("C.fox", walker.CurrentName()); | |
| 2143 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2144 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2145 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2146 EXPECT_STREQ("oats", walker.CurrentToken()); | |
| 2147 EXPECT(walker.Down()); | |
| 2148 EXPECT_STREQ("C.+", walker.CurrentName()); | |
| 2149 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2150 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2151 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2152 EXPECT_STREQ("fox", walker.CurrentToken()); | |
| 2153 EXPECT(walker.Down()); | |
| 2154 EXPECT_STREQ("C.bacon", walker.CurrentName()); | |
| 2155 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2156 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2157 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2158 EXPECT_STREQ("+", walker.CurrentToken()); | |
| 2159 EXPECT(walker.Down()); | |
| 2160 EXPECT_STREQ("main", walker.CurrentName()); | |
| 2161 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2162 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2163 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2164 EXPECT_STREQ("bacon", walker.CurrentToken()); | |
| 2165 EXPECT(!walker.Down()); | |
| 2166 } | |
| 2167 } | |
| 2168 | |
| 2169 | |
| 2170 TEST_CASE(Profiler_BinaryOperatorSourcePositionOptimized) { | |
|
srdjan
2016/03/02 19:02:56
Disable background compilation
| |
| 2171 DisableNativeProfileScope dnps; | |
| 2172 // We use the AlwaysInline and NeverInline annotations in this test. | |
| 2173 SetFlagScope<bool> sfs(&FLAG_enable_inlining_annotations, true); | |
| 2174 // Optimize quickly. | |
| 2175 SetFlagScope<int> sfs2(&FLAG_optimization_counter_threshold, 5); | |
| 2176 | |
| 2177 const char* kScript = | |
| 2178 "const AlwaysInline = 'AlwaysInline';\n" | |
| 2179 "const NeverInline = 'NeverInline';\n" | |
| 2180 "class A {\n" | |
| 2181 " var a;\n" | |
| 2182 " var b;\n" | |
| 2183 " @NeverInline A() { }\n" | |
| 2184 "}\n" | |
| 2185 "class B {\n" | |
| 2186 " @NeverInline\n" | |
| 2187 " static oats() {\n" | |
| 2188 " return boo();\n" | |
| 2189 " }\n" | |
| 2190 " @AlwaysInline\n" | |
| 2191 " static boo() {\n" | |
| 2192 " return new A();\n" | |
| 2193 " }\n" | |
| 2194 "}\n" | |
| 2195 "class C {\n" | |
| 2196 " @NeverInline bacon() {\n" | |
| 2197 " return this + this;\n" | |
| 2198 " }\n" | |
| 2199 " @AlwaysInline operator+(C other) {\n" | |
| 2200 " return fox();\n" | |
| 2201 " }\n" | |
| 2202 " @AlwaysInline fox() {\n" | |
| 2203 " return B.oats();\n" | |
| 2204 " }\n" | |
| 2205 "}\n" | |
| 2206 "main() {\n" | |
| 2207 " new C()..bacon();\n" | |
| 2208 "}\n"; | |
| 2209 | |
| 2210 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); | |
| 2211 EXPECT_VALID(lib); | |
| 2212 Library& root_library = Library::Handle(); | |
| 2213 root_library ^= Api::UnwrapHandle(lib); | |
| 2214 | |
| 2215 const Class& class_a = Class::Handle(GetClass(root_library, "A")); | |
| 2216 EXPECT(!class_a.IsNull()); | |
| 2217 | |
| 2218 const Function& main = Function::Handle(GetFunction(root_library, "main")); | |
| 2219 EXPECT(!main.IsNull()); | |
| 2220 | |
| 2221 // Warm up function. | |
| 2222 while (true) { | |
| 2223 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 2224 EXPECT_VALID(result); | |
| 2225 const Code& code = Code::Handle(main.CurrentCode()); | |
| 2226 if (code.is_optimized()) { | |
| 2227 // Warmed up. | |
| 2228 break; | |
| 2229 } | |
| 2230 } | |
| 2231 | |
| 2232 // Turn on allocation tracing for A. | |
| 2233 class_a.SetTraceAllocation(true); | |
| 2234 | |
| 2235 // Allocate one time. | |
| 2236 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL); | |
| 2237 EXPECT_VALID(result); | |
| 2238 | |
| 2239 // Still optimized. | |
| 2240 const Code& code = Code::Handle(main.CurrentCode()); | |
| 2241 EXPECT(code.is_optimized()); | |
| 2242 | |
| 2243 { | |
| 2244 Thread* thread = Thread::Current(); | |
| 2245 Isolate* isolate = thread->isolate(); | |
| 2246 StackZone zone(thread); | |
| 2247 HANDLESCOPE(thread); | |
| 2248 Profile profile(isolate); | |
| 2249 AllocationFilter filter(isolate, class_a.id()); | |
| 2250 profile.Build(thread, &filter, Profile::kNoTags); | |
| 2251 // We should have one allocation samples. | |
| 2252 EXPECT_EQ(1, profile.sample_count()); | |
| 2253 ProfileTrieWalker walker(&profile); | |
| 2254 | |
| 2255 // Exclusive function: B.boo -> main. | |
| 2256 walker.Reset(Profile::kExclusiveFunction); | |
| 2257 // Move down from the root. | |
| 2258 EXPECT(walker.Down()); | |
| 2259 EXPECT_STREQ("B.boo", walker.CurrentName()); | |
| 2260 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2261 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2262 EXPECT_EQ(1, walker.CurrentExclusiveTicks()); | |
| 2263 EXPECT_STREQ("A", walker.CurrentToken()); | |
| 2264 EXPECT(walker.Down()); | |
| 2265 EXPECT_STREQ("B.oats", walker.CurrentName()); | |
| 2266 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2267 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2268 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2269 EXPECT_STREQ("boo", walker.CurrentToken()); | |
| 2270 EXPECT(walker.Down()); | |
| 2271 EXPECT_STREQ("C.fox", walker.CurrentName()); | |
| 2272 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2273 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2274 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2275 EXPECT_STREQ("oats", walker.CurrentToken()); | |
| 2276 EXPECT(walker.Down()); | |
| 2277 EXPECT_STREQ("C.+", walker.CurrentName()); | |
| 2278 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2279 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2280 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2281 EXPECT_STREQ("fox", walker.CurrentToken()); | |
| 2282 EXPECT(walker.Down()); | |
| 2283 EXPECT_STREQ("C.bacon", walker.CurrentName()); | |
| 2284 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2285 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2286 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2287 EXPECT_STREQ("+", walker.CurrentToken()); | |
| 2288 EXPECT(walker.Down()); | |
| 2289 EXPECT_STREQ("main", walker.CurrentName()); | |
| 2290 EXPECT_EQ(1, walker.CurrentNodeTickCount()); | |
| 2291 EXPECT_EQ(1, walker.CurrentInclusiveTicks()); | |
| 2292 EXPECT_EQ(0, walker.CurrentExclusiveTicks()); | |
| 2293 EXPECT_STREQ("bacon", walker.CurrentToken()); | |
| 2294 EXPECT(!walker.Down()); | |
| 2295 } | |
| 2296 } | |
| 2297 | |
| 1661 #endif // !PRODUCT | 2298 #endif // !PRODUCT |
| 1662 | 2299 |
| 1663 } // namespace dart | 2300 } // namespace dart |
| OLD | NEW |