| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 "vm/profiler_service.h" | 5 #include "vm/profiler_service.h" |
| 6 | 6 |
| 7 #include "vm/growable_array.h" | 7 #include "vm/growable_array.h" |
| 8 #include "vm/native_symbol.h" | 8 #include "vm/native_symbol.h" |
| 9 #include "vm/object.h" | 9 #include "vm/object.h" |
| 10 #include "vm/os.h" | 10 #include "vm/os.h" |
| (...skipping 1057 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1068 | 1068 |
| 1069 void SanitizeMinMaxTimes() { | 1069 void SanitizeMinMaxTimes() { |
| 1070 if ((profile_->min_time_ == kMaxInt64) && (profile_->max_time_ == 0)) { | 1070 if ((profile_->min_time_ == kMaxInt64) && (profile_->max_time_ == 0)) { |
| 1071 profile_->min_time_ = 0; | 1071 profile_->min_time_ = 0; |
| 1072 profile_->max_time_ = 0; | 1072 profile_->max_time_ = 0; |
| 1073 } | 1073 } |
| 1074 } | 1074 } |
| 1075 | 1075 |
| 1076 void BuildCodeTable() { | 1076 void BuildCodeTable() { |
| 1077 ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler); | 1077 ScopeTimer sw("ProfileBuilder::BuildCodeTable", FLAG_trace_profiler); |
| 1078 |
| 1079 Isolate* isolate = thread_->isolate(); |
| 1080 ASSERT(isolate != NULL); |
| 1081 |
| 1082 // Build the live code table eagerly by populating it with code objects |
| 1083 // from the processed sample buffer. |
| 1084 const CodeLookupTable& code_lookup_table = samples_->code_lookup_table(); |
| 1085 for (intptr_t i = 0; i < code_lookup_table.length(); i++) { |
| 1086 const CodeDescriptor* descriptor = code_lookup_table.At(i); |
| 1087 ASSERT(descriptor != NULL); |
| 1088 const Code& code = Code::Handle(descriptor->code()); |
| 1089 ASSERT(!code.IsNull()); |
| 1090 RegisterLiveProfileCode( |
| 1091 new ProfileCode(ProfileCode::kDartCode, |
| 1092 code.EntryPoint(), |
| 1093 code.EntryPoint() + code.Size(), |
| 1094 code.compile_timestamp(), |
| 1095 code)); |
| 1096 } |
| 1097 |
| 1098 // Iterate over samples. |
| 1078 for (intptr_t sample_index = 0; | 1099 for (intptr_t sample_index = 0; |
| 1079 sample_index < samples_->length(); | 1100 sample_index < samples_->length(); |
| 1080 sample_index++) { | 1101 sample_index++) { |
| 1081 ProcessedSample* sample = samples_->At(sample_index); | 1102 ProcessedSample* sample = samples_->At(sample_index); |
| 1082 const int64_t timestamp = sample->timestamp(); | 1103 const int64_t timestamp = sample->timestamp(); |
| 1083 | 1104 |
| 1084 // This is our first pass over the sample buffer, use this as an | 1105 // This is our first pass over the sample buffer, use this as an |
| 1085 // opportunity to determine the min and max time ranges of this profile. | 1106 // opportunity to determine the min and max time ranges of this profile. |
| 1086 UpdateMinMaxTimes(timestamp); | 1107 UpdateMinMaxTimes(timestamp); |
| 1087 | 1108 |
| 1088 // Make sure VM tag exists. | 1109 // Make sure VM tag exists. |
| 1089 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { | 1110 if (VMTag::IsNativeEntryTag(sample->vm_tag())) { |
| 1090 RegisterProfileCodeTag(VMTag::kNativeTagId); | 1111 RegisterProfileCodeTag(VMTag::kNativeTagId); |
| 1091 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { | 1112 } else if (VMTag::IsRuntimeEntryTag(sample->vm_tag())) { |
| 1092 RegisterProfileCodeTag(VMTag::kRuntimeTagId); | 1113 RegisterProfileCodeTag(VMTag::kRuntimeTagId); |
| 1093 } | 1114 } |
| 1094 RegisterProfileCodeTag(sample->vm_tag()); | 1115 RegisterProfileCodeTag(sample->vm_tag()); |
| 1095 // Make sure user tag exists. | 1116 // Make sure user tag exists. |
| 1096 RegisterProfileCodeTag(sample->user_tag()); | 1117 RegisterProfileCodeTag(sample->user_tag()); |
| 1097 | 1118 |
| 1098 // Make sure that a ProfileCode objects exist for all pcs in the sample | 1119 // Make sure that a ProfileCode objects exist for all pcs in the sample |
| 1099 // and tick each one. | 1120 // and tick each one. |
| 1100 for (intptr_t frame_index = 0; | 1121 for (intptr_t frame_index = 0; |
| 1101 frame_index < sample->length(); | 1122 frame_index < sample->length(); |
| 1102 frame_index++) { | 1123 frame_index++) { |
| 1103 const uword pc = sample->At(frame_index); | 1124 const uword pc = sample->At(frame_index); |
| 1104 ASSERT(pc != 0); | 1125 ASSERT(pc != 0); |
| 1105 ProfileCode* code = RegisterProfileCode(pc, timestamp); | 1126 ProfileCode* code = FindOrRegisterProfileCode(pc, timestamp); |
| 1106 ASSERT(code != NULL); | 1127 ASSERT(code != NULL); |
| 1107 code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index); | 1128 code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index); |
| 1108 } | 1129 } |
| 1109 } | 1130 } |
| 1110 SanitizeMinMaxTimes(); | 1131 SanitizeMinMaxTimes(); |
| 1111 } | 1132 } |
| 1112 | 1133 |
| 1113 void FinalizeCodeIndexes() { | 1134 void FinalizeCodeIndexes() { |
| 1114 ScopeTimer sw("ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler); | 1135 ScopeTimer sw("ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler); |
| 1115 ProfileCodeTable* live_table = profile_->live_code_; | 1136 ProfileCodeTable* live_table = profile_->live_code_; |
| (...skipping 714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1830 | 1851 |
| 1831 ProfileCode* CreateProfileCodeReused(uword pc) { | 1852 ProfileCode* CreateProfileCodeReused(uword pc) { |
| 1832 ProfileCode* code = new ProfileCode(ProfileCode::kReusedCode, | 1853 ProfileCode* code = new ProfileCode(ProfileCode::kReusedCode, |
| 1833 pc, | 1854 pc, |
| 1834 pc + 1, | 1855 pc + 1, |
| 1835 0, | 1856 0, |
| 1836 null_code_); | 1857 null_code_); |
| 1837 return code; | 1858 return code; |
| 1838 } | 1859 } |
| 1839 | 1860 |
| 1840 ProfileCode* CreateProfileCode(uword pc) { | 1861 bool IsPCInDartHeap(uword pc) { |
| 1841 const intptr_t kDartCodeAlignment = OS::PreferredCodeAlignment(); | 1862 return vm_isolate_->heap()->CodeContains(pc) || |
| 1842 const intptr_t kDartCodeAlignmentMask = ~(kDartCodeAlignment - 1); | 1863 thread_->isolate()->heap()->CodeContains(pc); |
| 1843 Code& code = Code::Handle(thread_->zone()); | 1864 } |
| 1844 | 1865 |
| 1845 // Check current isolate for pc. | 1866 |
| 1846 if (thread_->isolate()->heap()->CodeContains(pc)) { | 1867 ProfileCode* FindOrRegisterNativeProfileCode(uword pc) { |
| 1847 code ^= Code::LookupCode(pc); | 1868 // Check if |pc| is already known in the live code table. |
| 1848 if (!code.IsNull()) { | 1869 ProfileCodeTable* live_table = profile_->live_code_; |
| 1849 deoptimized_code_->Add(code); | 1870 ProfileCode* profile_code = live_table->FindCodeForPC(pc); |
| 1850 return new ProfileCode(ProfileCode::kDartCode, | 1871 if (profile_code != NULL) { |
| 1851 code.EntryPoint(), | 1872 return profile_code; |
| 1852 code.EntryPoint() + code.Size(), | |
| 1853 code.compile_timestamp(), | |
| 1854 code); | |
| 1855 } | |
| 1856 return new ProfileCode(ProfileCode::kCollectedCode, | |
| 1857 pc, | |
| 1858 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment, | |
| 1859 0, | |
| 1860 code); | |
| 1861 } | 1873 } |
| 1862 | 1874 |
| 1863 // Check VM isolate for pc. | 1875 // We haven't seen this pc yet. |
| 1864 if (vm_isolate_->heap()->CodeContains(pc)) { | 1876 Code& code = Code::Handle(thread_->zone()); |
| 1865 code ^= Code::LookupCodeInVmIsolate(pc); | |
| 1866 if (!code.IsNull()) { | |
| 1867 return new ProfileCode(ProfileCode::kDartCode, | |
| 1868 code.EntryPoint(), | |
| 1869 code.EntryPoint() + code.Size(), | |
| 1870 code.compile_timestamp(), | |
| 1871 code); | |
| 1872 } | |
| 1873 // Precompiled instructions are in the VM isolate, but the code (except | |
| 1874 // stubs) is in the current isolate. | |
| 1875 code ^= Code::LookupCode(pc); | |
| 1876 if (!code.IsNull()) { | |
| 1877 return new ProfileCode(ProfileCode::kDartCode, | |
| 1878 code.EntryPoint(), | |
| 1879 code.EntryPoint() + code.Size(), | |
| 1880 code.compile_timestamp(), | |
| 1881 code); | |
| 1882 } | |
| 1883 return new ProfileCode(ProfileCode::kCollectedCode, | |
| 1884 pc, | |
| 1885 (pc & kDartCodeAlignmentMask) + kDartCodeAlignment, | |
| 1886 0, | |
| 1887 code); | |
| 1888 } | |
| 1889 | 1877 |
| 1890 // Check NativeSymbolResolver for pc. | 1878 // Check NativeSymbolResolver for pc. |
| 1891 uintptr_t native_start = 0; | 1879 uintptr_t native_start = 0; |
| 1892 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, | 1880 char* native_name = NativeSymbolResolver::LookupSymbolName(pc, |
| 1893 &native_start); | 1881 &native_start); |
| 1894 if (native_name == NULL) { | 1882 if (native_name == NULL) { |
| 1895 // No native name found. | 1883 // Failed to find a native symbol for pc. |
| 1896 return new ProfileCode(ProfileCode::kNativeCode, | 1884 native_start = pc; |
| 1897 pc, | |
| 1898 pc + 1, | |
| 1899 0, | |
| 1900 code); | |
| 1901 } | 1885 } |
| 1902 | 1886 |
| 1903 #if defined(HOST_ARCH_ARM) | 1887 #if defined(HOST_ARCH_ARM) |
| 1904 // The symbol for a Thumb function will be xxx1, but we may have samples | 1888 // The symbol for a Thumb function will be xxx1, but we may have samples |
| 1905 // at function entry which will have pc xxx0. | 1889 // at function entry which will have pc xxx0. |
| 1906 native_start &= ~1; | 1890 native_start &= ~1; |
| 1907 #endif | 1891 #endif |
| 1908 | 1892 |
| 1909 ASSERT(pc >= native_start); | 1893 ASSERT(pc >= native_start); |
| 1910 ProfileCode* profile_code = | 1894 profile_code = new ProfileCode(ProfileCode::kNativeCode, |
| 1911 new ProfileCode(ProfileCode::kNativeCode, | 1895 native_start, |
| 1912 native_start, | 1896 pc + 1, |
| 1913 pc + 1, | 1897 0, |
| 1914 0, | 1898 code); |
| 1915 code); | 1899 if (native_name != NULL) { |
| 1916 profile_code->SetName(native_name); | 1900 profile_code->SetName(native_name); |
| 1917 NativeSymbolResolver::FreeSymbolName(native_name); | 1901 NativeSymbolResolver::FreeSymbolName(native_name); |
| 1902 } |
| 1903 |
| 1904 RegisterLiveProfileCode(profile_code); |
| 1918 return profile_code; | 1905 return profile_code; |
| 1919 } | 1906 } |
| 1920 | 1907 |
| 1921 ProfileCode* RegisterProfileCode(uword pc, int64_t timestamp) { | 1908 void RegisterLiveProfileCode(ProfileCode* code) { |
| 1922 ProfileCodeTable* live_table = profile_->live_code_; | 1909 ProfileCodeTable* live_table = profile_->live_code_; |
| 1910 intptr_t index = live_table->InsertCode(code); |
| 1911 ASSERT(index >= 0); |
| 1912 } |
| 1913 |
| 1914 ProfileCode* FindOrRegisterDeadProfileCode(uword pc) { |
| 1923 ProfileCodeTable* dead_table = profile_->dead_code_; | 1915 ProfileCodeTable* dead_table = profile_->dead_code_; |
| 1924 | 1916 |
| 1925 ProfileCode* code = live_table->FindCodeForPC(pc); | 1917 ProfileCode* code = dead_table->FindCodeForPC(pc); |
| 1926 if (code == NULL) { | |
| 1927 // Code not found. | |
| 1928 intptr_t index = live_table->InsertCode(CreateProfileCode(pc)); | |
| 1929 ASSERT(index >= 0); | |
| 1930 code = live_table->At(index); | |
| 1931 if (code->compile_timestamp() <= timestamp) { | |
| 1932 // Code was compiled before sample was taken. | |
| 1933 return code; | |
| 1934 } | |
| 1935 // Code was compiled after the sample was taken. Insert code object into | |
| 1936 // the dead code table. | |
| 1937 index = dead_table->InsertCode(CreateProfileCodeReused(pc)); | |
| 1938 ASSERT(index >= 0); | |
| 1939 return dead_table->At(index); | |
| 1940 } | |
| 1941 // Existing code found. | |
| 1942 if (code->compile_timestamp() <= timestamp) { | |
| 1943 // Code was compiled before sample was taken. | |
| 1944 return code; | |
| 1945 } | |
| 1946 // Code was compiled after the sample was taken. Check if we have an entry | |
| 1947 // in the dead code table. | |
| 1948 code = dead_table->FindCodeForPC(pc); | |
| 1949 if (code != NULL) { | 1918 if (code != NULL) { |
| 1950 return code; | 1919 return code; |
| 1951 } | 1920 } |
| 1921 |
| 1952 // Create a new dead code entry. | 1922 // Create a new dead code entry. |
| 1953 intptr_t index = dead_table->InsertCode(CreateProfileCodeReused(pc)); | 1923 intptr_t index = dead_table->InsertCode(CreateProfileCodeReused(pc)); |
| 1954 ASSERT(index >= 0); | 1924 ASSERT(index >= 0); |
| 1955 return dead_table->At(index); | 1925 return dead_table->At(index); |
| 1956 } | 1926 } |
| 1957 | 1927 |
| 1928 ProfileCode* FindOrRegisterProfileCode(uword pc, int64_t timestamp) { |
| 1929 ProfileCodeTable* live_table = profile_->live_code_; |
| 1930 ProfileCode* code = live_table->FindCodeForPC(pc); |
| 1931 if ((code != NULL) && (code->compile_timestamp() <= timestamp)) { |
| 1932 // Code was compiled before sample was taken. |
| 1933 return code; |
| 1934 } |
| 1935 if ((code == NULL) && !IsPCInDartHeap(pc)) { |
| 1936 // Not a PC from Dart code. Check with native code. |
| 1937 return FindOrRegisterNativeProfileCode(pc); |
| 1938 } |
| 1939 // We either didn't find the code or it was compiled after the sample. |
| 1940 return FindOrRegisterDeadProfileCode(pc); |
| 1941 } |
| 1942 |
| 1958 Profile::TagOrder tag_order() const { | 1943 Profile::TagOrder tag_order() const { |
| 1959 return tag_order_; | 1944 return tag_order_; |
| 1960 } | 1945 } |
| 1961 | 1946 |
| 1962 bool vm_tags_emitted() const { | 1947 bool vm_tags_emitted() const { |
| 1963 return (tag_order_ == Profile::kUserVM) || | 1948 return (tag_order_ == Profile::kUserVM) || |
| 1964 (tag_order_ == Profile::kVMUser) || | 1949 (tag_order_ == Profile::kVMUser) || |
| 1965 (tag_order_ == Profile::kVM); | 1950 (tag_order_ == Profile::kVM); |
| 1966 } | 1951 } |
| 1967 | 1952 |
| (...skipping 324 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2292 Isolate* isolate = thread->isolate(); | 2277 Isolate* isolate = thread->isolate(); |
| 2293 | 2278 |
| 2294 // Disable thread interrupts while processing the buffer. | 2279 // Disable thread interrupts while processing the buffer. |
| 2295 DisableThreadInterruptsScope dtis(thread); | 2280 DisableThreadInterruptsScope dtis(thread); |
| 2296 | 2281 |
| 2297 ClearProfileVisitor clear_profile(isolate); | 2282 ClearProfileVisitor clear_profile(isolate); |
| 2298 sample_buffer->VisitSamples(&clear_profile); | 2283 sample_buffer->VisitSamples(&clear_profile); |
| 2299 } | 2284 } |
| 2300 | 2285 |
| 2301 } // namespace dart | 2286 } // namespace dart |
| OLD | NEW |