Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: runtime/vm/profiler.h

Issue 2966593002: Updated native memory allocation profiling to use its own sample buffer instead of sharing a sample… (Closed)
Patch Set: Updated native memory allocation profiling to use its own sample buffer instead of sharing a sample… Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/malloc_hooks_test.cc ('k') | runtime/vm/profiler.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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" 13 #include "vm/malloc_hooks.h"
14 #include "vm/native_symbol.h" 14 #include "vm/native_symbol.h"
15 #include "vm/object.h" 15 #include "vm/object.h"
16 #include "vm/tags.h" 16 #include "vm/tags.h"
17 #include "vm/thread_interrupter.h" 17 #include "vm/thread_interrupter.h"
18 18
19 // Profiler sampling and stack walking support. 19 // Profiler sampling and stack walking support.
20 // NOTE: For service related code, see profile_service.h. 20 // NOTE: For service related code, see profile_service.h.
21 21
22 namespace dart { 22 namespace dart {
23 23
24 // Forward declarations. 24 // Forward declarations.
25 class ProcessedSample; 25 class ProcessedSample;
26 class ProcessedSampleBuffer; 26 class ProcessedSampleBuffer;
27 27
28 class Sample; 28 class Sample;
29 class AllocationSampleBuffer;
29 class SampleBuffer; 30 class SampleBuffer;
30 class ProfileTrieNode; 31 class ProfileTrieNode;
31 32
32 struct ProfilerCounters { 33 struct ProfilerCounters {
33 // Count of bail out reasons: 34 // Count of bail out reasons:
34 int64_t bail_out_unknown_task; 35 int64_t bail_out_unknown_task;
35 int64_t bail_out_jump_to_exception_handler; 36 int64_t bail_out_jump_to_exception_handler;
36 int64_t bail_out_check_isolate; 37 int64_t bail_out_check_isolate;
37 // Count of single frame sampling reasons: 38 // Count of single frame sampling reasons:
38 int64_t single_frame_sample_deoptimizing; 39 int64_t single_frame_sample_deoptimizing;
39 int64_t single_frame_sample_register_check; 40 int64_t single_frame_sample_register_check;
40 int64_t single_frame_sample_get_and_validate_stack_bounds; 41 int64_t single_frame_sample_get_and_validate_stack_bounds;
41 // Count of stack walkers used: 42 // Count of stack walkers used:
42 int64_t stack_walker_native; 43 int64_t stack_walker_native;
43 int64_t stack_walker_dart_exit; 44 int64_t stack_walker_dart_exit;
44 int64_t stack_walker_dart; 45 int64_t stack_walker_dart;
45 int64_t stack_walker_none; 46 int64_t stack_walker_none;
46 // Count of failed checks: 47 // Count of failed checks:
47 int64_t failure_native_allocation_sample; 48 int64_t failure_native_allocation_sample;
48 }; 49 };
49 50
50 51
51 class Profiler : public AllStatic { 52 class Profiler : public AllStatic {
52 public: 53 public:
53 static void InitOnce(); 54 static void InitOnce();
55 static void InitAllocationSampleBuffer();
54 static void Shutdown(); 56 static void Shutdown();
55 57
56 static void SetSampleDepth(intptr_t depth); 58 static void SetSampleDepth(intptr_t depth);
57 static void SetSamplePeriod(intptr_t period); 59 static void SetSamplePeriod(intptr_t period);
58 60
59 static SampleBuffer* sample_buffer() { return sample_buffer_; } 61 static SampleBuffer* sample_buffer() { return sample_buffer_; }
62 static AllocationSampleBuffer* allocation_sample_buffer() {
63 return allocation_sample_buffer_;
64 }
60 65
61 static void DumpStackTrace(void* context); 66 static void DumpStackTrace(void* context);
62 static void DumpStackTrace(bool for_crash = true); 67 static void DumpStackTrace(bool for_crash = true);
63 68
64 static void SampleAllocation(Thread* thread, intptr_t cid); 69 static void SampleAllocation(Thread* thread, intptr_t cid);
65 static Sample* SampleNativeAllocation(intptr_t skip_count, 70 static Sample* SampleNativeAllocation(intptr_t skip_count,
66 uword address, 71 uword address,
67 uintptr_t allocation_size); 72 uintptr_t allocation_size);
68 73
69 // SampleThread is called from inside the signal handler and hence it is very 74 // SampleThread is called from inside the signal handler and hence it is very
(...skipping 12 matching lines...) Expand all
82 } 87 }
83 88
84 private: 89 private:
85 static void DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash); 90 static void DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash);
86 91
87 // Does not walk the thread's stack. 92 // Does not walk the thread's stack.
88 static void SampleThreadSingleFrame(Thread* thread, uintptr_t pc); 93 static void SampleThreadSingleFrame(Thread* thread, uintptr_t pc);
89 static bool initialized_; 94 static bool initialized_;
90 95
91 static SampleBuffer* sample_buffer_; 96 static SampleBuffer* sample_buffer_;
97 static AllocationSampleBuffer* allocation_sample_buffer_;
92 98
93 static ProfilerCounters counters_; 99 static ProfilerCounters counters_;
94 100
95 friend class Thread; 101 friend class Thread;
96 }; 102 };
97 103
98 104
99 class SampleVisitor : public ValueObject { 105 class SampleVisitor : public ValueObject {
100 public: 106 public:
101 explicit SampleVisitor(Dart_Port port) : port_(port), visited_(0) {} 107 explicit SampleVisitor(Dart_Port port) : port_(port), visited_(0) {}
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
185 stack_buffer_[i] = 0; 191 stack_buffer_[i] = 0;
186 } 192 }
187 vm_tag_ = VMTag::kInvalidTagId; 193 vm_tag_ = VMTag::kInvalidTagId;
188 user_tag_ = UserTags::kDefaultUserTag; 194 user_tag_ = UserTags::kDefaultUserTag;
189 lr_ = 0; 195 lr_ = 0;
190 metadata_ = 0; 196 metadata_ = 0;
191 state_ = 0; 197 state_ = 0;
192 native_allocation_address_ = 0; 198 native_allocation_address_ = 0;
193 native_allocation_size_bytes_ = 0; 199 native_allocation_size_bytes_ = 0;
194 continuation_index_ = -1; 200 continuation_index_ = -1;
201 next_free_ = NULL;
195 uword* pcs = GetPCArray(); 202 uword* pcs = GetPCArray();
196 for (intptr_t i = 0; i < pcs_length_; i++) { 203 for (intptr_t i = 0; i < pcs_length_; i++) {
197 pcs[i] = 0; 204 pcs[i] = 0;
198 } 205 }
199 set_head_sample(true); 206 set_head_sample(true);
200 } 207 }
201 208
202 // Timestamp sample was taken at. 209 // Timestamp sample was taken at.
203 int64_t timestamp() const { return timestamp_; } 210 int64_t timestamp() const { return timestamp_; }
204 211
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
286 } 293 }
287 294
288 bool is_allocation_sample() const { 295 bool is_allocation_sample() const {
289 return ClassAllocationSampleBit::decode(state_); 296 return ClassAllocationSampleBit::decode(state_);
290 } 297 }
291 298
292 void set_is_allocation_sample(bool allocation_sample) { 299 void set_is_allocation_sample(bool allocation_sample) {
293 state_ = ClassAllocationSampleBit::update(allocation_sample, state_); 300 state_ = ClassAllocationSampleBit::update(allocation_sample, state_);
294 } 301 }
295 302
296 bool is_native_allocation_sample() const { 303 uword native_allocation_address() const { return native_allocation_address_; }
297 return NativeAllocationSampleBit::decode(state_);
298 }
299
300 void set_is_native_allocation_sample(bool native_allocation_sample) {
301 state_ =
302 NativeAllocationSampleBit::update(native_allocation_sample, state_);
303 }
304 304
305 void set_native_allocation_address(uword address) { 305 void set_native_allocation_address(uword address) {
306 native_allocation_address_ = address; 306 native_allocation_address_ = address;
307 } 307 }
308 308
309 uword native_allocation_address() const { return native_allocation_address_; }
310
311 uintptr_t native_allocation_size_bytes() const { 309 uintptr_t native_allocation_size_bytes() const {
312 return native_allocation_size_bytes_; 310 return native_allocation_size_bytes_;
313 } 311 }
314 312
315 void set_native_allocation_size_bytes(uintptr_t size) { 313 void set_native_allocation_size_bytes(uintptr_t size) {
316 native_allocation_size_bytes_ = size; 314 native_allocation_size_bytes_ = size;
317 } 315 }
318 316
317 Sample* next_free() const { return next_free_; }
318 void set_next_free(Sample* next_free) { next_free_ = next_free; }
319
319 Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); } 320 Thread::TaskKind thread_task() const { return ThreadTaskBit::decode(state_); }
320 321
321 void set_thread_task(Thread::TaskKind task) { 322 void set_thread_task(Thread::TaskKind task) {
322 state_ = ThreadTaskBit::update(task, state_); 323 state_ = ThreadTaskBit::update(task, state_);
323 } 324 }
324 325
325 bool is_continuation_sample() const { 326 bool is_continuation_sample() const {
326 return ContinuationSampleBit::decode(state_); 327 return ContinuationSampleBit::decode(state_);
327 } 328 }
328 329
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 enum StateBits { 373 enum StateBits {
373 kHeadSampleBit = 0, 374 kHeadSampleBit = 0,
374 kLeafFrameIsDartBit = 1, 375 kLeafFrameIsDartBit = 1,
375 kIgnoreBit = 2, 376 kIgnoreBit = 2,
376 kExitFrameBit = 3, 377 kExitFrameBit = 3,
377 kMissingFrameInsertedBit = 4, 378 kMissingFrameInsertedBit = 4,
378 kTruncatedTraceBit = 5, 379 kTruncatedTraceBit = 5,
379 kClassAllocationSampleBit = 6, 380 kClassAllocationSampleBit = 6,
380 kContinuationSampleBit = 7, 381 kContinuationSampleBit = 7,
381 kThreadTaskBit = 8, // 5 bits. 382 kThreadTaskBit = 8, // 5 bits.
382 kNativeAllocationSampleBit = 13, 383 kNextFreeBit = 13,
383 kNextFreeBit = 14,
384 }; 384 };
385 class HeadSampleBit : public BitField<uword, bool, kHeadSampleBit, 1> {}; 385 class HeadSampleBit : public BitField<uword, bool, kHeadSampleBit, 1> {};
386 class LeafFrameIsDart : public BitField<uword, bool, kLeafFrameIsDartBit, 1> { 386 class LeafFrameIsDart : public BitField<uword, bool, kLeafFrameIsDartBit, 1> {
387 }; 387 };
388 class IgnoreBit : public BitField<uword, bool, kIgnoreBit, 1> {}; 388 class IgnoreBit : public BitField<uword, bool, kIgnoreBit, 1> {};
389 class ExitFrameBit : public BitField<uword, bool, kExitFrameBit, 1> {}; 389 class ExitFrameBit : public BitField<uword, bool, kExitFrameBit, 1> {};
390 class MissingFrameInsertedBit 390 class MissingFrameInsertedBit
391 : public BitField<uword, bool, kMissingFrameInsertedBit, 1> {}; 391 : public BitField<uword, bool, kMissingFrameInsertedBit, 1> {};
392 class TruncatedTraceBit 392 class TruncatedTraceBit
393 : public BitField<uword, bool, kTruncatedTraceBit, 1> {}; 393 : public BitField<uword, bool, kTruncatedTraceBit, 1> {};
394 class ClassAllocationSampleBit 394 class ClassAllocationSampleBit
395 : public BitField<uword, bool, kClassAllocationSampleBit, 1> {}; 395 : public BitField<uword, bool, kClassAllocationSampleBit, 1> {};
396 class ContinuationSampleBit 396 class ContinuationSampleBit
397 : public BitField<uword, bool, kContinuationSampleBit, 1> {}; 397 : public BitField<uword, bool, kContinuationSampleBit, 1> {};
398 class ThreadTaskBit 398 class ThreadTaskBit
399 : public BitField<uword, Thread::TaskKind, kThreadTaskBit, 5> {}; 399 : public BitField<uword, Thread::TaskKind, kThreadTaskBit, 5> {};
400 class NativeAllocationSampleBit
401 : public BitField<uword, bool, kNativeAllocationSampleBit, 1> {};
402 400
403 int64_t timestamp_; 401 int64_t timestamp_;
404 ThreadId tid_; 402 ThreadId tid_;
405 Dart_Port port_; 403 Dart_Port port_;
406 uword pc_marker_; 404 uword pc_marker_;
407 uword stack_buffer_[kStackBufferSizeInWords]; 405 uword stack_buffer_[kStackBufferSizeInWords];
408 uword vm_tag_; 406 uword vm_tag_;
409 uword user_tag_; 407 uword user_tag_;
410 uword metadata_; 408 uword metadata_;
411 uword lr_; 409 uword lr_;
412 uword state_; 410 uword state_;
413 uword native_allocation_address_; 411 uword native_allocation_address_;
414 uintptr_t native_allocation_size_bytes_; 412 uintptr_t native_allocation_size_bytes_;
415 intptr_t continuation_index_; 413 intptr_t continuation_index_;
414 Sample* next_free_;
416 415
417 /* There are a variable number of words that follow, the words hold the 416 /* There are a variable number of words that follow, the words hold the
418 * sampled pc values. Access via GetPCArray() */ 417 * sampled pc values. Access via GetPCArray() */
419
420 DISALLOW_COPY_AND_ASSIGN(Sample); 418 DISALLOW_COPY_AND_ASSIGN(Sample);
421 }; 419 };
422 420
423 421
424 class NativeAllocationSampleFilter : public SampleFilter { 422 class NativeAllocationSampleFilter : public SampleFilter {
425 public: 423 public:
426 NativeAllocationSampleFilter(int64_t time_origin_micros, 424 NativeAllocationSampleFilter(int64_t time_origin_micros,
427 int64_t time_extent_micros) 425 int64_t time_extent_micros)
428 : SampleFilter(ILLEGAL_PORT, 426 : SampleFilter(ILLEGAL_PORT,
429 SampleFilter::kNoTaskFilter, 427 SampleFilter::kNoTaskFilter,
430 time_origin_micros, 428 time_origin_micros,
431 time_extent_micros) {} 429 time_extent_micros) {}
432 430
433 bool FilterSample(Sample* sample) { 431 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 432 // 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 433 // memory at the address hasn't been freed, and if the address associated
439 // with the allocation has been freed and then reissued. 434 // with the allocation has been freed and then reissued.
440 void* alloc_address = 435 void* alloc_address =
441 reinterpret_cast<void*>(sample->native_allocation_address()); 436 reinterpret_cast<void*>(sample->native_allocation_address());
437 ASSERT(alloc_address != NULL);
442 Sample* recorded_sample = MallocHooks::GetSample(alloc_address); 438 Sample* recorded_sample = MallocHooks::GetSample(alloc_address);
443 return (sample == recorded_sample); 439 return (sample == recorded_sample);
444 } 440 }
445 }; 441 };
446 442
447 443
448 // A Code object descriptor. 444 // A Code object descriptor.
449 class CodeDescriptor : public ZoneAllocated { 445 class CodeDescriptor : public ZoneAllocated {
450 public: 446 public:
451 explicit CodeDescriptor(const Code& code); 447 explicit CodeDescriptor(const Code& code);
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 DISALLOW_COPY_AND_ASSIGN(CodeLookupTable); 510 DISALLOW_COPY_AND_ASSIGN(CodeLookupTable);
515 }; 511 };
516 512
517 513
518 // Ring buffer of Samples that is (usually) shared by many isolates. 514 // Ring buffer of Samples that is (usually) shared by many isolates.
519 class SampleBuffer { 515 class SampleBuffer {
520 public: 516 public:
521 static const intptr_t kDefaultBufferCapacity = 120000; // 2 minutes @ 1000hz. 517 static const intptr_t kDefaultBufferCapacity = 120000; // 2 minutes @ 1000hz.
522 518
523 explicit SampleBuffer(intptr_t capacity = kDefaultBufferCapacity); 519 explicit SampleBuffer(intptr_t capacity = kDefaultBufferCapacity);
524 ~SampleBuffer(); 520 virtual ~SampleBuffer();
525 521
526 intptr_t capacity() const { return capacity_; } 522 intptr_t capacity() const { return capacity_; }
527 523
528 Sample* At(intptr_t idx) const; 524 Sample* At(intptr_t idx) const;
529 intptr_t ReserveSampleSlot(); 525 intptr_t ReserveSampleSlot();
530 Sample* ReserveSample(); 526 virtual Sample* ReserveSample();
531 Sample* ReserveSampleAndLink(Sample* previous); 527 virtual Sample* ReserveSampleAndLink(Sample* previous);
532 528
533 void VisitSamples(SampleVisitor* visitor) { 529 void VisitSamples(SampleVisitor* visitor) {
534 ASSERT(visitor != NULL); 530 ASSERT(visitor != NULL);
535 const intptr_t length = capacity(); 531 const intptr_t length = capacity();
536 for (intptr_t i = 0; i < length; i++) { 532 for (intptr_t i = 0; i < length; i++) {
537 Sample* sample = At(i); 533 Sample* sample = At(i);
538 if (!sample->head_sample()) { 534 if (!sample->head_sample()) {
539 // An inner sample in a chain of samples. 535 // An inner sample in a chain of samples.
540 continue; 536 continue;
541 } 537 }
(...skipping 13 matching lines...) Expand all
555 // No frames. 551 // No frames.
556 continue; 552 continue;
557 } 553 }
558 visitor->IncrementVisited(); 554 visitor->IncrementVisited();
559 visitor->VisitSample(sample); 555 visitor->VisitSample(sample);
560 } 556 }
561 } 557 }
562 558
563 ProcessedSampleBuffer* BuildProcessedSampleBuffer(SampleFilter* filter); 559 ProcessedSampleBuffer* BuildProcessedSampleBuffer(SampleFilter* filter);
564 560
565 private: 561 protected:
566 ProcessedSample* BuildProcessedSample(Sample* sample, 562 ProcessedSample* BuildProcessedSample(Sample* sample,
567 const CodeLookupTable& clt); 563 const CodeLookupTable& clt);
568 Sample* Next(Sample* sample); 564 Sample* Next(Sample* sample);
569 565
570 VirtualMemory* memory_; 566 VirtualMemory* memory_;
571 Sample* samples_; 567 Sample* samples_;
572 intptr_t capacity_; 568 intptr_t capacity_;
573 uintptr_t cursor_; 569 uintptr_t cursor_;
574 570
571 private:
575 DISALLOW_COPY_AND_ASSIGN(SampleBuffer); 572 DISALLOW_COPY_AND_ASSIGN(SampleBuffer);
576 }; 573 };
577 574
578 575
576 class AllocationSampleBuffer : public SampleBuffer {
577 public:
578 explicit AllocationSampleBuffer(intptr_t capacity = kDefaultBufferCapacity);
579 virtual ~AllocationSampleBuffer();
580
581 intptr_t ReserveSampleSlotLocked();
582 virtual Sample* ReserveSample();
583 virtual Sample* ReserveSampleAndLink(Sample* previous);
584 void FreeAllocationSample(Sample* sample);
585
586 private:
587 Mutex* mutex_;
588 Sample* free_sample_list_;
589
590 DISALLOW_COPY_AND_ASSIGN(AllocationSampleBuffer);
591 };
592
593
579 // A |ProcessedSample| is a combination of 1 (or more) |Sample|(s) that have 594 // A |ProcessedSample| is a combination of 1 (or more) |Sample|(s) that have
580 // been merged into a logical sample. The raw data may have been processed to 595 // been merged into a logical sample. The raw data may have been processed to
581 // improve the quality of the stack trace. 596 // improve the quality of the stack trace.
582 class ProcessedSample : public ZoneAllocated { 597 class ProcessedSample : public ZoneAllocated {
583 public: 598 public:
584 ProcessedSample(); 599 ProcessedSample();
585 600
586 // Add |pc| to stack trace. 601 // Add |pc| to stack trace.
587 void Add(uword pc) { pcs_.Add(pc); } 602 void Add(uword pc) { pcs_.Add(pc); }
588 603
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
692 private: 707 private:
693 ZoneGrowableArray<ProcessedSample*> samples_; 708 ZoneGrowableArray<ProcessedSample*> samples_;
694 CodeLookupTable* code_lookup_table_; 709 CodeLookupTable* code_lookup_table_;
695 710
696 DISALLOW_COPY_AND_ASSIGN(ProcessedSampleBuffer); 711 DISALLOW_COPY_AND_ASSIGN(ProcessedSampleBuffer);
697 }; 712 };
698 713
699 } // namespace dart 714 } // namespace dart
700 715
701 #endif // RUNTIME_VM_PROFILER_H_ 716 #endif // RUNTIME_VM_PROFILER_H_
OLDNEW
« no previous file with comments | « runtime/vm/malloc_hooks_test.cc ('k') | runtime/vm/profiler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698