| 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/address_sanitizer.h" | 5 #include "platform/address_sanitizer.h" |
| 6 #include "platform/memory_sanitizer.h" | 6 #include "platform/memory_sanitizer.h" |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 | 8 |
| 9 #include "vm/allocation.h" | 9 #include "vm/allocation.h" |
| 10 #include "vm/atomic.h" | 10 #include "vm/atomic.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 #if defined(USING_SIMULATOR) | 50 #if defined(USING_SIMULATOR) |
| 51 DEFINE_FLAG(bool, profile_vm, true, "Always collect native stack traces."); | 51 DEFINE_FLAG(bool, profile_vm, true, "Always collect native stack traces."); |
| 52 #else | 52 #else |
| 53 DEFINE_FLAG(bool, profile_vm, false, "Always collect native stack traces."); | 53 DEFINE_FLAG(bool, profile_vm, false, "Always collect native stack traces."); |
| 54 #endif | 54 #endif |
| 55 | 55 |
| 56 #ifndef PRODUCT | 56 #ifndef PRODUCT |
| 57 | 57 |
| 58 bool Profiler::initialized_ = false; | 58 bool Profiler::initialized_ = false; |
| 59 SampleBuffer* Profiler::sample_buffer_ = NULL; | 59 SampleBuffer* Profiler::sample_buffer_ = NULL; |
| 60 AllocationSampleBuffer* Profiler::allocation_sample_buffer_ = NULL; |
| 60 ProfilerCounters Profiler::counters_; | 61 ProfilerCounters Profiler::counters_; |
| 61 | 62 |
| 62 void Profiler::InitOnce() { | 63 void Profiler::InitOnce() { |
| 63 // Place some sane restrictions on user controlled flags. | 64 // Place some sane restrictions on user controlled flags. |
| 64 SetSamplePeriod(FLAG_profile_period); | 65 SetSamplePeriod(FLAG_profile_period); |
| 65 SetSampleDepth(FLAG_max_profile_depth); | 66 SetSampleDepth(FLAG_max_profile_depth); |
| 66 Sample::InitOnce(); | 67 Sample::InitOnce(); |
| 67 if (!FLAG_profiler) { | 68 if (!FLAG_profiler) { |
| 68 return; | 69 return; |
| 69 } | 70 } |
| 70 ASSERT(!initialized_); | 71 ASSERT(!initialized_); |
| 71 sample_buffer_ = new SampleBuffer(); | 72 sample_buffer_ = new SampleBuffer(); |
| 73 Profiler::InitAllocationSampleBuffer(); |
| 72 // Zero counters. | 74 // Zero counters. |
| 73 memset(&counters_, 0, sizeof(counters_)); | 75 memset(&counters_, 0, sizeof(counters_)); |
| 74 NativeSymbolResolver::InitOnce(); | 76 NativeSymbolResolver::InitOnce(); |
| 75 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); | 77 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); |
| 76 ThreadInterrupter::Startup(); | 78 ThreadInterrupter::Startup(); |
| 77 initialized_ = true; | 79 initialized_ = true; |
| 78 } | 80 } |
| 79 | 81 |
| 80 | 82 |
| 83 void Profiler::InitAllocationSampleBuffer() { |
| 84 if (FLAG_profiler_native_memory && |
| 85 (Profiler::allocation_sample_buffer_ == NULL)) { |
| 86 Profiler::allocation_sample_buffer_ = new AllocationSampleBuffer(); |
| 87 } |
| 88 } |
| 89 |
| 90 |
| 81 void Profiler::Shutdown() { | 91 void Profiler::Shutdown() { |
| 82 if (!FLAG_profiler) { | 92 if (!FLAG_profiler) { |
| 83 return; | 93 return; |
| 84 } | 94 } |
| 85 ASSERT(initialized_); | 95 ASSERT(initialized_); |
| 86 ThreadInterrupter::Shutdown(); | 96 ThreadInterrupter::Shutdown(); |
| 87 NativeSymbolResolver::ShutdownOnce(); | 97 NativeSymbolResolver::ShutdownOnce(); |
| 88 } | 98 } |
| 89 | 99 |
| 90 | 100 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 cursor_ = 0; | 153 cursor_ = 0; |
| 144 | 154 |
| 145 if (FLAG_trace_profiler) { | 155 if (FLAG_trace_profiler) { |
| 146 OS::Print("Profiler holds %" Pd " samples\n", capacity); | 156 OS::Print("Profiler holds %" Pd " samples\n", capacity); |
| 147 OS::Print("Profiler sample is %" Pd " bytes\n", Sample::instance_size()); | 157 OS::Print("Profiler sample is %" Pd " bytes\n", Sample::instance_size()); |
| 148 OS::Print("Profiler memory usage = %" Pd " bytes\n", size); | 158 OS::Print("Profiler memory usage = %" Pd " bytes\n", size); |
| 149 } | 159 } |
| 150 } | 160 } |
| 151 | 161 |
| 152 | 162 |
| 163 AllocationSampleBuffer::AllocationSampleBuffer(intptr_t capacity) |
| 164 : SampleBuffer(capacity), mutex_(new Mutex()) {} |
| 165 |
| 166 |
| 153 SampleBuffer::~SampleBuffer() { | 167 SampleBuffer::~SampleBuffer() { |
| 154 delete memory_; | 168 delete memory_; |
| 155 } | 169 } |
| 156 | 170 |
| 157 | 171 |
| 172 AllocationSampleBuffer::~AllocationSampleBuffer() { |
| 173 delete mutex_; |
| 174 } |
| 175 |
| 176 |
| 158 Sample* SampleBuffer::At(intptr_t idx) const { | 177 Sample* SampleBuffer::At(intptr_t idx) const { |
| 159 ASSERT(idx >= 0); | 178 ASSERT(idx >= 0); |
| 160 ASSERT(idx < capacity_); | 179 ASSERT(idx < capacity_); |
| 161 intptr_t offset = idx * Sample::instance_size(); | 180 intptr_t offset = idx * Sample::instance_size(); |
| 162 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); | 181 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); |
| 163 return reinterpret_cast<Sample*>(samples + offset); | 182 return reinterpret_cast<Sample*>(samples + offset); |
| 164 } | 183 } |
| 165 | 184 |
| 166 | 185 |
| 167 intptr_t SampleBuffer::ReserveSampleSlot() { | 186 intptr_t SampleBuffer::ReserveSampleSlot() { |
| 168 ASSERT(samples_ != NULL); | 187 ASSERT(samples_ != NULL); |
| 169 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 188 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); |
| 170 // Map back into sample buffer range. | 189 // Map back into sample buffer range. |
| 171 cursor = cursor % capacity_; | 190 cursor = cursor % capacity_; |
| 172 return cursor; | 191 return cursor; |
| 173 } | 192 } |
| 174 | 193 |
| 194 |
| 175 Sample* SampleBuffer::ReserveSample() { | 195 Sample* SampleBuffer::ReserveSample() { |
| 176 return At(ReserveSampleSlot()); | 196 return At(ReserveSampleSlot()); |
| 177 } | 197 } |
| 178 | 198 |
| 179 | 199 |
| 180 Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) { | 200 Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) { |
| 181 ASSERT(previous != NULL); | 201 ASSERT(previous != NULL); |
| 182 intptr_t next_index = ReserveSampleSlot(); | 202 intptr_t next_index = ReserveSampleSlot(); |
| 183 Sample* next = At(next_index); | 203 Sample* next = At(next_index); |
| 184 next->Init(previous->port(), previous->timestamp(), previous->tid()); | 204 next->Init(previous->port(), previous->timestamp(), previous->tid()); |
| 185 next->set_head_sample(false); | 205 next->set_head_sample(false); |
| 186 // Mark that previous continues at next. | 206 // Mark that previous continues at next. |
| 187 previous->SetContinuationIndex(next_index); | 207 previous->SetContinuationIndex(next_index); |
| 188 return next; | 208 return next; |
| 189 } | 209 } |
| 190 | 210 |
| 191 | 211 |
| 212 void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) { |
| 213 MutexLocker ml(mutex_); |
| 214 while (sample != NULL) { |
| 215 intptr_t continuation_index = -1; |
| 216 if (sample->is_continuation_sample()) { |
| 217 continuation_index = sample->continuation_index(); |
| 218 } |
| 219 sample->Clear(); |
| 220 sample->set_next_free(free_sample_list_); |
| 221 free_sample_list_ = sample; |
| 222 |
| 223 if (continuation_index != -1) { |
| 224 sample = At(continuation_index); |
| 225 } else { |
| 226 sample = NULL; |
| 227 } |
| 228 } |
| 229 } |
| 230 |
| 231 |
| 232 intptr_t AllocationSampleBuffer::ReserveSampleSlotLocked() { |
| 233 if (free_sample_list_ != NULL) { |
| 234 Sample* free_sample = free_sample_list_; |
| 235 free_sample_list_ = free_sample->next_free(); |
| 236 free_sample->set_next_free(NULL); |
| 237 uint8_t* samples_array_ptr = reinterpret_cast<uint8_t*>(samples_); |
| 238 uint8_t* free_sample_ptr = reinterpret_cast<uint8_t*>(free_sample); |
| 239 return static_cast<intptr_t>((free_sample_ptr - samples_array_ptr) / |
| 240 Sample::instance_size()); |
| 241 } else if (cursor_ < static_cast<uintptr_t>(capacity_ - 1)) { |
| 242 return cursor_++; |
| 243 } else { |
| 244 return -1; |
| 245 } |
| 246 } |
| 247 |
| 248 |
| 249 Sample* AllocationSampleBuffer::ReserveSampleAndLink(Sample* previous) { |
| 250 MutexLocker ml(mutex_); |
| 251 ASSERT(previous != NULL); |
| 252 intptr_t next_index = ReserveSampleSlotLocked(); |
| 253 if (next_index < 0) { |
| 254 // Could not find a free sample. |
| 255 return NULL; |
| 256 } |
| 257 Sample* next = At(next_index); |
| 258 next->Init(previous->port(), previous->timestamp(), previous->tid()); |
| 259 next->set_native_allocation_address(previous->native_allocation_address()); |
| 260 next->set_native_allocation_size_bytes( |
| 261 previous->native_allocation_size_bytes()); |
| 262 next->set_head_sample(false); |
| 263 // Mark that previous continues at next. |
| 264 previous->SetContinuationIndex(next_index); |
| 265 return next; |
| 266 } |
| 267 |
| 268 |
| 269 Sample* AllocationSampleBuffer::ReserveSample() { |
| 270 MutexLocker ml(mutex_); |
| 271 intptr_t index = ReserveSampleSlotLocked(); |
| 272 if (index < 0) { |
| 273 return NULL; |
| 274 } |
| 275 return At(index); |
| 276 } |
| 277 |
| 278 |
| 192 // Attempts to find the true return address when a Dart frame is being setup | 279 // Attempts to find the true return address when a Dart frame is being setup |
| 193 // or torn down. | 280 // or torn down. |
| 194 // NOTE: Architecture specific implementations below. | 281 // NOTE: Architecture specific implementations below. |
| 195 class ReturnAddressLocator : public ValueObject { | 282 class ReturnAddressLocator : public ValueObject { |
| 196 public: | 283 public: |
| 197 ReturnAddressLocator(Sample* sample, const Code& code) | 284 ReturnAddressLocator(Sample* sample, const Code& code) |
| 198 : stack_buffer_(sample->GetStackBuffer()), | 285 : stack_buffer_(sample->GetStackBuffer()), |
| 199 pc_(sample->pc()), | 286 pc_(sample->pc()), |
| 200 code_(Code::ZoneHandle(code.raw())) { | 287 code_(Code::ZoneHandle(code.raw())) { |
| 201 ASSERT(!code_.IsNull()); | 288 ASSERT(!code_.IsNull()); |
| (...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 949 #endif | 1036 #endif |
| 950 sample->set_vm_tag(vm_tag); | 1037 sample->set_vm_tag(vm_tag); |
| 951 sample->set_user_tag(isolate->user_tag()); | 1038 sample->set_user_tag(isolate->user_tag()); |
| 952 sample->set_thread_task(thread->task_kind()); | 1039 sample->set_thread_task(thread->task_kind()); |
| 953 return sample; | 1040 return sample; |
| 954 } | 1041 } |
| 955 | 1042 |
| 956 | 1043 |
| 957 static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) { | 1044 static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) { |
| 958 Sample* sample = sample_buffer->ReserveSample(); | 1045 Sample* sample = sample_buffer->ReserveSample(); |
| 1046 if (sample == NULL) { |
| 1047 return NULL; |
| 1048 } |
| 959 sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid); | 1049 sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid); |
| 960 sample->set_is_native_allocation_sample(true); | |
| 961 Thread* thread = Thread::Current(); | 1050 Thread* thread = Thread::Current(); |
| 962 | 1051 |
| 963 // Note: setting thread task in order to be consistent with other samples. The | 1052 // Note: setting thread task in order to be consistent with other samples. The |
| 964 // task kind is not used by NativeAllocationSampleFilter for filtering | 1053 // task kind is not used by NativeAllocationSampleFilter for filtering |
| 965 // purposes as some samples may be collected when no thread exists. | 1054 // purposes as some samples may be collected when no thread exists. |
| 966 if (thread != NULL) { | 1055 if (thread != NULL) { |
| 967 sample->set_thread_task(thread->task_kind()); | 1056 sample->set_thread_task(thread->task_kind()); |
| 968 } | 1057 } |
| 969 return sample; | 1058 return sample; |
| 970 } | 1059 } |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1109 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); | 1198 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); |
| 1110 sample->SetAllocationCid(cid); | 1199 sample->SetAllocationCid(cid); |
| 1111 sample->SetAt(0, pc); | 1200 sample->SetAt(0, pc); |
| 1112 } | 1201 } |
| 1113 } | 1202 } |
| 1114 | 1203 |
| 1115 | 1204 |
| 1116 Sample* Profiler::SampleNativeAllocation(intptr_t skip_count, | 1205 Sample* Profiler::SampleNativeAllocation(intptr_t skip_count, |
| 1117 uword address, | 1206 uword address, |
| 1118 uintptr_t allocation_size) { | 1207 uintptr_t allocation_size) { |
| 1119 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 1208 AllocationSampleBuffer* sample_buffer = Profiler::allocation_sample_buffer(); |
| 1120 if (sample_buffer == NULL) { | 1209 if (sample_buffer == NULL) { |
| 1121 return NULL; | 1210 return NULL; |
| 1122 } | 1211 } |
| 1123 | 1212 |
| 1124 uintptr_t sp = Thread::GetCurrentStackPointer(); | 1213 uintptr_t sp = Thread::GetCurrentStackPointer(); |
| 1125 uintptr_t fp = 0; | 1214 uintptr_t fp = 0; |
| 1126 uintptr_t pc = OS::GetProgramCounter(); | 1215 uintptr_t pc = OS::GetProgramCounter(); |
| 1127 | 1216 |
| 1128 COPY_FP_REGISTER(fp); | 1217 COPY_FP_REGISTER(fp); |
| 1129 | 1218 |
| 1130 uword stack_lower = 0; | 1219 uword stack_lower = 0; |
| 1131 uword stack_upper = 0; | 1220 uword stack_upper = 0; |
| 1132 if (!InitialRegisterCheck(pc, fp, sp)) { | 1221 if (!InitialRegisterCheck(pc, fp, sp)) { |
| 1133 AtomicOperations::IncrementInt64By( | 1222 AtomicOperations::IncrementInt64By( |
| 1134 &counters_.failure_native_allocation_sample, 1); | 1223 &counters_.failure_native_allocation_sample, 1); |
| 1135 return NULL; | 1224 return NULL; |
| 1136 } | 1225 } |
| 1137 | 1226 |
| 1138 if (!(OSThread::GetCurrentStackBounds(&stack_lower, &stack_upper) && | 1227 if (!(OSThread::GetCurrentStackBounds(&stack_lower, &stack_upper) && |
| 1139 ValidateThreadStackBounds(fp, sp, stack_lower, stack_upper))) { | 1228 ValidateThreadStackBounds(fp, sp, stack_lower, stack_upper))) { |
| 1140 // Could not get stack boundary. | 1229 // Could not get stack boundary. |
| 1141 AtomicOperations::IncrementInt64By( | 1230 AtomicOperations::IncrementInt64By( |
| 1142 &counters_.failure_native_allocation_sample, 1); | 1231 &counters_.failure_native_allocation_sample, 1); |
| 1143 return NULL; | 1232 return NULL; |
| 1144 } | 1233 } |
| 1145 | 1234 |
| 1146 OSThread* os_thread = OSThread::Current(); | 1235 OSThread* os_thread = OSThread::Current(); |
| 1147 Sample* sample = SetupSampleNative(sample_buffer, os_thread->trace_id()); | 1236 Sample* sample = SetupSampleNative(sample_buffer, os_thread->trace_id()); |
| 1237 if (sample == NULL) { |
| 1238 OS::PrintErr( |
| 1239 "Native memory profile sample buffer is full because there are more " |
| 1240 "than %" Pd |
| 1241 " outstanding allocations. Not recording allocation " |
| 1242 "0x%" Px " with size: %" Pu " bytes.\n", |
| 1243 sample_buffer->capacity(), address, allocation_size); |
| 1244 return NULL; |
| 1245 } |
| 1246 |
| 1148 sample->set_native_allocation_address(address); | 1247 sample->set_native_allocation_address(address); |
| 1149 sample->set_native_allocation_size_bytes(allocation_size); | 1248 sample->set_native_allocation_size_bytes(allocation_size); |
| 1150 | 1249 |
| 1151 ProfilerNativeStackWalker native_stack_walker( | 1250 ProfilerNativeStackWalker native_stack_walker( |
| 1152 ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, | 1251 ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, |
| 1153 skip_count); | 1252 skip_count); |
| 1154 | 1253 |
| 1155 native_stack_walker.walk(); | 1254 native_stack_walker.walk(); |
| 1255 |
| 1156 return sample; | 1256 return sample; |
| 1157 } | 1257 } |
| 1158 | 1258 |
| 1159 | 1259 |
| 1160 void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) { | 1260 void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) { |
| 1161 ASSERT(thread != NULL); | 1261 ASSERT(thread != NULL); |
| 1162 OSThread* os_thread = thread->os_thread(); | 1262 OSThread* os_thread = thread->os_thread(); |
| 1163 ASSERT(os_thread != NULL); | 1263 ASSERT(os_thread != NULL); |
| 1164 Isolate* isolate = thread->isolate(); | 1264 Isolate* isolate = thread->isolate(); |
| 1165 | 1265 |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1621 | 1721 |
| 1622 | 1722 |
| 1623 ProcessedSampleBuffer::ProcessedSampleBuffer() | 1723 ProcessedSampleBuffer::ProcessedSampleBuffer() |
| 1624 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { | 1724 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { |
| 1625 ASSERT(code_lookup_table_ != NULL); | 1725 ASSERT(code_lookup_table_ != NULL); |
| 1626 } | 1726 } |
| 1627 | 1727 |
| 1628 #endif // !PRODUCT | 1728 #endif // !PRODUCT |
| 1629 | 1729 |
| 1630 } // namespace dart | 1730 } // namespace dart |
| OLD | NEW |