OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 using i::SmartPointer; | 49 using i::SmartPointer; |
50 using i::Vector; | 50 using i::Vector; |
51 | 51 |
52 | 52 |
53 // Helper methods | 53 // Helper methods |
54 static v8::Local<v8::Function> GetFunction(v8::Context* env, const char* name) { | 54 static v8::Local<v8::Function> GetFunction(v8::Context* env, const char* name) { |
55 return v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str(name))); | 55 return v8::Local<v8::Function>::Cast(env->Global()->Get(v8_str(name))); |
56 } | 56 } |
57 | 57 |
58 | 58 |
| 59 static int offset(const char* src, const char* substring) { |
| 60 return static_cast<int>(strstr(src, substring) - src); |
| 61 } |
| 62 |
| 63 |
59 static const char* reason(const i::Deoptimizer::DeoptReason reason) { | 64 static const char* reason(const i::Deoptimizer::DeoptReason reason) { |
60 return i::Deoptimizer::GetDeoptReason(reason); | 65 return i::Deoptimizer::GetDeoptReason(reason); |
61 } | 66 } |
62 | 67 |
63 | 68 |
64 TEST(StartStop) { | 69 TEST(StartStop) { |
65 i::Isolate* isolate = CcTest::i_isolate(); | 70 i::Isolate* isolate = CcTest::i_isolate(); |
66 CpuProfilesCollection profiles(isolate->heap()); | 71 CpuProfilesCollection profiles(isolate->heap()); |
67 ProfileGenerator generator(&profiles); | 72 ProfileGenerator generator(&profiles); |
68 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( | 73 SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( |
(...skipping 1638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1707 outer_profile = NULL; | 1712 outer_profile = NULL; |
1708 CHECK_EQ(0, iprofiler->GetProfilesCount()); | 1713 CHECK_EQ(0, iprofiler->GetProfilesCount()); |
1709 } | 1714 } |
1710 | 1715 |
1711 | 1716 |
1712 const char* GetBranchDeoptReason(i::CpuProfile* iprofile, const char* branch[], | 1717 const char* GetBranchDeoptReason(i::CpuProfile* iprofile, const char* branch[], |
1713 int length) { | 1718 int length) { |
1714 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); | 1719 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); |
1715 const ProfileNode* iopt_function = NULL; | 1720 const ProfileNode* iopt_function = NULL; |
1716 iopt_function = GetSimpleBranch(profile, branch, length); | 1721 iopt_function = GetSimpleBranch(profile, branch, length); |
1717 CHECK_EQ(1, iopt_function->deopt_infos().length()); | 1722 CHECK_EQ(1, iopt_function->deopt_infos().size()); |
1718 return iopt_function->deopt_infos()[0].deopt_reason; | 1723 return iopt_function->deopt_infos()[0].deopt_reason; |
1719 } | 1724 } |
1720 | 1725 |
1721 | 1726 |
1722 // deopt at top function | 1727 // deopt at top function |
1723 TEST(CollectDeoptEvents) { | 1728 TEST(CollectDeoptEvents) { |
1724 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; | 1729 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; |
1725 i::FLAG_allow_natives_syntax = true; | 1730 i::FLAG_allow_natives_syntax = true; |
1726 v8::HandleScope scope(CcTest::isolate()); | 1731 v8::HandleScope scope(CcTest::isolate()); |
1727 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); | 1732 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1770 "opt_function2(1, 1);\n" | 1775 "opt_function2(1, 1);\n" |
1771 "\n" | 1776 "\n" |
1772 "opt_function2(0, 1);\n" | 1777 "opt_function2(0, 1);\n" |
1773 "\n" | 1778 "\n" |
1774 "stopProfiling();\n" | 1779 "stopProfiling();\n" |
1775 "\n"; | 1780 "\n"; |
1776 | 1781 |
1777 v8::Script::Compile(v8_str(source))->Run(); | 1782 v8::Script::Compile(v8_str(source))->Run(); |
1778 i::CpuProfile* iprofile = iprofiler->GetProfile(0); | 1783 i::CpuProfile* iprofile = iprofiler->GetProfile(0); |
1779 iprofile->Print(); | 1784 iprofile->Print(); |
| 1785 /* The expected profile |
| 1786 [Top down]: |
| 1787 0 (root) 0 #1 |
| 1788 23 32 #2 |
| 1789 1 opt_function2 31 #7 |
| 1790 1 opt_function2 31 #8 |
| 1791 ;;; deopted at script_id: 31 position: 106 with reason |
| 1792 'division by zero'. |
| 1793 2 opt_function0 29 #3 |
| 1794 4 opt_function0 29 #4 |
| 1795 ;;; deopted at script_id: 29 position: 108 with reason 'not a |
| 1796 heap number'. |
| 1797 0 opt_function1 30 #5 |
| 1798 1 opt_function1 30 #6 |
| 1799 ;;; deopted at script_id: 30 position: 108 with reason 'lost |
| 1800 precision or NaN'. |
| 1801 */ |
| 1802 |
1780 { | 1803 { |
1781 const char* branch[] = {"", "opt_function0", "opt_function0"}; | 1804 const char* branch[] = {"", "opt_function0", "opt_function0"}; |
1782 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), | 1805 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), |
1783 GetBranchDeoptReason(iprofile, branch, arraysize(branch))); | 1806 GetBranchDeoptReason(iprofile, branch, arraysize(branch))); |
1784 } | 1807 } |
1785 { | 1808 { |
1786 const char* branch[] = {"", "opt_function1", "opt_function1"}; | 1809 const char* branch[] = {"", "opt_function1", "opt_function1"}; |
1787 const char* deopt_reason = | 1810 const char* deopt_reason = |
1788 GetBranchDeoptReason(iprofile, branch, arraysize(branch)); | 1811 GetBranchDeoptReason(iprofile, branch, arraysize(branch)); |
1789 if (deopt_reason != reason(i::Deoptimizer::kNaN) && | 1812 if (deopt_reason != reason(i::Deoptimizer::kNaN) && |
(...skipping 17 matching lines...) Expand all Loading... |
1807 v8::HandleScope scope(CcTest::isolate()); | 1830 v8::HandleScope scope(CcTest::isolate()); |
1808 | 1831 |
1809 const char* source = | 1832 const char* source = |
1810 "function CompareStatementWithThis() {\n" | 1833 "function CompareStatementWithThis() {\n" |
1811 " if (this === 1) {}\n" | 1834 " if (this === 1) {}\n" |
1812 "}\n" | 1835 "}\n" |
1813 "CompareStatementWithThis();\n"; | 1836 "CompareStatementWithThis();\n"; |
1814 | 1837 |
1815 v8::Script::Compile(v8_str(source))->Run(); | 1838 v8::Script::Compile(v8_str(source))->Run(); |
1816 } | 1839 } |
| 1840 |
| 1841 |
| 1842 static const char* inlined_source = |
| 1843 "function opt_function(left, right) { var k = left / 10; var r = 10 / " |
| 1844 "right; return k + r; }\n"; |
| 1845 // 0.........1.........2.........3.........4....*....5.........6......*..7 |
| 1846 |
| 1847 |
| 1848 // deopt at the first level inlined function |
| 1849 TEST(DeoptAtFirstLevelInlinedSource) { |
| 1850 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; |
| 1851 i::FLAG_allow_natives_syntax = true; |
| 1852 v8::HandleScope scope(CcTest::isolate()); |
| 1853 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); |
| 1854 v8::Context::Scope context_scope(env); |
| 1855 v8::Isolate* isolate = env->GetIsolate(); |
| 1856 v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); |
| 1857 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); |
| 1858 |
| 1859 // 0.........1.........2.........3.........4.........5.........6.........7 |
| 1860 const char* source = |
| 1861 "function test(left, right) { return opt_function(left, right); }\n" |
| 1862 "\n" |
| 1863 "startProfiling();\n" |
| 1864 "\n" |
| 1865 "test(10, 10);\n" |
| 1866 "\n" |
| 1867 "%OptimizeFunctionOnNextCall(test)\n" |
| 1868 "\n" |
| 1869 "test(10, 10);\n" |
| 1870 "\n" |
| 1871 "test(undefined, 10);\n" |
| 1872 "\n" |
| 1873 "stopProfiling();\n" |
| 1874 "\n"; |
| 1875 |
| 1876 v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source); |
| 1877 inlined_script->Run(); |
| 1878 int inlined_script_id = inlined_script->GetUnboundScript()->GetId(); |
| 1879 |
| 1880 v8::Handle<v8::Script> script = v8_compile(source); |
| 1881 script->Run(); |
| 1882 int script_id = script->GetUnboundScript()->GetId(); |
| 1883 |
| 1884 i::CpuProfile* iprofile = iprofiler->GetProfile(0); |
| 1885 iprofile->Print(); |
| 1886 /* The expected profile output |
| 1887 [Top down]: |
| 1888 0 (root) 0 #1 |
| 1889 10 30 #2 |
| 1890 1 test 30 #3 |
| 1891 ;;; deopted at script_id: 29 position: 45 with reason 'not a |
| 1892 heap number'. |
| 1893 ;;; Inline point: script_id 30 position: 36. |
| 1894 4 opt_function 29 #4 |
| 1895 */ |
| 1896 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); |
| 1897 |
| 1898 const char* branch[] = {"", "test"}; |
| 1899 const ProfileNode* itest_node = |
| 1900 GetSimpleBranch(profile, branch, arraysize(branch)); |
| 1901 const std::vector<i::DeoptInfo>& deopt_infos = itest_node->deopt_infos(); |
| 1902 CHECK_EQ(1, deopt_infos.size()); |
| 1903 |
| 1904 const i::DeoptInfo& info0 = deopt_infos[0]; |
| 1905 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info0.deopt_reason); |
| 1906 CHECK_EQ(2, info0.stack.size()); |
| 1907 CHECK_EQ(inlined_script_id, info0.stack[0].script_id); |
| 1908 CHECK_EQ(offset(inlined_source, "left /"), info0.stack[0].position); |
| 1909 CHECK_EQ(script_id, info0.stack[1].script_id); |
| 1910 CHECK_EQ(offset(source, "opt_function(left,"), info0.stack[1].position); |
| 1911 |
| 1912 iprofiler->DeleteProfile(iprofile); |
| 1913 } |
| 1914 |
| 1915 |
| 1916 // deopt at the second level inlined function |
| 1917 TEST(DeoptAtSecondLevelInlinedSource) { |
| 1918 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; |
| 1919 i::FLAG_allow_natives_syntax = true; |
| 1920 v8::HandleScope scope(CcTest::isolate()); |
| 1921 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); |
| 1922 v8::Context::Scope context_scope(env); |
| 1923 v8::Isolate* isolate = env->GetIsolate(); |
| 1924 v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); |
| 1925 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); |
| 1926 |
| 1927 // 0.........1.........2.........3.........4.........5.........6.........7 |
| 1928 const char* source = |
| 1929 "function test2(left, right) { return opt_function(left, right); }\n" |
| 1930 "function test1(left, right) { return test2(left, right); }\n" |
| 1931 "\n" |
| 1932 "startProfiling();\n" |
| 1933 "\n" |
| 1934 "test1(10, 10);\n" |
| 1935 "\n" |
| 1936 "%OptimizeFunctionOnNextCall(test1)\n" |
| 1937 "\n" |
| 1938 "test1(10, 10);\n" |
| 1939 "\n" |
| 1940 "test1(undefined, 10);\n" |
| 1941 "\n" |
| 1942 "stopProfiling();\n" |
| 1943 "\n"; |
| 1944 |
| 1945 v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source); |
| 1946 inlined_script->Run(); |
| 1947 int inlined_script_id = inlined_script->GetUnboundScript()->GetId(); |
| 1948 |
| 1949 v8::Handle<v8::Script> script = v8_compile(source); |
| 1950 script->Run(); |
| 1951 int script_id = script->GetUnboundScript()->GetId(); |
| 1952 |
| 1953 i::CpuProfile* iprofile = iprofiler->GetProfile(0); |
| 1954 iprofile->Print(); |
| 1955 /* The expected profile output |
| 1956 [Top down]: |
| 1957 0 (root) 0 #1 |
| 1958 11 30 #2 |
| 1959 1 test1 30 #3 |
| 1960 ;;; deopted at script_id: 29 position: 45 with reason 'not a |
| 1961 heap number'. |
| 1962 ;;; Inline point: script_id 30 position: 37. |
| 1963 ;;; Inline point: script_id 30 position: 103. |
| 1964 1 test2 30 #4 |
| 1965 3 opt_function 29 #5 |
| 1966 */ |
| 1967 |
| 1968 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); |
| 1969 |
| 1970 const char* branch[] = {"", "test1"}; |
| 1971 const ProfileNode* itest_node = |
| 1972 GetSimpleBranch(profile, branch, arraysize(branch)); |
| 1973 const std::vector<i::DeoptInfo>& deopt_infos = itest_node->deopt_infos(); |
| 1974 CHECK_EQ(1, deopt_infos.size()); |
| 1975 |
| 1976 const i::DeoptInfo& info0 = deopt_infos[0]; |
| 1977 CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber), info0.deopt_reason); |
| 1978 CHECK_EQ(3, info0.stack.size()); |
| 1979 CHECK_EQ(inlined_script_id, info0.stack[0].script_id); |
| 1980 CHECK_EQ(offset(inlined_source, "left /"), info0.stack[0].position); |
| 1981 CHECK_EQ(script_id, info0.stack[1].script_id); |
| 1982 CHECK_EQ(offset(source, "opt_function(left,"), info0.stack[1].position); |
| 1983 CHECK_EQ(offset(source, "test2(left, right);"), info0.stack[2].position); |
| 1984 |
| 1985 iprofiler->DeleteProfile(iprofile); |
| 1986 } |
| 1987 |
| 1988 |
| 1989 // deopt in untracked function |
| 1990 TEST(DeoptUntrackedFunction) { |
| 1991 if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return; |
| 1992 i::FLAG_allow_natives_syntax = true; |
| 1993 v8::HandleScope scope(CcTest::isolate()); |
| 1994 v8::Local<v8::Context> env = CcTest::NewContext(PROFILER_EXTENSION); |
| 1995 v8::Context::Scope context_scope(env); |
| 1996 v8::Isolate* isolate = env->GetIsolate(); |
| 1997 v8::CpuProfiler* profiler = isolate->GetCpuProfiler(); |
| 1998 i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler); |
| 1999 |
| 2000 // 0.........1.........2.........3.........4.........5.........6.........7 |
| 2001 const char* source = |
| 2002 "function test(left, right) { return opt_function(left, right); }\n" |
| 2003 "\n" |
| 2004 "test(10, 10);\n" |
| 2005 "\n" |
| 2006 "%OptimizeFunctionOnNextCall(test)\n" |
| 2007 "\n" |
| 2008 "test(10, 10);\n" |
| 2009 "\n" |
| 2010 "startProfiling();\n" // profiler started after compilation. |
| 2011 "\n" |
| 2012 "test(undefined, 10);\n" |
| 2013 "\n" |
| 2014 "stopProfiling();\n" |
| 2015 "\n"; |
| 2016 |
| 2017 v8::Handle<v8::Script> inlined_script = v8_compile(inlined_source); |
| 2018 inlined_script->Run(); |
| 2019 |
| 2020 v8::Handle<v8::Script> script = v8_compile(source); |
| 2021 script->Run(); |
| 2022 |
| 2023 i::CpuProfile* iprofile = iprofiler->GetProfile(0); |
| 2024 iprofile->Print(); |
| 2025 v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile); |
| 2026 |
| 2027 const char* branch[] = {"", "test"}; |
| 2028 const ProfileNode* itest_node = |
| 2029 GetSimpleBranch(profile, branch, arraysize(branch)); |
| 2030 CHECK_EQ(0, itest_node->deopt_infos().size()); |
| 2031 |
| 2032 iprofiler->DeleteProfile(iprofile); |
| 2033 } |
OLD | NEW |