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 |