| 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 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 sample_buffer_ = new SampleBuffer(); | 72 sample_buffer_ = new SampleBuffer(); |
| 73 Profiler::InitAllocationSampleBuffer(); | 73 Profiler::InitAllocationSampleBuffer(); |
| 74 // Zero counters. | 74 // Zero counters. |
| 75 memset(&counters_, 0, sizeof(counters_)); | 75 memset(&counters_, 0, sizeof(counters_)); |
| 76 NativeSymbolResolver::InitOnce(); | 76 NativeSymbolResolver::InitOnce(); |
| 77 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); | 77 ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period); |
| 78 ThreadInterrupter::Startup(); | 78 ThreadInterrupter::Startup(); |
| 79 initialized_ = true; | 79 initialized_ = true; |
| 80 } | 80 } |
| 81 | 81 |
| 82 | |
| 83 void Profiler::InitAllocationSampleBuffer() { | 82 void Profiler::InitAllocationSampleBuffer() { |
| 84 if (FLAG_profiler_native_memory && | 83 if (FLAG_profiler_native_memory && |
| 85 (Profiler::allocation_sample_buffer_ == NULL)) { | 84 (Profiler::allocation_sample_buffer_ == NULL)) { |
| 86 Profiler::allocation_sample_buffer_ = new AllocationSampleBuffer(); | 85 Profiler::allocation_sample_buffer_ = new AllocationSampleBuffer(); |
| 87 } | 86 } |
| 88 } | 87 } |
| 89 | 88 |
| 90 | |
| 91 void Profiler::Shutdown() { | 89 void Profiler::Shutdown() { |
| 92 if (!FLAG_profiler) { | 90 if (!FLAG_profiler) { |
| 93 return; | 91 return; |
| 94 } | 92 } |
| 95 ASSERT(initialized_); | 93 ASSERT(initialized_); |
| 96 ThreadInterrupter::Shutdown(); | 94 ThreadInterrupter::Shutdown(); |
| 97 NativeSymbolResolver::ShutdownOnce(); | 95 NativeSymbolResolver::ShutdownOnce(); |
| 98 } | 96 } |
| 99 | 97 |
| 100 | |
| 101 void Profiler::SetSampleDepth(intptr_t depth) { | 98 void Profiler::SetSampleDepth(intptr_t depth) { |
| 102 const int kMinimumDepth = 2; | 99 const int kMinimumDepth = 2; |
| 103 const int kMaximumDepth = 255; | 100 const int kMaximumDepth = 255; |
| 104 if (depth < kMinimumDepth) { | 101 if (depth < kMinimumDepth) { |
| 105 FLAG_max_profile_depth = kMinimumDepth; | 102 FLAG_max_profile_depth = kMinimumDepth; |
| 106 } else if (depth > kMaximumDepth) { | 103 } else if (depth > kMaximumDepth) { |
| 107 FLAG_max_profile_depth = kMaximumDepth; | 104 FLAG_max_profile_depth = kMaximumDepth; |
| 108 } else { | 105 } else { |
| 109 FLAG_max_profile_depth = depth; | 106 FLAG_max_profile_depth = depth; |
| 110 } | 107 } |
| 111 } | 108 } |
| 112 | 109 |
| 113 | |
| 114 void Profiler::SetSamplePeriod(intptr_t period) { | 110 void Profiler::SetSamplePeriod(intptr_t period) { |
| 115 const int kMinimumProfilePeriod = 50; | 111 const int kMinimumProfilePeriod = 50; |
| 116 if (period < kMinimumProfilePeriod) { | 112 if (period < kMinimumProfilePeriod) { |
| 117 FLAG_profile_period = kMinimumProfilePeriod; | 113 FLAG_profile_period = kMinimumProfilePeriod; |
| 118 } else { | 114 } else { |
| 119 FLAG_profile_period = period; | 115 FLAG_profile_period = period; |
| 120 } | 116 } |
| 121 } | 117 } |
| 122 | 118 |
| 123 | |
| 124 intptr_t Sample::pcs_length_ = 0; | 119 intptr_t Sample::pcs_length_ = 0; |
| 125 intptr_t Sample::instance_size_ = 0; | 120 intptr_t Sample::instance_size_ = 0; |
| 126 | 121 |
| 127 | |
| 128 void Sample::InitOnce() { | 122 void Sample::InitOnce() { |
| 129 pcs_length_ = kSampleSize; | 123 pcs_length_ = kSampleSize; |
| 130 instance_size_ = sizeof(Sample) + (sizeof(uword) * pcs_length_); // NOLINT. | 124 instance_size_ = sizeof(Sample) + (sizeof(uword) * pcs_length_); // NOLINT. |
| 131 } | 125 } |
| 132 | 126 |
| 133 | |
| 134 uword* Sample::GetPCArray() const { | 127 uword* Sample::GetPCArray() const { |
| 135 return reinterpret_cast<uword*>(reinterpret_cast<uintptr_t>(this) + | 128 return reinterpret_cast<uword*>(reinterpret_cast<uintptr_t>(this) + |
| 136 sizeof(*this)); | 129 sizeof(*this)); |
| 137 } | 130 } |
| 138 | 131 |
| 139 | |
| 140 SampleBuffer::SampleBuffer(intptr_t capacity) { | 132 SampleBuffer::SampleBuffer(intptr_t capacity) { |
| 141 ASSERT(Sample::instance_size() > 0); | 133 ASSERT(Sample::instance_size() > 0); |
| 142 | 134 |
| 143 const intptr_t size = Utils::RoundUp(capacity * Sample::instance_size(), | 135 const intptr_t size = Utils::RoundUp(capacity * Sample::instance_size(), |
| 144 VirtualMemory::PageSize()); | 136 VirtualMemory::PageSize()); |
| 145 const bool kNotExecutable = false; | 137 const bool kNotExecutable = false; |
| 146 memory_ = VirtualMemory::Reserve(size); | 138 memory_ = VirtualMemory::Reserve(size); |
| 147 if ((memory_ == NULL) || !memory_->Commit(kNotExecutable, "dart-profiler")) { | 139 if ((memory_ == NULL) || !memory_->Commit(kNotExecutable, "dart-profiler")) { |
| 148 OUT_OF_MEMORY(); | 140 OUT_OF_MEMORY(); |
| 149 } | 141 } |
| 150 | 142 |
| 151 samples_ = reinterpret_cast<Sample*>(memory_->address()); | 143 samples_ = reinterpret_cast<Sample*>(memory_->address()); |
| 152 capacity_ = capacity; | 144 capacity_ = capacity; |
| 153 cursor_ = 0; | 145 cursor_ = 0; |
| 154 | 146 |
| 155 if (FLAG_trace_profiler) { | 147 if (FLAG_trace_profiler) { |
| 156 OS::Print("Profiler holds %" Pd " samples\n", capacity); | 148 OS::Print("Profiler holds %" Pd " samples\n", capacity); |
| 157 OS::Print("Profiler sample is %" Pd " bytes\n", Sample::instance_size()); | 149 OS::Print("Profiler sample is %" Pd " bytes\n", Sample::instance_size()); |
| 158 OS::Print("Profiler memory usage = %" Pd " bytes\n", size); | 150 OS::Print("Profiler memory usage = %" Pd " bytes\n", size); |
| 159 } | 151 } |
| 160 } | 152 } |
| 161 | 153 |
| 162 | |
| 163 AllocationSampleBuffer::AllocationSampleBuffer(intptr_t capacity) | 154 AllocationSampleBuffer::AllocationSampleBuffer(intptr_t capacity) |
| 164 : SampleBuffer(capacity), mutex_(new Mutex()) {} | 155 : SampleBuffer(capacity), mutex_(new Mutex()) {} |
| 165 | 156 |
| 166 | |
| 167 SampleBuffer::~SampleBuffer() { | 157 SampleBuffer::~SampleBuffer() { |
| 168 delete memory_; | 158 delete memory_; |
| 169 } | 159 } |
| 170 | 160 |
| 171 | |
| 172 AllocationSampleBuffer::~AllocationSampleBuffer() { | 161 AllocationSampleBuffer::~AllocationSampleBuffer() { |
| 173 delete mutex_; | 162 delete mutex_; |
| 174 } | 163 } |
| 175 | 164 |
| 176 | |
| 177 Sample* SampleBuffer::At(intptr_t idx) const { | 165 Sample* SampleBuffer::At(intptr_t idx) const { |
| 178 ASSERT(idx >= 0); | 166 ASSERT(idx >= 0); |
| 179 ASSERT(idx < capacity_); | 167 ASSERT(idx < capacity_); |
| 180 intptr_t offset = idx * Sample::instance_size(); | 168 intptr_t offset = idx * Sample::instance_size(); |
| 181 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); | 169 uint8_t* samples = reinterpret_cast<uint8_t*>(samples_); |
| 182 return reinterpret_cast<Sample*>(samples + offset); | 170 return reinterpret_cast<Sample*>(samples + offset); |
| 183 } | 171 } |
| 184 | 172 |
| 185 | |
| 186 intptr_t SampleBuffer::ReserveSampleSlot() { | 173 intptr_t SampleBuffer::ReserveSampleSlot() { |
| 187 ASSERT(samples_ != NULL); | 174 ASSERT(samples_ != NULL); |
| 188 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); | 175 uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_); |
| 189 // Map back into sample buffer range. | 176 // Map back into sample buffer range. |
| 190 cursor = cursor % capacity_; | 177 cursor = cursor % capacity_; |
| 191 return cursor; | 178 return cursor; |
| 192 } | 179 } |
| 193 | 180 |
| 194 | |
| 195 Sample* SampleBuffer::ReserveSample() { | 181 Sample* SampleBuffer::ReserveSample() { |
| 196 return At(ReserveSampleSlot()); | 182 return At(ReserveSampleSlot()); |
| 197 } | 183 } |
| 198 | 184 |
| 199 | |
| 200 Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) { | 185 Sample* SampleBuffer::ReserveSampleAndLink(Sample* previous) { |
| 201 ASSERT(previous != NULL); | 186 ASSERT(previous != NULL); |
| 202 intptr_t next_index = ReserveSampleSlot(); | 187 intptr_t next_index = ReserveSampleSlot(); |
| 203 Sample* next = At(next_index); | 188 Sample* next = At(next_index); |
| 204 next->Init(previous->port(), previous->timestamp(), previous->tid()); | 189 next->Init(previous->port(), previous->timestamp(), previous->tid()); |
| 205 next->set_head_sample(false); | 190 next->set_head_sample(false); |
| 206 // Mark that previous continues at next. | 191 // Mark that previous continues at next. |
| 207 previous->SetContinuationIndex(next_index); | 192 previous->SetContinuationIndex(next_index); |
| 208 return next; | 193 return next; |
| 209 } | 194 } |
| 210 | 195 |
| 211 | |
| 212 void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) { | 196 void AllocationSampleBuffer::FreeAllocationSample(Sample* sample) { |
| 213 MutexLocker ml(mutex_); | 197 MutexLocker ml(mutex_); |
| 214 while (sample != NULL) { | 198 while (sample != NULL) { |
| 215 intptr_t continuation_index = -1; | 199 intptr_t continuation_index = -1; |
| 216 if (sample->is_continuation_sample()) { | 200 if (sample->is_continuation_sample()) { |
| 217 continuation_index = sample->continuation_index(); | 201 continuation_index = sample->continuation_index(); |
| 218 } | 202 } |
| 219 sample->Clear(); | 203 sample->Clear(); |
| 220 sample->set_next_free(free_sample_list_); | 204 sample->set_next_free(free_sample_list_); |
| 221 free_sample_list_ = sample; | 205 free_sample_list_ = sample; |
| 222 | 206 |
| 223 if (continuation_index != -1) { | 207 if (continuation_index != -1) { |
| 224 sample = At(continuation_index); | 208 sample = At(continuation_index); |
| 225 } else { | 209 } else { |
| 226 sample = NULL; | 210 sample = NULL; |
| 227 } | 211 } |
| 228 } | 212 } |
| 229 } | 213 } |
| 230 | 214 |
| 231 | |
| 232 intptr_t AllocationSampleBuffer::ReserveSampleSlotLocked() { | 215 intptr_t AllocationSampleBuffer::ReserveSampleSlotLocked() { |
| 233 if (free_sample_list_ != NULL) { | 216 if (free_sample_list_ != NULL) { |
| 234 Sample* free_sample = free_sample_list_; | 217 Sample* free_sample = free_sample_list_; |
| 235 free_sample_list_ = free_sample->next_free(); | 218 free_sample_list_ = free_sample->next_free(); |
| 236 free_sample->set_next_free(NULL); | 219 free_sample->set_next_free(NULL); |
| 237 uint8_t* samples_array_ptr = reinterpret_cast<uint8_t*>(samples_); | 220 uint8_t* samples_array_ptr = reinterpret_cast<uint8_t*>(samples_); |
| 238 uint8_t* free_sample_ptr = reinterpret_cast<uint8_t*>(free_sample); | 221 uint8_t* free_sample_ptr = reinterpret_cast<uint8_t*>(free_sample); |
| 239 return static_cast<intptr_t>((free_sample_ptr - samples_array_ptr) / | 222 return static_cast<intptr_t>((free_sample_ptr - samples_array_ptr) / |
| 240 Sample::instance_size()); | 223 Sample::instance_size()); |
| 241 } else if (cursor_ < static_cast<uintptr_t>(capacity_ - 1)) { | 224 } else if (cursor_ < static_cast<uintptr_t>(capacity_ - 1)) { |
| 242 return cursor_++; | 225 return cursor_++; |
| 243 } else { | 226 } else { |
| 244 return -1; | 227 return -1; |
| 245 } | 228 } |
| 246 } | 229 } |
| 247 | 230 |
| 248 | |
| 249 Sample* AllocationSampleBuffer::ReserveSampleAndLink(Sample* previous) { | 231 Sample* AllocationSampleBuffer::ReserveSampleAndLink(Sample* previous) { |
| 250 MutexLocker ml(mutex_); | 232 MutexLocker ml(mutex_); |
| 251 ASSERT(previous != NULL); | 233 ASSERT(previous != NULL); |
| 252 intptr_t next_index = ReserveSampleSlotLocked(); | 234 intptr_t next_index = ReserveSampleSlotLocked(); |
| 253 if (next_index < 0) { | 235 if (next_index < 0) { |
| 254 // Could not find a free sample. | 236 // Could not find a free sample. |
| 255 return NULL; | 237 return NULL; |
| 256 } | 238 } |
| 257 Sample* next = At(next_index); | 239 Sample* next = At(next_index); |
| 258 next->Init(previous->port(), previous->timestamp(), previous->tid()); | 240 next->Init(previous->port(), previous->timestamp(), previous->tid()); |
| 259 next->set_native_allocation_address(previous->native_allocation_address()); | 241 next->set_native_allocation_address(previous->native_allocation_address()); |
| 260 next->set_native_allocation_size_bytes( | 242 next->set_native_allocation_size_bytes( |
| 261 previous->native_allocation_size_bytes()); | 243 previous->native_allocation_size_bytes()); |
| 262 next->set_head_sample(false); | 244 next->set_head_sample(false); |
| 263 // Mark that previous continues at next. | 245 // Mark that previous continues at next. |
| 264 previous->SetContinuationIndex(next_index); | 246 previous->SetContinuationIndex(next_index); |
| 265 return next; | 247 return next; |
| 266 } | 248 } |
| 267 | 249 |
| 268 | |
| 269 Sample* AllocationSampleBuffer::ReserveSample() { | 250 Sample* AllocationSampleBuffer::ReserveSample() { |
| 270 MutexLocker ml(mutex_); | 251 MutexLocker ml(mutex_); |
| 271 intptr_t index = ReserveSampleSlotLocked(); | 252 intptr_t index = ReserveSampleSlotLocked(); |
| 272 if (index < 0) { | 253 if (index < 0) { |
| 273 return NULL; | 254 return NULL; |
| 274 } | 255 } |
| 275 return At(index); | 256 return At(index); |
| 276 } | 257 } |
| 277 | 258 |
| 278 | |
| 279 // Attempts to find the true return address when a Dart frame is being setup | 259 // Attempts to find the true return address when a Dart frame is being setup |
| 280 // or torn down. | 260 // or torn down. |
| 281 // NOTE: Architecture specific implementations below. | 261 // NOTE: Architecture specific implementations below. |
| 282 class ReturnAddressLocator : public ValueObject { | 262 class ReturnAddressLocator : public ValueObject { |
| 283 public: | 263 public: |
| 284 ReturnAddressLocator(Sample* sample, const Code& code) | 264 ReturnAddressLocator(Sample* sample, const Code& code) |
| 285 : stack_buffer_(sample->GetStackBuffer()), | 265 : stack_buffer_(sample->GetStackBuffer()), |
| 286 pc_(sample->pc()), | 266 pc_(sample->pc()), |
| 287 code_(Code::ZoneHandle(code.raw())) { | 267 code_(Code::ZoneHandle(code.raw())) { |
| 288 ASSERT(!code_.IsNull()); | 268 ASSERT(!code_.IsNull()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 ASSERT(i < Sample::kStackBufferSizeInWords); | 301 ASSERT(i < Sample::kStackBufferSizeInWords); |
| 322 return stack_buffer_[i]; | 302 return stack_buffer_[i]; |
| 323 } | 303 } |
| 324 | 304 |
| 325 private: | 305 private: |
| 326 uword* stack_buffer_; | 306 uword* stack_buffer_; |
| 327 uword pc_; | 307 uword pc_; |
| 328 const Code& code_; | 308 const Code& code_; |
| 329 }; | 309 }; |
| 330 | 310 |
| 331 | |
| 332 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) | 311 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) |
| 333 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { | 312 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { |
| 334 ASSERT(return_address != NULL); | 313 ASSERT(return_address != NULL); |
| 335 const intptr_t offset = RelativePC(); | 314 const intptr_t offset = RelativePC(); |
| 336 ASSERT(offset >= 0); | 315 ASSERT(offset >= 0); |
| 337 const intptr_t size = code_.Size(); | 316 const intptr_t size = code_.Size(); |
| 338 ASSERT(offset < size); | 317 ASSERT(offset < size); |
| 339 const intptr_t prologue_offset = code_.GetPrologueOffset(); | 318 const intptr_t prologue_offset = code_.GetPrologueOffset(); |
| 340 if (offset < prologue_offset) { | 319 if (offset < prologue_offset) { |
| 341 // Before the prologue, return address is at the top of the stack. | 320 // Before the prologue, return address is at the top of the stack. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 } | 369 } |
| 391 #elif defined(TARGET_ARCH_DBC) | 370 #elif defined(TARGET_ARCH_DBC) |
| 392 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { | 371 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { |
| 393 ASSERT(return_address != NULL); | 372 ASSERT(return_address != NULL); |
| 394 return false; | 373 return false; |
| 395 } | 374 } |
| 396 #else | 375 #else |
| 397 #error ReturnAddressLocator implementation missing for this architecture. | 376 #error ReturnAddressLocator implementation missing for this architecture. |
| 398 #endif | 377 #endif |
| 399 | 378 |
| 400 | |
| 401 bool SampleFilter::TimeFilterSample(Sample* sample) { | 379 bool SampleFilter::TimeFilterSample(Sample* sample) { |
| 402 if ((time_origin_micros_ == -1) || (time_extent_micros_ == -1)) { | 380 if ((time_origin_micros_ == -1) || (time_extent_micros_ == -1)) { |
| 403 // No time filter passed in, always pass. | 381 // No time filter passed in, always pass. |
| 404 return true; | 382 return true; |
| 405 } | 383 } |
| 406 const int64_t timestamp = sample->timestamp(); | 384 const int64_t timestamp = sample->timestamp(); |
| 407 int64_t delta = timestamp - time_origin_micros_; | 385 int64_t delta = timestamp - time_origin_micros_; |
| 408 return (delta >= 0) && (delta <= time_extent_micros_); | 386 return (delta >= 0) && (delta <= time_extent_micros_); |
| 409 } | 387 } |
| 410 | 388 |
| 411 | |
| 412 bool SampleFilter::TaskFilterSample(Sample* sample) { | 389 bool SampleFilter::TaskFilterSample(Sample* sample) { |
| 413 const intptr_t task = static_cast<intptr_t>(sample->thread_task()); | 390 const intptr_t task = static_cast<intptr_t>(sample->thread_task()); |
| 414 if (thread_task_mask_ == kNoTaskFilter) { | 391 if (thread_task_mask_ == kNoTaskFilter) { |
| 415 return true; | 392 return true; |
| 416 } | 393 } |
| 417 return (task & thread_task_mask_) != 0; | 394 return (task & thread_task_mask_) != 0; |
| 418 } | 395 } |
| 419 | 396 |
| 420 | |
| 421 ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate) | 397 ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate) |
| 422 : SampleVisitor(isolate->main_port()) {} | 398 : SampleVisitor(isolate->main_port()) {} |
| 423 | 399 |
| 424 | |
| 425 void ClearProfileVisitor::VisitSample(Sample* sample) { | 400 void ClearProfileVisitor::VisitSample(Sample* sample) { |
| 426 sample->Clear(); | 401 sample->Clear(); |
| 427 } | 402 } |
| 428 | 403 |
| 429 | |
| 430 static void DumpStackFrame(intptr_t frame_index, uword pc) { | 404 static void DumpStackFrame(intptr_t frame_index, uword pc) { |
| 431 Isolate* isolate = Isolate::Current(); | 405 Isolate* isolate = Isolate::Current(); |
| 432 if ((isolate != NULL) && isolate->is_runnable()) { | 406 if ((isolate != NULL) && isolate->is_runnable()) { |
| 433 Code& code = Code::Handle(Code::LookupCodeInVmIsolate(pc)); | 407 Code& code = Code::Handle(Code::LookupCodeInVmIsolate(pc)); |
| 434 if (!code.IsNull()) { | 408 if (!code.IsNull()) { |
| 435 OS::PrintErr(" [0x%" Pp "] %s\n", pc, code.QualifiedName()); | 409 OS::PrintErr(" [0x%" Pp "] %s\n", pc, code.QualifiedName()); |
| 436 return; | 410 return; |
| 437 } | 411 } |
| 438 code = Code::LookupCode(pc); | 412 code = Code::LookupCode(pc); |
| 439 if (!code.IsNull()) { | 413 if (!code.IsNull()) { |
| 440 OS::PrintErr(" [0x%" Pp "] %s\n", pc, code.QualifiedName()); | 414 OS::PrintErr(" [0x%" Pp "] %s\n", pc, code.QualifiedName()); |
| 441 return; | 415 return; |
| 442 } | 416 } |
| 443 } | 417 } |
| 444 | 418 |
| 445 uintptr_t start = 0; | 419 uintptr_t start = 0; |
| 446 char* native_symbol_name = NativeSymbolResolver::LookupSymbolName(pc, &start); | 420 char* native_symbol_name = NativeSymbolResolver::LookupSymbolName(pc, &start); |
| 447 if (native_symbol_name == NULL) { | 421 if (native_symbol_name == NULL) { |
| 448 OS::PrintErr(" [0x%" Pp "] Unknown symbol\n", pc); | 422 OS::PrintErr(" [0x%" Pp "] Unknown symbol\n", pc); |
| 449 } else { | 423 } else { |
| 450 OS::PrintErr(" [0x%" Pp "] %s\n", pc, native_symbol_name); | 424 OS::PrintErr(" [0x%" Pp "] %s\n", pc, native_symbol_name); |
| 451 NativeSymbolResolver::FreeSymbolName(native_symbol_name); | 425 NativeSymbolResolver::FreeSymbolName(native_symbol_name); |
| 452 } | 426 } |
| 453 } | 427 } |
| 454 | 428 |
| 455 | |
| 456 class ProfilerStackWalker : public ValueObject { | 429 class ProfilerStackWalker : public ValueObject { |
| 457 public: | 430 public: |
| 458 ProfilerStackWalker(Dart_Port port_id, | 431 ProfilerStackWalker(Dart_Port port_id, |
| 459 Sample* head_sample, | 432 Sample* head_sample, |
| 460 SampleBuffer* sample_buffer, | 433 SampleBuffer* sample_buffer, |
| 461 intptr_t skip_count = 0) | 434 intptr_t skip_count = 0) |
| 462 : port_id_(port_id), | 435 : port_id_(port_id), |
| 463 sample_(head_sample), | 436 sample_(head_sample), |
| 464 sample_buffer_(sample_buffer), | 437 sample_buffer_(sample_buffer), |
| 465 skip_count_(skip_count), | 438 skip_count_(skip_count), |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 511 protected: | 484 protected: |
| 512 Dart_Port port_id_; | 485 Dart_Port port_id_; |
| 513 Sample* sample_; | 486 Sample* sample_; |
| 514 SampleBuffer* sample_buffer_; | 487 SampleBuffer* sample_buffer_; |
| 515 intptr_t skip_count_; | 488 intptr_t skip_count_; |
| 516 intptr_t frames_skipped_; | 489 intptr_t frames_skipped_; |
| 517 intptr_t frame_index_; | 490 intptr_t frame_index_; |
| 518 intptr_t total_frames_; | 491 intptr_t total_frames_; |
| 519 }; | 492 }; |
| 520 | 493 |
| 521 | |
| 522 // Executing Dart code, walk the stack. | 494 // Executing Dart code, walk the stack. |
| 523 class ProfilerDartStackWalker : public ProfilerStackWalker { | 495 class ProfilerDartStackWalker : public ProfilerStackWalker { |
| 524 public: | 496 public: |
| 525 ProfilerDartStackWalker(Thread* thread, | 497 ProfilerDartStackWalker(Thread* thread, |
| 526 Sample* sample, | 498 Sample* sample, |
| 527 SampleBuffer* sample_buffer, | 499 SampleBuffer* sample_buffer, |
| 528 uword stack_lower, | 500 uword stack_lower, |
| 529 uword stack_upper, | 501 uword stack_upper, |
| 530 uword pc, | 502 uword pc, |
| 531 uword fp, | 503 uword fp, |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 } | 677 } |
| 706 | 678 |
| 707 uword* pc_; | 679 uword* pc_; |
| 708 uword* fp_; | 680 uword* fp_; |
| 709 uword* sp_; | 681 uword* sp_; |
| 710 const uword stack_upper_; | 682 const uword stack_upper_; |
| 711 const uword stack_lower_; | 683 const uword stack_lower_; |
| 712 bool has_exit_frame_; | 684 bool has_exit_frame_; |
| 713 }; | 685 }; |
| 714 | 686 |
| 715 | |
| 716 // If the VM is compiled without frame pointers (which is the default on | 687 // If the VM is compiled without frame pointers (which is the default on |
| 717 // recent GCC versions with optimizing enabled) the stack walking code may | 688 // recent GCC versions with optimizing enabled) the stack walking code may |
| 718 // fail. | 689 // fail. |
| 719 // | 690 // |
| 720 class ProfilerNativeStackWalker : public ProfilerStackWalker { | 691 class ProfilerNativeStackWalker : public ProfilerStackWalker { |
| 721 public: | 692 public: |
| 722 ProfilerNativeStackWalker(Dart_Port port_id, | 693 ProfilerNativeStackWalker(Dart_Port port_id, |
| 723 Sample* sample, | 694 Sample* sample, |
| 724 SampleBuffer* sample_buffer, | 695 SampleBuffer* sample_buffer, |
| 725 uword stack_lower, | 696 uword stack_lower, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 818 return r; | 789 return r; |
| 819 } | 790 } |
| 820 | 791 |
| 821 const uword stack_upper_; | 792 const uword stack_upper_; |
| 822 const uword original_pc_; | 793 const uword original_pc_; |
| 823 const uword original_fp_; | 794 const uword original_fp_; |
| 824 const uword original_sp_; | 795 const uword original_sp_; |
| 825 uword lower_bound_; | 796 uword lower_bound_; |
| 826 }; | 797 }; |
| 827 | 798 |
| 828 | |
| 829 static void CopyStackBuffer(Sample* sample, uword sp_addr) { | 799 static void CopyStackBuffer(Sample* sample, uword sp_addr) { |
| 830 ASSERT(sample != NULL); | 800 ASSERT(sample != NULL); |
| 831 uword* sp = reinterpret_cast<uword*>(sp_addr); | 801 uword* sp = reinterpret_cast<uword*>(sp_addr); |
| 832 uword* buffer = sample->GetStackBuffer(); | 802 uword* buffer = sample->GetStackBuffer(); |
| 833 if (sp != NULL) { | 803 if (sp != NULL) { |
| 834 for (intptr_t i = 0; i < Sample::kStackBufferSizeInWords; i++) { | 804 for (intptr_t i = 0; i < Sample::kStackBufferSizeInWords; i++) { |
| 835 MSAN_UNPOISON(sp, kWordSize); | 805 MSAN_UNPOISON(sp, kWordSize); |
| 836 ASAN_UNPOISON(sp, kWordSize); | 806 ASAN_UNPOISON(sp, kWordSize); |
| 837 buffer[i] = *sp; | 807 buffer[i] = *sp; |
| 838 sp++; | 808 sp++; |
| 839 } | 809 } |
| 840 } | 810 } |
| 841 } | 811 } |
| 842 | 812 |
| 843 | |
| 844 #if defined(HOST_OS_WINDOWS) | 813 #if defined(HOST_OS_WINDOWS) |
| 845 // On Windows this code is synchronously executed from the thread interrupter | 814 // On Windows this code is synchronously executed from the thread interrupter |
| 846 // thread. This means we can safely have a static fault_address. | 815 // thread. This means we can safely have a static fault_address. |
| 847 static uword fault_address = 0; | 816 static uword fault_address = 0; |
| 848 static LONG GuardPageExceptionFilter(EXCEPTION_POINTERS* ep) { | 817 static LONG GuardPageExceptionFilter(EXCEPTION_POINTERS* ep) { |
| 849 fault_address = 0; | 818 fault_address = 0; |
| 850 if (ep->ExceptionRecord->ExceptionCode != STATUS_GUARD_PAGE_VIOLATION) { | 819 if (ep->ExceptionRecord->ExceptionCode != STATUS_GUARD_PAGE_VIOLATION) { |
| 851 return EXCEPTION_CONTINUE_SEARCH; | 820 return EXCEPTION_CONTINUE_SEARCH; |
| 852 } | 821 } |
| 853 // https://goo.gl/p5Fe10 | 822 // https://goo.gl/p5Fe10 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 BOOL success = | 881 BOOL success = |
| 913 VirtualProtect(reinterpret_cast<void*>(fault_address), | 882 VirtualProtect(reinterpret_cast<void*>(fault_address), |
| 914 sizeof(fault_address), new_protect, &old_protect); | 883 sizeof(fault_address), new_protect, &old_protect); |
| 915 USE(success); | 884 USE(success); |
| 916 ASSERT(success); | 885 ASSERT(success); |
| 917 ASSERT(old_protect == PAGE_READWRITE); | 886 ASSERT(old_protect == PAGE_READWRITE); |
| 918 } | 887 } |
| 919 #endif | 888 #endif |
| 920 } | 889 } |
| 921 | 890 |
| 922 | |
| 923 static bool ValidateThreadStackBounds(uintptr_t fp, | 891 static bool ValidateThreadStackBounds(uintptr_t fp, |
| 924 uintptr_t sp, | 892 uintptr_t sp, |
| 925 uword stack_lower, | 893 uword stack_lower, |
| 926 uword stack_upper) { | 894 uword stack_upper) { |
| 927 if (stack_lower >= stack_upper) { | 895 if (stack_lower >= stack_upper) { |
| 928 // Stack boundary is invalid. | 896 // Stack boundary is invalid. |
| 929 return false; | 897 return false; |
| 930 } | 898 } |
| 931 | 899 |
| 932 if ((sp < stack_lower) || (sp >= stack_upper)) { | 900 if ((sp < stack_lower) || (sp >= stack_upper)) { |
| 933 // Stack pointer is outside thread's stack boundary. | 901 // Stack pointer is outside thread's stack boundary. |
| 934 return false; | 902 return false; |
| 935 } | 903 } |
| 936 | 904 |
| 937 if ((fp < stack_lower) || (fp >= stack_upper)) { | 905 if ((fp < stack_lower) || (fp >= stack_upper)) { |
| 938 // Frame pointer is outside threads's stack boundary. | 906 // Frame pointer is outside threads's stack boundary. |
| 939 return false; | 907 return false; |
| 940 } | 908 } |
| 941 | 909 |
| 942 return true; | 910 return true; |
| 943 } | 911 } |
| 944 | 912 |
| 945 | |
| 946 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within | 913 // Get |isolate|'s stack boundary and verify that |sp| and |fp| are within |
| 947 // it. If |get_os_thread_bounds| is true then if |isolate| stackbounds are | 914 // it. If |get_os_thread_bounds| is true then if |isolate| stackbounds are |
| 948 // not available we fallback to using underlying OS thread bounds. This only | 915 // not available we fallback to using underlying OS thread bounds. This only |
| 949 // works for the current thread. | 916 // works for the current thread. |
| 950 // Return |false| if anything looks suspicious. | 917 // Return |false| if anything looks suspicious. |
| 951 static bool GetAndValidateThreadStackBounds(Thread* thread, | 918 static bool GetAndValidateThreadStackBounds(Thread* thread, |
| 952 uintptr_t fp, | 919 uintptr_t fp, |
| 953 uintptr_t sp, | 920 uintptr_t sp, |
| 954 uword* stack_lower, | 921 uword* stack_lower, |
| 955 uword* stack_upper, | 922 uword* stack_upper, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 991 } | 958 } |
| 992 | 959 |
| 993 if (!use_simulator_stack_bounds && (sp > *stack_lower)) { | 960 if (!use_simulator_stack_bounds && (sp > *stack_lower)) { |
| 994 // The stack pointer gives us a tighter lower bound. | 961 // The stack pointer gives us a tighter lower bound. |
| 995 *stack_lower = sp; | 962 *stack_lower = sp; |
| 996 } | 963 } |
| 997 | 964 |
| 998 return ValidateThreadStackBounds(fp, sp, *stack_lower, *stack_upper); | 965 return ValidateThreadStackBounds(fp, sp, *stack_lower, *stack_upper); |
| 999 } | 966 } |
| 1000 | 967 |
| 1001 | |
| 1002 // Some simple sanity checking of |pc|, |fp|, and |sp|. | 968 // Some simple sanity checking of |pc|, |fp|, and |sp|. |
| 1003 static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) { | 969 static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) { |
| 1004 if ((sp == 0) || (fp == 0) || (pc == 0)) { | 970 if ((sp == 0) || (fp == 0) || (pc == 0)) { |
| 1005 // None of these registers should be zero. | 971 // None of these registers should be zero. |
| 1006 return false; | 972 return false; |
| 1007 } | 973 } |
| 1008 | 974 |
| 1009 if (sp > fp) { | 975 if (sp > fp) { |
| 1010 // Assuming the stack grows down, we should never have a stack pointer above | 976 // Assuming the stack grows down, we should never have a stack pointer above |
| 1011 // the frame pointer. | 977 // the frame pointer. |
| 1012 return false; | 978 return false; |
| 1013 } | 979 } |
| 1014 | 980 |
| 1015 return true; | 981 return true; |
| 1016 } | 982 } |
| 1017 | 983 |
| 1018 | |
| 1019 static Sample* SetupSample(Thread* thread, | 984 static Sample* SetupSample(Thread* thread, |
| 1020 SampleBuffer* sample_buffer, | 985 SampleBuffer* sample_buffer, |
| 1021 ThreadId tid) { | 986 ThreadId tid) { |
| 1022 ASSERT(thread != NULL); | 987 ASSERT(thread != NULL); |
| 1023 Isolate* isolate = thread->isolate(); | 988 Isolate* isolate = thread->isolate(); |
| 1024 ASSERT(sample_buffer != NULL); | 989 ASSERT(sample_buffer != NULL); |
| 1025 Sample* sample = sample_buffer->ReserveSample(); | 990 Sample* sample = sample_buffer->ReserveSample(); |
| 1026 sample->Init(isolate->main_port(), OS::GetCurrentMonotonicMicros(), tid); | 991 sample->Init(isolate->main_port(), OS::GetCurrentMonotonicMicros(), tid); |
| 1027 uword vm_tag = thread->vm_tag(); | 992 uword vm_tag = thread->vm_tag(); |
| 1028 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) | 993 #if defined(USING_SIMULATOR) && !defined(TARGET_ARCH_DBC) |
| 1029 // When running in the simulator, the runtime entry function address | 994 // When running in the simulator, the runtime entry function address |
| 1030 // (stored as the vm tag) is the address of a redirect function. | 995 // (stored as the vm tag) is the address of a redirect function. |
| 1031 // Attempt to find the real runtime entry function address and use that. | 996 // Attempt to find the real runtime entry function address and use that. |
| 1032 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); | 997 uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag); |
| 1033 if (redirect_vm_tag != 0) { | 998 if (redirect_vm_tag != 0) { |
| 1034 vm_tag = redirect_vm_tag; | 999 vm_tag = redirect_vm_tag; |
| 1035 } | 1000 } |
| 1036 #endif | 1001 #endif |
| 1037 sample->set_vm_tag(vm_tag); | 1002 sample->set_vm_tag(vm_tag); |
| 1038 sample->set_user_tag(isolate->user_tag()); | 1003 sample->set_user_tag(isolate->user_tag()); |
| 1039 sample->set_thread_task(thread->task_kind()); | 1004 sample->set_thread_task(thread->task_kind()); |
| 1040 return sample; | 1005 return sample; |
| 1041 } | 1006 } |
| 1042 | 1007 |
| 1043 | |
| 1044 static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) { | 1008 static Sample* SetupSampleNative(SampleBuffer* sample_buffer, ThreadId tid) { |
| 1045 Sample* sample = sample_buffer->ReserveSample(); | 1009 Sample* sample = sample_buffer->ReserveSample(); |
| 1046 if (sample == NULL) { | 1010 if (sample == NULL) { |
| 1047 return NULL; | 1011 return NULL; |
| 1048 } | 1012 } |
| 1049 sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid); | 1013 sample->Init(ILLEGAL_PORT, OS::GetCurrentMonotonicMicros(), tid); |
| 1050 Thread* thread = Thread::Current(); | 1014 Thread* thread = Thread::Current(); |
| 1051 | 1015 |
| 1052 // Note: setting thread task in order to be consistent with other samples. The | 1016 // Note: setting thread task in order to be consistent with other samples. The |
| 1053 // task kind is not used by NativeAllocationSampleFilter for filtering | 1017 // task kind is not used by NativeAllocationSampleFilter for filtering |
| 1054 // purposes as some samples may be collected when no thread exists. | 1018 // purposes as some samples may be collected when no thread exists. |
| 1055 if (thread != NULL) { | 1019 if (thread != NULL) { |
| 1056 sample->set_thread_task(thread->task_kind()); | 1020 sample->set_thread_task(thread->task_kind()); |
| 1057 } | 1021 } |
| 1058 return sample; | 1022 return sample; |
| 1059 } | 1023 } |
| 1060 | 1024 |
| 1061 | |
| 1062 static bool CheckIsolate(Isolate* isolate) { | 1025 static bool CheckIsolate(Isolate* isolate) { |
| 1063 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { | 1026 if ((isolate == NULL) || (Dart::vm_isolate() == NULL)) { |
| 1064 // No isolate. | 1027 // No isolate. |
| 1065 return false; | 1028 return false; |
| 1066 } | 1029 } |
| 1067 return isolate != Dart::vm_isolate(); | 1030 return isolate != Dart::vm_isolate(); |
| 1068 } | 1031 } |
| 1069 | 1032 |
| 1070 | |
| 1071 void Profiler::DumpStackTrace(void* context) { | 1033 void Profiler::DumpStackTrace(void* context) { |
| 1072 #if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) | 1034 #if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) |
| 1073 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); | 1035 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| 1074 mcontext_t mcontext = ucontext->uc_mcontext; | 1036 mcontext_t mcontext = ucontext->uc_mcontext; |
| 1075 uword pc = SignalHandler::GetProgramCounter(mcontext); | 1037 uword pc = SignalHandler::GetProgramCounter(mcontext); |
| 1076 uword fp = SignalHandler::GetFramePointer(mcontext); | 1038 uword fp = SignalHandler::GetFramePointer(mcontext); |
| 1077 uword sp = SignalHandler::GetCStackPointer(mcontext); | 1039 uword sp = SignalHandler::GetCStackPointer(mcontext); |
| 1078 DumpStackTrace(sp, fp, pc, true /* for_crash */); | 1040 DumpStackTrace(sp, fp, pc, true /* for_crash */); |
| 1079 #else | 1041 #else |
| 1080 // TODO(fschneider): Add support for more platforms. | 1042 // TODO(fschneider): Add support for more platforms. |
| 1081 // Do nothing on unsupported platforms. | 1043 // Do nothing on unsupported platforms. |
| 1082 #endif | 1044 #endif |
| 1083 } | 1045 } |
| 1084 | 1046 |
| 1085 | |
| 1086 void Profiler::DumpStackTrace(bool for_crash) { | 1047 void Profiler::DumpStackTrace(bool for_crash) { |
| 1087 uintptr_t sp = Thread::GetCurrentStackPointer(); | 1048 uintptr_t sp = Thread::GetCurrentStackPointer(); |
| 1088 uintptr_t fp = 0; | 1049 uintptr_t fp = 0; |
| 1089 uintptr_t pc = OS::GetProgramCounter(); | 1050 uintptr_t pc = OS::GetProgramCounter(); |
| 1090 | 1051 |
| 1091 COPY_FP_REGISTER(fp); | 1052 COPY_FP_REGISTER(fp); |
| 1092 | 1053 |
| 1093 DumpStackTrace(sp, fp, pc, for_crash); | 1054 DumpStackTrace(sp, fp, pc, for_crash); |
| 1094 } | 1055 } |
| 1095 | 1056 |
| 1096 | |
| 1097 void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) { | 1057 void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) { |
| 1098 if (for_crash) { | 1058 if (for_crash) { |
| 1099 // Allow only one stack trace to prevent recursively printing stack traces | 1059 // Allow only one stack trace to prevent recursively printing stack traces |
| 1100 // if we hit an assert while printing the stack. | 1060 // if we hit an assert while printing the stack. |
| 1101 static uintptr_t started_dump = 0; | 1061 static uintptr_t started_dump = 0; |
| 1102 if (AtomicOperations::FetchAndIncrement(&started_dump) != 0) { | 1062 if (AtomicOperations::FetchAndIncrement(&started_dump) != 0) { |
| 1103 OS::PrintErr("Aborting re-entrant request for stack trace.\n"); | 1063 OS::PrintErr("Aborting re-entrant request for stack trace.\n"); |
| 1104 return; | 1064 return; |
| 1105 } | 1065 } |
| 1106 } | 1066 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1135 return; | 1095 return; |
| 1136 } | 1096 } |
| 1137 | 1097 |
| 1138 ProfilerNativeStackWalker native_stack_walker( | 1098 ProfilerNativeStackWalker native_stack_walker( |
| 1139 (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, NULL, NULL, | 1099 (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT, NULL, NULL, |
| 1140 stack_lower, stack_upper, pc, fp, sp); | 1100 stack_lower, stack_upper, pc, fp, sp); |
| 1141 native_stack_walker.walk(); | 1101 native_stack_walker.walk(); |
| 1142 OS::PrintErr("-- End of DumpStackTrace\n"); | 1102 OS::PrintErr("-- End of DumpStackTrace\n"); |
| 1143 } | 1103 } |
| 1144 | 1104 |
| 1145 | |
| 1146 void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { | 1105 void Profiler::SampleAllocation(Thread* thread, intptr_t cid) { |
| 1147 ASSERT(thread != NULL); | 1106 ASSERT(thread != NULL); |
| 1148 OSThread* os_thread = thread->os_thread(); | 1107 OSThread* os_thread = thread->os_thread(); |
| 1149 ASSERT(os_thread != NULL); | 1108 ASSERT(os_thread != NULL); |
| 1150 Isolate* isolate = thread->isolate(); | 1109 Isolate* isolate = thread->isolate(); |
| 1151 if (!CheckIsolate(isolate)) { | 1110 if (!CheckIsolate(isolate)) { |
| 1152 return; | 1111 return; |
| 1153 } | 1112 } |
| 1154 | 1113 |
| 1155 const bool exited_dart_code = thread->HasExitedDartCode(); | 1114 const bool exited_dart_code = thread->HasExitedDartCode(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1194 dart_exit_stack_walker.walk(); | 1153 dart_exit_stack_walker.walk(); |
| 1195 } else { | 1154 } else { |
| 1196 // Fall back. | 1155 // Fall back. |
| 1197 uintptr_t pc = OS::GetProgramCounter(); | 1156 uintptr_t pc = OS::GetProgramCounter(); |
| 1198 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); | 1157 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); |
| 1199 sample->SetAllocationCid(cid); | 1158 sample->SetAllocationCid(cid); |
| 1200 sample->SetAt(0, pc); | 1159 sample->SetAt(0, pc); |
| 1201 } | 1160 } |
| 1202 } | 1161 } |
| 1203 | 1162 |
| 1204 | |
| 1205 Sample* Profiler::SampleNativeAllocation(intptr_t skip_count, | 1163 Sample* Profiler::SampleNativeAllocation(intptr_t skip_count, |
| 1206 uword address, | 1164 uword address, |
| 1207 uintptr_t allocation_size) { | 1165 uintptr_t allocation_size) { |
| 1208 AllocationSampleBuffer* sample_buffer = Profiler::allocation_sample_buffer(); | 1166 AllocationSampleBuffer* sample_buffer = Profiler::allocation_sample_buffer(); |
| 1209 if (sample_buffer == NULL) { | 1167 if (sample_buffer == NULL) { |
| 1210 return NULL; | 1168 return NULL; |
| 1211 } | 1169 } |
| 1212 | 1170 |
| 1213 uintptr_t sp = Thread::GetCurrentStackPointer(); | 1171 uintptr_t sp = Thread::GetCurrentStackPointer(); |
| 1214 uintptr_t fp = 0; | 1172 uintptr_t fp = 0; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1249 | 1207 |
| 1250 ProfilerNativeStackWalker native_stack_walker( | 1208 ProfilerNativeStackWalker native_stack_walker( |
| 1251 ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, | 1209 ILLEGAL_PORT, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp, |
| 1252 skip_count); | 1210 skip_count); |
| 1253 | 1211 |
| 1254 native_stack_walker.walk(); | 1212 native_stack_walker.walk(); |
| 1255 | 1213 |
| 1256 return sample; | 1214 return sample; |
| 1257 } | 1215 } |
| 1258 | 1216 |
| 1259 | |
| 1260 void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) { | 1217 void Profiler::SampleThreadSingleFrame(Thread* thread, uintptr_t pc) { |
| 1261 ASSERT(thread != NULL); | 1218 ASSERT(thread != NULL); |
| 1262 OSThread* os_thread = thread->os_thread(); | 1219 OSThread* os_thread = thread->os_thread(); |
| 1263 ASSERT(os_thread != NULL); | 1220 ASSERT(os_thread != NULL); |
| 1264 Isolate* isolate = thread->isolate(); | 1221 Isolate* isolate = thread->isolate(); |
| 1265 | 1222 |
| 1266 SampleBuffer* sample_buffer = Profiler::sample_buffer(); | 1223 SampleBuffer* sample_buffer = Profiler::sample_buffer(); |
| 1267 if (sample_buffer == NULL) { | 1224 if (sample_buffer == NULL) { |
| 1268 // Profiler not initialized. | 1225 // Profiler not initialized. |
| 1269 return; | 1226 return; |
| 1270 } | 1227 } |
| 1271 | 1228 |
| 1272 // Setup sample. | 1229 // Setup sample. |
| 1273 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); | 1230 Sample* sample = SetupSample(thread, sample_buffer, os_thread->trace_id()); |
| 1274 // Increment counter for vm tag. | 1231 // Increment counter for vm tag. |
| 1275 VMTagCounters* counters = isolate->vm_tag_counters(); | 1232 VMTagCounters* counters = isolate->vm_tag_counters(); |
| 1276 ASSERT(counters != NULL); | 1233 ASSERT(counters != NULL); |
| 1277 if (thread->IsMutatorThread()) { | 1234 if (thread->IsMutatorThread()) { |
| 1278 counters->Increment(sample->vm_tag()); | 1235 counters->Increment(sample->vm_tag()); |
| 1279 } | 1236 } |
| 1280 | 1237 |
| 1281 // Write the single pc value. | 1238 // Write the single pc value. |
| 1282 sample->SetAt(0, pc); | 1239 sample->SetAt(0, pc); |
| 1283 } | 1240 } |
| 1284 | 1241 |
| 1285 | |
| 1286 void Profiler::SampleThread(Thread* thread, | 1242 void Profiler::SampleThread(Thread* thread, |
| 1287 const InterruptedThreadState& state) { | 1243 const InterruptedThreadState& state) { |
| 1288 ASSERT(thread != NULL); | 1244 ASSERT(thread != NULL); |
| 1289 OSThread* os_thread = thread->os_thread(); | 1245 OSThread* os_thread = thread->os_thread(); |
| 1290 ASSERT(os_thread != NULL); | 1246 ASSERT(os_thread != NULL); |
| 1291 Isolate* isolate = thread->isolate(); | 1247 Isolate* isolate = thread->isolate(); |
| 1292 | 1248 |
| 1293 // Thread is not doing VM work. | 1249 // Thread is not doing VM work. |
| 1294 if (thread->task_kind() == Thread::kUnknownTask) { | 1250 if (thread->task_kind() == Thread::kUnknownTask) { |
| 1295 AtomicOperations::IncrementInt64By(&counters_.bail_out_unknown_task, 1); | 1251 AtomicOperations::IncrementInt64By(&counters_.bail_out_unknown_task, 1); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer, | 1344 ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer, |
| 1389 stack_lower, stack_upper, pc, fp, | 1345 stack_lower, stack_upper, pc, fp, |
| 1390 sp, exited_dart_code, false); | 1346 sp, exited_dart_code, false); |
| 1391 | 1347 |
| 1392 // All memory access is done inside CollectSample. | 1348 // All memory access is done inside CollectSample. |
| 1393 CollectSample(isolate, exited_dart_code, in_dart_code, sample, | 1349 CollectSample(isolate, exited_dart_code, in_dart_code, sample, |
| 1394 &native_stack_walker, &dart_stack_walker, pc, fp, sp, | 1350 &native_stack_walker, &dart_stack_walker, pc, fp, sp, |
| 1395 &counters_); | 1351 &counters_); |
| 1396 } | 1352 } |
| 1397 | 1353 |
| 1398 | |
| 1399 CodeDescriptor::CodeDescriptor(const Code& code) : code_(code) { | 1354 CodeDescriptor::CodeDescriptor(const Code& code) : code_(code) { |
| 1400 ASSERT(!code_.IsNull()); | 1355 ASSERT(!code_.IsNull()); |
| 1401 } | 1356 } |
| 1402 | 1357 |
| 1403 | |
| 1404 uword CodeDescriptor::Start() const { | 1358 uword CodeDescriptor::Start() const { |
| 1405 return code_.PayloadStart(); | 1359 return code_.PayloadStart(); |
| 1406 } | 1360 } |
| 1407 | 1361 |
| 1408 | |
| 1409 uword CodeDescriptor::Size() const { | 1362 uword CodeDescriptor::Size() const { |
| 1410 return code_.Size(); | 1363 return code_.Size(); |
| 1411 } | 1364 } |
| 1412 | 1365 |
| 1413 | |
| 1414 int64_t CodeDescriptor::CompileTimestamp() const { | 1366 int64_t CodeDescriptor::CompileTimestamp() const { |
| 1415 return code_.compile_timestamp(); | 1367 return code_.compile_timestamp(); |
| 1416 } | 1368 } |
| 1417 | 1369 |
| 1418 | |
| 1419 CodeLookupTable::CodeLookupTable(Thread* thread) { | 1370 CodeLookupTable::CodeLookupTable(Thread* thread) { |
| 1420 Build(thread); | 1371 Build(thread); |
| 1421 } | 1372 } |
| 1422 | 1373 |
| 1423 | |
| 1424 class CodeLookupTableBuilder : public ObjectVisitor { | 1374 class CodeLookupTableBuilder : public ObjectVisitor { |
| 1425 public: | 1375 public: |
| 1426 explicit CodeLookupTableBuilder(CodeLookupTable* table) : table_(table) { | 1376 explicit CodeLookupTableBuilder(CodeLookupTable* table) : table_(table) { |
| 1427 ASSERT(table_ != NULL); | 1377 ASSERT(table_ != NULL); |
| 1428 } | 1378 } |
| 1429 | 1379 |
| 1430 ~CodeLookupTableBuilder() {} | 1380 ~CodeLookupTableBuilder() {} |
| 1431 | 1381 |
| 1432 void VisitObject(RawObject* raw_obj) { | 1382 void VisitObject(RawObject* raw_obj) { |
| 1433 uint32_t tags = raw_obj->ptr()->tags_; | 1383 uint32_t tags = raw_obj->ptr()->tags_; |
| 1434 if (RawObject::ClassIdTag::decode(tags) == kCodeCid) { | 1384 if (RawObject::ClassIdTag::decode(tags) == kCodeCid) { |
| 1435 RawCode* raw_code = reinterpret_cast<RawCode*>(raw_obj); | 1385 RawCode* raw_code = reinterpret_cast<RawCode*>(raw_obj); |
| 1436 const Code& code = Code::Handle(raw_code); | 1386 const Code& code = Code::Handle(raw_code); |
| 1437 ASSERT(!code.IsNull()); | 1387 ASSERT(!code.IsNull()); |
| 1438 const Instructions& instructions = | 1388 const Instructions& instructions = |
| 1439 Instructions::Handle(code.instructions()); | 1389 Instructions::Handle(code.instructions()); |
| 1440 ASSERT(!instructions.IsNull()); | 1390 ASSERT(!instructions.IsNull()); |
| 1441 table_->Add(code); | 1391 table_->Add(code); |
| 1442 } | 1392 } |
| 1443 } | 1393 } |
| 1444 | 1394 |
| 1445 private: | 1395 private: |
| 1446 CodeLookupTable* table_; | 1396 CodeLookupTable* table_; |
| 1447 }; | 1397 }; |
| 1448 | 1398 |
| 1449 | |
| 1450 void CodeLookupTable::Build(Thread* thread) { | 1399 void CodeLookupTable::Build(Thread* thread) { |
| 1451 ASSERT(thread != NULL); | 1400 ASSERT(thread != NULL); |
| 1452 Isolate* isolate = thread->isolate(); | 1401 Isolate* isolate = thread->isolate(); |
| 1453 ASSERT(isolate != NULL); | 1402 ASSERT(isolate != NULL); |
| 1454 Isolate* vm_isolate = Dart::vm_isolate(); | 1403 Isolate* vm_isolate = Dart::vm_isolate(); |
| 1455 ASSERT(vm_isolate != NULL); | 1404 ASSERT(vm_isolate != NULL); |
| 1456 | 1405 |
| 1457 // Clear. | 1406 // Clear. |
| 1458 code_objects_.Clear(); | 1407 code_objects_.Clear(); |
| 1459 | 1408 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1478 const CodeDescriptor* b = At(i + 1); | 1427 const CodeDescriptor* b = At(i + 1); |
| 1479 ASSERT(a->Start() < b->Start()); | 1428 ASSERT(a->Start() < b->Start()); |
| 1480 ASSERT(FindCode(a->Start()) == a); | 1429 ASSERT(FindCode(a->Start()) == a); |
| 1481 ASSERT(FindCode(b->Start()) == b); | 1430 ASSERT(FindCode(b->Start()) == b); |
| 1482 ASSERT(FindCode(a->Start() + a->Size() - 1) == a); | 1431 ASSERT(FindCode(a->Start() + a->Size() - 1) == a); |
| 1483 ASSERT(FindCode(b->Start() + b->Size() - 1) == b); | 1432 ASSERT(FindCode(b->Start() + b->Size() - 1) == b); |
| 1484 } | 1433 } |
| 1485 #endif | 1434 #endif |
| 1486 } | 1435 } |
| 1487 | 1436 |
| 1488 | |
| 1489 void CodeLookupTable::Add(const Code& code) { | 1437 void CodeLookupTable::Add(const Code& code) { |
| 1490 ASSERT(!code.IsNull()); | 1438 ASSERT(!code.IsNull()); |
| 1491 CodeDescriptor* cd = new CodeDescriptor(code); | 1439 CodeDescriptor* cd = new CodeDescriptor(code); |
| 1492 code_objects_.Add(cd); | 1440 code_objects_.Add(cd); |
| 1493 } | 1441 } |
| 1494 | 1442 |
| 1495 | |
| 1496 const CodeDescriptor* CodeLookupTable::FindCode(uword pc) const { | 1443 const CodeDescriptor* CodeLookupTable::FindCode(uword pc) const { |
| 1497 intptr_t first = 0; | 1444 intptr_t first = 0; |
| 1498 intptr_t count = length(); | 1445 intptr_t count = length(); |
| 1499 while (count > 0) { | 1446 while (count > 0) { |
| 1500 intptr_t current = first; | 1447 intptr_t current = first; |
| 1501 intptr_t step = count / 2; | 1448 intptr_t step = count / 2; |
| 1502 current += step; | 1449 current += step; |
| 1503 const CodeDescriptor* cd = At(current); | 1450 const CodeDescriptor* cd = At(current); |
| 1504 if (pc >= cd->Start()) { | 1451 if (pc >= cd->Start()) { |
| 1505 first = ++current; | 1452 first = ++current; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1516 first--; | 1463 first--; |
| 1517 ASSERT(first >= 0); | 1464 ASSERT(first >= 0); |
| 1518 ASSERT(first < length()); | 1465 ASSERT(first < length()); |
| 1519 const CodeDescriptor* cd = At(first); | 1466 const CodeDescriptor* cd = At(first); |
| 1520 if (cd->Contains(pc)) { | 1467 if (cd->Contains(pc)) { |
| 1521 return cd; | 1468 return cd; |
| 1522 } | 1469 } |
| 1523 return NULL; | 1470 return NULL; |
| 1524 } | 1471 } |
| 1525 | 1472 |
| 1526 | |
| 1527 ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer( | 1473 ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer( |
| 1528 SampleFilter* filter) { | 1474 SampleFilter* filter) { |
| 1529 ASSERT(filter != NULL); | 1475 ASSERT(filter != NULL); |
| 1530 Thread* thread = Thread::Current(); | 1476 Thread* thread = Thread::Current(); |
| 1531 Zone* zone = thread->zone(); | 1477 Zone* zone = thread->zone(); |
| 1532 | 1478 |
| 1533 ProcessedSampleBuffer* buffer = new (zone) ProcessedSampleBuffer(); | 1479 ProcessedSampleBuffer* buffer = new (zone) ProcessedSampleBuffer(); |
| 1534 | 1480 |
| 1535 const intptr_t length = capacity(); | 1481 const intptr_t length = capacity(); |
| 1536 for (intptr_t i = 0; i < length; i++) { | 1482 for (intptr_t i = 0; i < length; i++) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1567 } | 1513 } |
| 1568 if (!filter->FilterSample(sample)) { | 1514 if (!filter->FilterSample(sample)) { |
| 1569 // Did not pass filter. | 1515 // Did not pass filter. |
| 1570 continue; | 1516 continue; |
| 1571 } | 1517 } |
| 1572 buffer->Add(BuildProcessedSample(sample, buffer->code_lookup_table())); | 1518 buffer->Add(BuildProcessedSample(sample, buffer->code_lookup_table())); |
| 1573 } | 1519 } |
| 1574 return buffer; | 1520 return buffer; |
| 1575 } | 1521 } |
| 1576 | 1522 |
| 1577 | |
| 1578 ProcessedSample* SampleBuffer::BuildProcessedSample( | 1523 ProcessedSample* SampleBuffer::BuildProcessedSample( |
| 1579 Sample* sample, | 1524 Sample* sample, |
| 1580 const CodeLookupTable& clt) { | 1525 const CodeLookupTable& clt) { |
| 1581 Thread* thread = Thread::Current(); | 1526 Thread* thread = Thread::Current(); |
| 1582 Zone* zone = thread->zone(); | 1527 Zone* zone = thread->zone(); |
| 1583 | 1528 |
| 1584 ProcessedSample* processed_sample = new (zone) ProcessedSample(); | 1529 ProcessedSample* processed_sample = new (zone) ProcessedSample(); |
| 1585 | 1530 |
| 1586 // Copy state bits from sample. | 1531 // Copy state bits from sample. |
| 1587 processed_sample->set_native_allocation_size_bytes( | 1532 processed_sample->set_native_allocation_size_bytes( |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1612 | 1557 |
| 1613 if (!sample->exit_frame_sample()) { | 1558 if (!sample->exit_frame_sample()) { |
| 1614 processed_sample->FixupCaller(clt, sample->pc_marker(), | 1559 processed_sample->FixupCaller(clt, sample->pc_marker(), |
| 1615 sample->GetStackBuffer()); | 1560 sample->GetStackBuffer()); |
| 1616 } | 1561 } |
| 1617 | 1562 |
| 1618 processed_sample->set_truncated(truncated); | 1563 processed_sample->set_truncated(truncated); |
| 1619 return processed_sample; | 1564 return processed_sample; |
| 1620 } | 1565 } |
| 1621 | 1566 |
| 1622 | |
| 1623 Sample* SampleBuffer::Next(Sample* sample) { | 1567 Sample* SampleBuffer::Next(Sample* sample) { |
| 1624 if (!sample->is_continuation_sample()) return NULL; | 1568 if (!sample->is_continuation_sample()) return NULL; |
| 1625 Sample* next_sample = At(sample->continuation_index()); | 1569 Sample* next_sample = At(sample->continuation_index()); |
| 1626 // Sanity check. | 1570 // Sanity check. |
| 1627 ASSERT(sample != next_sample); | 1571 ASSERT(sample != next_sample); |
| 1628 // Detect invalid chaining. | 1572 // Detect invalid chaining. |
| 1629 if (sample->port() != next_sample->port()) { | 1573 if (sample->port() != next_sample->port()) { |
| 1630 return NULL; | 1574 return NULL; |
| 1631 } | 1575 } |
| 1632 if (sample->timestamp() != next_sample->timestamp()) { | 1576 if (sample->timestamp() != next_sample->timestamp()) { |
| 1633 return NULL; | 1577 return NULL; |
| 1634 } | 1578 } |
| 1635 if (sample->tid() != next_sample->tid()) { | 1579 if (sample->tid() != next_sample->tid()) { |
| 1636 return NULL; | 1580 return NULL; |
| 1637 } | 1581 } |
| 1638 return next_sample; | 1582 return next_sample; |
| 1639 } | 1583 } |
| 1640 | 1584 |
| 1641 | |
| 1642 ProcessedSample::ProcessedSample() | 1585 ProcessedSample::ProcessedSample() |
| 1643 : pcs_(kSampleSize), | 1586 : pcs_(kSampleSize), |
| 1644 timestamp_(0), | 1587 timestamp_(0), |
| 1645 vm_tag_(0), | 1588 vm_tag_(0), |
| 1646 user_tag_(0), | 1589 user_tag_(0), |
| 1647 allocation_cid_(-1), | 1590 allocation_cid_(-1), |
| 1648 truncated_(false), | 1591 truncated_(false), |
| 1649 timeline_trie_(NULL) {} | 1592 timeline_trie_(NULL) {} |
| 1650 | 1593 |
| 1651 | |
| 1652 void ProcessedSample::FixupCaller(const CodeLookupTable& clt, | 1594 void ProcessedSample::FixupCaller(const CodeLookupTable& clt, |
| 1653 uword pc_marker, | 1595 uword pc_marker, |
| 1654 uword* stack_buffer) { | 1596 uword* stack_buffer) { |
| 1655 const CodeDescriptor* cd = clt.FindCode(At(0)); | 1597 const CodeDescriptor* cd = clt.FindCode(At(0)); |
| 1656 if (cd == NULL) { | 1598 if (cd == NULL) { |
| 1657 // No Dart code. | 1599 // No Dart code. |
| 1658 return; | 1600 return; |
| 1659 } | 1601 } |
| 1660 if (cd->CompileTimestamp() > timestamp()) { | 1602 if (cd->CompileTimestamp() > timestamp()) { |
| 1661 // Code compiled after sample. Ignore. | 1603 // Code compiled after sample. Ignore. |
| 1662 return; | 1604 return; |
| 1663 } | 1605 } |
| 1664 CheckForMissingDartFrame(clt, cd, pc_marker, stack_buffer); | 1606 CheckForMissingDartFrame(clt, cd, pc_marker, stack_buffer); |
| 1665 } | 1607 } |
| 1666 | 1608 |
| 1667 | |
| 1668 void ProcessedSample::CheckForMissingDartFrame(const CodeLookupTable& clt, | 1609 void ProcessedSample::CheckForMissingDartFrame(const CodeLookupTable& clt, |
| 1669 const CodeDescriptor* cd, | 1610 const CodeDescriptor* cd, |
| 1670 uword pc_marker, | 1611 uword pc_marker, |
| 1671 uword* stack_buffer) { | 1612 uword* stack_buffer) { |
| 1672 ASSERT(cd != NULL); | 1613 ASSERT(cd != NULL); |
| 1673 const Code& code = Code::Handle(cd->code()); | 1614 const Code& code = Code::Handle(cd->code()); |
| 1674 ASSERT(!code.IsNull()); | 1615 ASSERT(!code.IsNull()); |
| 1675 // Some stubs (and intrinsics) do not push a frame onto the stack leaving | 1616 // Some stubs (and intrinsics) do not push a frame onto the stack leaving |
| 1676 // the frame pointer in the caller. | 1617 // the frame pointer in the caller. |
| 1677 // | 1618 // |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1712 if (clt.FindCode(return_address) == NULL) { | 1653 if (clt.FindCode(return_address) == NULL) { |
| 1713 // Return address is not from a Dart code object. Do not insert. | 1654 // Return address is not from a Dart code object. Do not insert. |
| 1714 return; | 1655 return; |
| 1715 } | 1656 } |
| 1716 | 1657 |
| 1717 if (return_address != 0) { | 1658 if (return_address != 0) { |
| 1718 InsertAt(1, return_address); | 1659 InsertAt(1, return_address); |
| 1719 } | 1660 } |
| 1720 } | 1661 } |
| 1721 | 1662 |
| 1722 | |
| 1723 ProcessedSampleBuffer::ProcessedSampleBuffer() | 1663 ProcessedSampleBuffer::ProcessedSampleBuffer() |
| 1724 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { | 1664 : code_lookup_table_(new CodeLookupTable(Thread::Current())) { |
| 1725 ASSERT(code_lookup_table_ != NULL); | 1665 ASSERT(code_lookup_table_ != NULL); |
| 1726 } | 1666 } |
| 1727 | 1667 |
| 1728 #endif // !PRODUCT | 1668 #endif // !PRODUCT |
| 1729 | 1669 |
| 1730 } // namespace dart | 1670 } // namespace dart |
| OLD | NEW |