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 #ifndef RUNTIME_VM_PROFILER_H_ | 5 #ifndef RUNTIME_VM_PROFILER_H_ |
6 #define RUNTIME_VM_PROFILER_H_ | 6 #define RUNTIME_VM_PROFILER_H_ |
7 | 7 |
8 #include "vm/allocation.h" | 8 #include "vm/allocation.h" |
9 #include "vm/bitfield.h" | 9 #include "vm/bitfield.h" |
10 #include "vm/code_observers.h" | 10 #include "vm/code_observers.h" |
11 #include "vm/globals.h" | 11 #include "vm/globals.h" |
12 #include "vm/growable_array.h" | 12 #include "vm/growable_array.h" |
| 13 #include "vm/malloc_hooks.h" |
| 14 #include "vm/native_symbol.h" |
13 #include "vm/object.h" | 15 #include "vm/object.h" |
14 #include "vm/tags.h" | 16 #include "vm/tags.h" |
15 #include "vm/thread_interrupter.h" | 17 #include "vm/thread_interrupter.h" |
16 | 18 |
17 // Profiler sampling and stack walking support. | 19 // Profiler sampling and stack walking support. |
18 // NOTE: For service related code, see profile_service.h. | 20 // NOTE: For service related code, see profile_service.h. |
19 | 21 |
20 namespace dart { | 22 namespace dart { |
21 | 23 |
22 // Forward declarations. | 24 // Forward declarations. |
(...skipping 30 matching lines...) Expand all Loading... |
53 | 55 |
54 static void SetSampleDepth(intptr_t depth); | 56 static void SetSampleDepth(intptr_t depth); |
55 static void SetSamplePeriod(intptr_t period); | 57 static void SetSamplePeriod(intptr_t period); |
56 | 58 |
57 static SampleBuffer* sample_buffer() { return sample_buffer_; } | 59 static SampleBuffer* sample_buffer() { return sample_buffer_; } |
58 | 60 |
59 static void DumpStackTrace(void* context); | 61 static void DumpStackTrace(void* context); |
60 static void DumpStackTrace(); | 62 static void DumpStackTrace(); |
61 | 63 |
62 static void SampleAllocation(Thread* thread, intptr_t cid); | 64 static void SampleAllocation(Thread* thread, intptr_t cid); |
63 static Sample* SampleNativeAllocation(intptr_t skip_count); | 65 static Sample* SampleNativeAllocation(intptr_t skip_count, |
| 66 uword address, |
| 67 uintptr_t allocation_size); |
64 | 68 |
65 // SampleThread is called from inside the signal handler and hence it is very | 69 // SampleThread is called from inside the signal handler and hence it is very |
66 // critical that the implementation of SampleThread does not do any of the | 70 // critical that the implementation of SampleThread does not do any of the |
67 // following: | 71 // following: |
68 // * Accessing TLS -- Because on Windows the callback will be running in a | 72 // * Accessing TLS -- Because on Windows the callback will be running in a |
69 // different thread. | 73 // different thread. |
70 // * Allocating memory -- Because this takes locks which may already be | 74 // * Allocating memory -- Because this takes locks which may already be |
71 // held, resulting in a dead lock. | 75 // held, resulting in a dead lock. |
72 // * Taking a lock -- See above. | 76 // * Taking a lock -- See above. |
73 static void SampleThread(Thread* thread, const InterruptedThreadState& state); | 77 static void SampleThread(Thread* thread, const InterruptedThreadState& state); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 virtual bool FilterSample(Sample* sample) { return true; } | 138 virtual bool FilterSample(Sample* sample) { return true; } |
135 | 139 |
136 Dart_Port port() const { return port_; } | 140 Dart_Port port() const { return port_; } |
137 | 141 |
138 // Returns |true| if |sample| passes the time filter. | 142 // Returns |true| if |sample| passes the time filter. |
139 bool TimeFilterSample(Sample* sample); | 143 bool TimeFilterSample(Sample* sample); |
140 | 144 |
141 // Returns |true| if |sample| passes the thread task filter. | 145 // Returns |true| if |sample| passes the thread task filter. |
142 bool TaskFilterSample(Sample* sample); | 146 bool TaskFilterSample(Sample* sample); |
143 | 147 |
| 148 static const intptr_t kNoTaskFilter = -1; |
| 149 |
144 private: | 150 private: |
145 Dart_Port port_; | 151 Dart_Port port_; |
146 intptr_t thread_task_mask_; | 152 intptr_t thread_task_mask_; |
147 int64_t time_origin_micros_; | 153 int64_t time_origin_micros_; |
148 int64_t time_extent_micros_; | 154 int64_t time_extent_micros_; |
149 }; | 155 }; |
150 | 156 |
151 | 157 |
152 class ClearProfileVisitor : public SampleVisitor { | 158 class ClearProfileVisitor : public SampleVisitor { |
153 public: | 159 public: |
(...skipping 22 matching lines...) Expand all Loading... |
176 port_ = ILLEGAL_PORT; | 182 port_ = ILLEGAL_PORT; |
177 pc_marker_ = 0; | 183 pc_marker_ = 0; |
178 for (intptr_t i = 0; i < kStackBufferSizeInWords; i++) { | 184 for (intptr_t i = 0; i < kStackBufferSizeInWords; i++) { |
179 stack_buffer_[i] = 0; | 185 stack_buffer_[i] = 0; |
180 } | 186 } |
181 vm_tag_ = VMTag::kInvalidTagId; | 187 vm_tag_ = VMTag::kInvalidTagId; |
182 user_tag_ = UserTags::kDefaultUserTag; | 188 user_tag_ = UserTags::kDefaultUserTag; |
183 lr_ = 0; | 189 lr_ = 0; |
184 metadata_ = 0; | 190 metadata_ = 0; |
185 state_ = 0; | 191 state_ = 0; |
| 192 native_allocation_address_ = 0; |
| 193 native_allocation_size_bytes_ = 0; |
186 continuation_index_ = -1; | 194 continuation_index_ = -1; |
187 uword* pcs = GetPCArray(); | 195 uword* pcs = GetPCArray(); |
188 for (intptr_t i = 0; i < pcs_length_; i++) { | 196 for (intptr_t i = 0; i < pcs_length_; i++) { |
189 pcs[i] = 0; | 197 pcs[i] = 0; |
190 } | 198 } |
191 set_head_sample(true); | 199 set_head_sample(true); |
192 } | 200 } |
193 | 201 |
194 // Timestamp sample was taken at. | 202 // Timestamp sample was taken at. |
195 int64_t timestamp() const { return timestamp_; } | 203 int64_t timestamp() const { return timestamp_; } |
(...skipping 10 matching lines...) Expand all Loading... |
206 } | 214 } |
207 | 215 |
208 // Set stack trace entry. | 216 // Set stack trace entry. |
209 void SetAt(intptr_t i, uword pc) { | 217 void SetAt(intptr_t i, uword pc) { |
210 ASSERT(i >= 0); | 218 ASSERT(i >= 0); |
211 ASSERT(i < pcs_length_); | 219 ASSERT(i < pcs_length_); |
212 uword* pcs = GetPCArray(); | 220 uword* pcs = GetPCArray(); |
213 pcs[i] = pc; | 221 pcs[i] = pc; |
214 } | 222 } |
215 | 223 |
| 224 void DumpStackTrace() { |
| 225 for (intptr_t i = 0; i < pcs_length_; ++i) { |
| 226 uintptr_t start = 0; |
| 227 uword pc = At(i); |
| 228 char* native_symbol_name = |
| 229 NativeSymbolResolver::LookupSymbolName(pc, &start); |
| 230 if (native_symbol_name == NULL) { |
| 231 OS::PrintErr(" [0x%" Pp "] Unknown symbol\n", pc); |
| 232 } else { |
| 233 OS::PrintErr(" [0x%" Pp "] %s\n", pc, native_symbol_name); |
| 234 NativeSymbolResolver::FreeSymbolName(native_symbol_name); |
| 235 } |
| 236 } |
| 237 } |
| 238 |
216 uword vm_tag() const { return vm_tag_; } | 239 uword vm_tag() const { return vm_tag_; } |
217 void set_vm_tag(uword tag) { | 240 void set_vm_tag(uword tag) { |
218 ASSERT(tag != VMTag::kInvalidTagId); | 241 ASSERT(tag != VMTag::kInvalidTagId); |
219 vm_tag_ = tag; | 242 vm_tag_ = tag; |
220 } | 243 } |
221 | 244 |
222 uword user_tag() const { return user_tag_; } | 245 uword user_tag() const { return user_tag_; } |
223 void set_user_tag(uword tag) { user_tag_ = tag; } | 246 void set_user_tag(uword tag) { user_tag_ = tag; } |
224 | 247 |
225 uword pc_marker() const { return pc_marker_; } | 248 uword pc_marker() const { return pc_marker_; } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 | 295 |
273 bool is_native_allocation_sample() const { | 296 bool is_native_allocation_sample() const { |
274 return NativeAllocationSampleBit::decode(state_); | 297 return NativeAllocationSampleBit::decode(state_); |
275 } | 298 } |
276 | 299 |
277 void set_is_native_allocation_sample(bool native_allocation_sample) { | 300 void set_is_native_allocation_sample(bool native_allocation_sample) { |
278 state_ = | 301 state_ = |
279 NativeAllocationSampleBit::update(native_allocation_sample, state_); | 302 NativeAllocationSampleBit::update(native_allocation_sample, state_); |
280 } | 303 } |
281 | 304 |
| 305 void set_native_allocation_address(uword address) { |
| 306 native_allocation_address_ = address; |
| 307 } |
| 308 |
| 309 uword native_allocation_address() const { return native_allocation_address_; } |
| 310 |
| 311 uintptr_t native_allocation_size_bytes() const { |
| 312 return native_allocation_size_bytes_; |
| 313 } |
| 314 |
| 315 void set_native_allocation_size_bytes(uintptr_t size) { |
| 316 native_allocation_size_bytes_ = size; |
| 317 } |
| 318 |
282 Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); } | 319 Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); } |
283 | 320 |
284 void set_thread_task(Thread::TaskKind task) { | 321 void set_thread_task(Thread::TaskKind task) { |
285 state_ = ThreadTaskBit::update(task, state_); | 322 state_ = ThreadTaskBit::update(task, state_); |
286 } | 323 } |
287 | 324 |
288 bool is_continuation_sample() const { | 325 bool is_continuation_sample() const { |
289 return ContinuationSampleBit::decode(state_); | 326 return ContinuationSampleBit::decode(state_); |
290 } | 327 } |
291 | 328 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
366 int64_t timestamp_; | 403 int64_t timestamp_; |
367 ThreadId tid_; | 404 ThreadId tid_; |
368 Dart_Port port_; | 405 Dart_Port port_; |
369 uword pc_marker_; | 406 uword pc_marker_; |
370 uword stack_buffer_[kStackBufferSizeInWords]; | 407 uword stack_buffer_[kStackBufferSizeInWords]; |
371 uword vm_tag_; | 408 uword vm_tag_; |
372 uword user_tag_; | 409 uword user_tag_; |
373 uword metadata_; | 410 uword metadata_; |
374 uword lr_; | 411 uword lr_; |
375 uword state_; | 412 uword state_; |
| 413 uword native_allocation_address_; |
| 414 uintptr_t native_allocation_size_bytes_; |
376 intptr_t continuation_index_; | 415 intptr_t continuation_index_; |
377 | 416 |
378 /* There are a variable number of words that follow, the words hold the | 417 /* There are a variable number of words that follow, the words hold the |
379 * sampled pc values. Access via GetPCArray() */ | 418 * sampled pc values. Access via GetPCArray() */ |
380 | 419 |
381 DISALLOW_COPY_AND_ASSIGN(Sample); | 420 DISALLOW_COPY_AND_ASSIGN(Sample); |
382 }; | 421 }; |
383 | 422 |
384 | 423 |
| 424 class NativeAllocationSampleFilter : public SampleFilter { |
| 425 public: |
| 426 NativeAllocationSampleFilter(int64_t time_origin_micros, |
| 427 int64_t time_extent_micros) |
| 428 : SampleFilter(ILLEGAL_PORT, |
| 429 SampleFilter::kNoTaskFilter, |
| 430 time_origin_micros, |
| 431 time_extent_micros) {} |
| 432 |
| 433 bool FilterSample(Sample* sample) { |
| 434 if (!sample->is_native_allocation_sample()) { |
| 435 return false; |
| 436 } |
| 437 // If the sample is an allocation sample, we need to check that the |
| 438 // memory at the address hasn't been freed, and if the address associated |
| 439 // with the allocation has been freed and then reissued. |
| 440 void* alloc_address = |
| 441 reinterpret_cast<void*>(sample->native_allocation_address()); |
| 442 Sample* recorded_sample = MallocHooks::GetSample(alloc_address); |
| 443 return (sample == recorded_sample); |
| 444 } |
| 445 }; |
| 446 |
| 447 |
385 // A Code object descriptor. | 448 // A Code object descriptor. |
386 class CodeDescriptor : public ZoneAllocated { | 449 class CodeDescriptor : public ZoneAllocated { |
387 public: | 450 public: |
388 explicit CodeDescriptor(const Code& code); | 451 explicit CodeDescriptor(const Code& code); |
389 | 452 |
390 uword Start() const; | 453 uword Start() const; |
391 | 454 |
392 uword Size() const; | 455 uword Size() const; |
393 | 456 |
394 int64_t CompileTimestamp() const; | 457 int64_t CompileTimestamp() const; |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 // The user tag. | 620 // The user tag. |
558 uword user_tag() const { return user_tag_; } | 621 uword user_tag() const { return user_tag_; } |
559 void set_user_tag(uword tag) { user_tag_ = tag; } | 622 void set_user_tag(uword tag) { user_tag_ = tag; } |
560 | 623 |
561 // The class id if this is an allocation profile sample. -1 otherwise. | 624 // The class id if this is an allocation profile sample. -1 otherwise. |
562 intptr_t allocation_cid() const { return allocation_cid_; } | 625 intptr_t allocation_cid() const { return allocation_cid_; } |
563 void set_allocation_cid(intptr_t cid) { allocation_cid_ = cid; } | 626 void set_allocation_cid(intptr_t cid) { allocation_cid_ = cid; } |
564 | 627 |
565 bool IsAllocationSample() const { return allocation_cid_ > 0; } | 628 bool IsAllocationSample() const { return allocation_cid_ > 0; } |
566 | 629 |
| 630 bool is_native_allocation_sample() const { |
| 631 return native_allocation_size_bytes_ != 0; |
| 632 } |
| 633 |
| 634 uintptr_t native_allocation_size_bytes() const { |
| 635 return native_allocation_size_bytes_; |
| 636 } |
| 637 void set_native_allocation_size_bytes(uintptr_t allocation_size) { |
| 638 native_allocation_size_bytes_ = allocation_size; |
| 639 } |
| 640 |
567 // Was the stack trace truncated? | 641 // Was the stack trace truncated? |
568 bool truncated() const { return truncated_; } | 642 bool truncated() const { return truncated_; } |
569 void set_truncated(bool truncated) { truncated_ = truncated; } | 643 void set_truncated(bool truncated) { truncated_ = truncated; } |
570 | 644 |
571 // Was the first frame in the stack trace executing? | 645 // Was the first frame in the stack trace executing? |
572 bool first_frame_executing() const { return first_frame_executing_; } | 646 bool first_frame_executing() const { return first_frame_executing_; } |
573 void set_first_frame_executing(bool first_frame_executing) { | 647 void set_first_frame_executing(bool first_frame_executing) { |
574 first_frame_executing_ = first_frame_executing; | 648 first_frame_executing_ = first_frame_executing; |
575 } | 649 } |
576 | 650 |
(...skipping 14 matching lines...) Expand all Loading... |
591 uword* stack_buffer); | 665 uword* stack_buffer); |
592 | 666 |
593 ZoneGrowableArray<uword> pcs_; | 667 ZoneGrowableArray<uword> pcs_; |
594 int64_t timestamp_; | 668 int64_t timestamp_; |
595 ThreadId tid_; | 669 ThreadId tid_; |
596 uword vm_tag_; | 670 uword vm_tag_; |
597 uword user_tag_; | 671 uword user_tag_; |
598 intptr_t allocation_cid_; | 672 intptr_t allocation_cid_; |
599 bool truncated_; | 673 bool truncated_; |
600 bool first_frame_executing_; | 674 bool first_frame_executing_; |
| 675 uword native_allocation_address_; |
| 676 uintptr_t native_allocation_size_bytes_; |
601 ProfileTrieNode* timeline_trie_; | 677 ProfileTrieNode* timeline_trie_; |
602 | 678 |
603 friend class SampleBuffer; | 679 friend class SampleBuffer; |
604 DISALLOW_COPY_AND_ASSIGN(ProcessedSample); | 680 DISALLOW_COPY_AND_ASSIGN(ProcessedSample); |
605 }; | 681 }; |
606 | 682 |
607 | 683 |
608 // A collection of |ProcessedSample|s. | 684 // A collection of |ProcessedSample|s. |
609 class ProcessedSampleBuffer : public ZoneAllocated { | 685 class ProcessedSampleBuffer : public ZoneAllocated { |
610 public: | 686 public: |
(...skipping 12 matching lines...) Expand all Loading... |
623 private: | 699 private: |
624 ZoneGrowableArray<ProcessedSample*> samples_; | 700 ZoneGrowableArray<ProcessedSample*> samples_; |
625 CodeLookupTable* code_lookup_table_; | 701 CodeLookupTable* code_lookup_table_; |
626 | 702 |
627 DISALLOW_COPY_AND_ASSIGN(ProcessedSampleBuffer); | 703 DISALLOW_COPY_AND_ASSIGN(ProcessedSampleBuffer); |
628 }; | 704 }; |
629 | 705 |
630 } // namespace dart | 706 } // namespace dart |
631 | 707 |
632 #endif // RUNTIME_VM_PROFILER_H_ | 708 #endif // RUNTIME_VM_PROFILER_H_ |
OLD | NEW |