Chromium Code Reviews| 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); |
| 1728 v8::Context::Scope context_scope(env); | 1733 v8::Context::Scope context_scope(env); |
| (...skipping 41 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 | |
|
alph
2015/03/20 08:28:43
nit: shifted a bit
loislo
2015/03/20 08:53:12
done
| |
| 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 | |
|
alph
2015/03/20 08:28:43
ditto
loislo
2015/03/20 08:53:12
done
| |
| 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 |