OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 <cstdlib> | 5 #include <cstdlib> |
6 | 6 |
7 #include "vm/atomic.h" | 7 #include "vm/atomic.h" |
8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
9 #include "vm/json_stream.h" | 9 #include "vm/json_stream.h" |
10 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
| 11 #include "vm/log.h" |
11 #include "vm/object.h" | 12 #include "vm/object.h" |
12 #include "vm/thread.h" | 13 #include "vm/thread.h" |
13 #include "vm/timeline.h" | 14 #include "vm/timeline.h" |
14 | 15 |
15 namespace dart { | 16 namespace dart { |
16 | 17 |
17 DEFINE_FLAG(bool, trace_timeline, false, "Trace timeline backend"); | |
18 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 18 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
19 | 19 DEFINE_FLAG(bool, trace_timeline, false, |
| 20 "Trace timeline backend"); |
| 21 DEFINE_FLAG(bool, trace_timeline_analysis, false, |
| 22 "Trace timeline analysis backend"); |
| 23 DEFINE_FLAG(bool, timing, false, |
| 24 "Dump isolate timing information from timeline."); |
20 DEFINE_FLAG(charp, timeline_dir, NULL, | 25 DEFINE_FLAG(charp, timeline_dir, NULL, |
21 "Enable all timeline trace streams and output VM global trace " | 26 "Enable all timeline trace streams and output VM global trace " |
22 "into specified directory."); | 27 "into specified directory."); |
23 | 28 |
24 void Timeline::InitOnce() { | 29 void Timeline::InitOnce() { |
25 ASSERT(recorder_ == NULL); | 30 ASSERT(recorder_ == NULL); |
26 // Default to ring recorder being enabled. | 31 // Default to ring recorder being enabled. |
27 const bool use_ring_recorder = true; | 32 const bool use_ring_recorder = true; |
28 // Some flags require that we use the endless recorder. | 33 // Some flags require that we use the endless recorder. |
29 const bool use_endless_recorder = (FLAG_timeline_dir != NULL); | 34 const bool use_endless_recorder = |
| 35 (FLAG_timeline_dir != NULL) || FLAG_timing; |
30 if (use_endless_recorder) { | 36 if (use_endless_recorder) { |
31 recorder_ = new TimelineEventEndlessRecorder(); | 37 recorder_ = new TimelineEventEndlessRecorder(); |
32 } else if (use_ring_recorder) { | 38 } else if (use_ring_recorder) { |
33 recorder_ = new TimelineEventRingRecorder(); | 39 recorder_ = new TimelineEventRingRecorder(); |
34 } | 40 } |
35 vm_stream_ = new TimelineStream(); | 41 vm_stream_ = new TimelineStream(); |
36 vm_stream_->Init("VM", EnableStreamByDefault("VM")); | 42 vm_stream_->Init("VM", EnableStreamByDefault("VM")); |
37 } | 43 } |
38 | 44 |
39 | 45 |
40 void Timeline::Shutdown() { | 46 void Timeline::Shutdown() { |
41 ASSERT(recorder_ != NULL); | 47 ASSERT(recorder_ != NULL); |
42 if (FLAG_timeline_dir != NULL) { | 48 if (FLAG_timeline_dir != NULL) { |
43 recorder_->WriteTo(FLAG_timeline_dir); | 49 recorder_->WriteTo(FLAG_timeline_dir); |
44 } | 50 } |
45 delete recorder_; | 51 delete recorder_; |
46 recorder_ = NULL; | 52 recorder_ = NULL; |
47 delete vm_stream_; | 53 delete vm_stream_; |
48 vm_stream_ = NULL; | 54 vm_stream_ = NULL; |
49 } | 55 } |
50 | 56 |
51 | 57 |
52 TimelineEventRecorder* Timeline::recorder() { | 58 TimelineEventRecorder* Timeline::recorder() { |
53 return recorder_; | 59 return recorder_; |
54 } | 60 } |
55 | 61 |
56 | 62 |
57 bool Timeline::EnableStreamByDefault(const char* stream_name) { | 63 bool Timeline::EnableStreamByDefault(const char* stream_name) { |
58 // TODO(johnmccutchan): Allow for command line control over streams. | 64 // TODO(johnmccutchan): Allow for command line control over streams. |
59 return FLAG_timeline_dir != NULL; | 65 return (FLAG_timeline_dir != NULL) || FLAG_timing; |
60 } | 66 } |
61 | 67 |
62 | 68 |
63 TimelineStream* Timeline::GetVMStream() { | 69 TimelineStream* Timeline::GetVMStream() { |
64 ASSERT(vm_stream_ != NULL); | 70 ASSERT(vm_stream_ != NULL); |
65 return vm_stream_; | 71 return vm_stream_; |
66 } | 72 } |
67 | 73 |
68 | 74 |
69 TimelineEventRecorder* Timeline::recorder_ = NULL; | 75 TimelineEventRecorder* Timeline::recorder_ = NULL; |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 ASSERT(!thread_block->IsFull()); | 409 ASSERT(!thread_block->IsFull()); |
404 return thread_block->StartEvent(); | 410 return thread_block->StartEvent(); |
405 } | 411 } |
406 return NULL; | 412 return NULL; |
407 } | 413 } |
408 | 414 |
409 | 415 |
410 | 416 |
411 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() { | 417 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() { |
412 MutexLocker ml(&lock_); | 418 MutexLocker ml(&lock_); |
| 419 if (FLAG_trace_timeline) { |
| 420 OS::Print("GlobalBlockStartEvent in block %p for thread %" Px "\n", |
| 421 global_block_, OSThread::CurrentCurrentThreadIdAsIntPtr()); |
| 422 } |
413 if ((global_block_ != NULL) && global_block_->IsFull()) { | 423 if ((global_block_ != NULL) && global_block_->IsFull()) { |
414 // Global block is full. | 424 // Global block is full. |
415 global_block_->Finish(); | 425 global_block_->Finish(); |
416 global_block_ = NULL; | 426 global_block_ = NULL; |
417 } | 427 } |
418 if (global_block_ == NULL) { | 428 if (global_block_ == NULL) { |
419 // Allocate a new block. | 429 // Allocate a new block. |
420 global_block_ = GetNewBlockLocked(NULL); | 430 global_block_ = GetNewBlockLocked(NULL); |
| 431 ASSERT(global_block_ != NULL); |
421 } | 432 } |
422 if (global_block_ != NULL) { | 433 if (global_block_ != NULL) { |
423 ASSERT(!global_block_->IsFull()); | 434 ASSERT(!global_block_->IsFull()); |
424 return global_block_->StartEvent(); | 435 return global_block_->StartEvent(); |
425 } | 436 } |
426 return NULL; | 437 return NULL; |
427 } | 438 } |
428 | 439 |
429 | 440 |
430 void TimelineEventRecorder::WriteTo(const char* directory) { | 441 void TimelineEventRecorder::WriteTo(const char* directory) { |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 | 636 |
626 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { | 637 void TimelineEventStreamingRecorder::CompleteEvent(TimelineEvent* event) { |
627 StreamEvent(event); | 638 StreamEvent(event); |
628 delete event; | 639 delete event; |
629 } | 640 } |
630 | 641 |
631 | 642 |
632 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() | 643 TimelineEventEndlessRecorder::TimelineEventEndlessRecorder() |
633 : head_(NULL), | 644 : head_(NULL), |
634 block_index_(0) { | 645 block_index_(0) { |
635 GetNewBlock(); | |
636 } | 646 } |
637 | 647 |
638 | 648 |
639 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, | 649 void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, |
640 TimelineEventFilter* filter) { | 650 TimelineEventFilter* filter) { |
641 MutexLocker ml(&lock_); | 651 MutexLocker ml(&lock_); |
642 JSONObject topLevel(js); | 652 JSONObject topLevel(js); |
643 topLevel.AddProperty("type", "_Timeline"); | 653 topLevel.AddProperty("type", "_Timeline"); |
644 { | 654 { |
645 JSONArray events(&topLevel, "traceEvents"); | 655 JSONArray events(&topLevel, "traceEvents"); |
(...skipping 17 matching lines...) Expand all Loading... |
663 // no-op. | 673 // no-op. |
664 } | 674 } |
665 | 675 |
666 | 676 |
667 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( | 677 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( |
668 Isolate* isolate) { | 678 Isolate* isolate) { |
669 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); | 679 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); |
670 block->set_next(head_); | 680 block->set_next(head_); |
671 block->Open(isolate); | 681 block->Open(isolate); |
672 head_ = block; | 682 head_ = block; |
| 683 if (FLAG_trace_timeline) { |
| 684 if (isolate != NULL) { |
| 685 OS::Print("Created new isolate block %p for %s\n", |
| 686 block, isolate->name()); |
| 687 } else { |
| 688 OS::Print("Created new global block %p\n", block); |
| 689 } |
| 690 } |
673 return head_; | 691 return head_; |
674 } | 692 } |
675 | 693 |
676 | 694 |
677 void TimelineEventEndlessRecorder::PrintJSONEvents( | 695 void TimelineEventEndlessRecorder::PrintJSONEvents( |
678 JSONArray* events, | 696 JSONArray* events, |
679 TimelineEventFilter* filter) const { | 697 TimelineEventFilter* filter) const { |
680 TimelineEventBlock* current = head_; | 698 TimelineEventBlock* current = head_; |
681 | 699 |
682 while (current != NULL) { | 700 while (current != NULL) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
718 } | 736 } |
719 | 737 |
720 | 738 |
721 TimelineEventBlock::~TimelineEventBlock() { | 739 TimelineEventBlock::~TimelineEventBlock() { |
722 Reset(); | 740 Reset(); |
723 } | 741 } |
724 | 742 |
725 | 743 |
726 TimelineEvent* TimelineEventBlock::StartEvent() { | 744 TimelineEvent* TimelineEventBlock::StartEvent() { |
727 ASSERT(!IsFull()); | 745 ASSERT(!IsFull()); |
| 746 if (FLAG_trace_timeline) { |
| 747 OS::Print("StartEvent in block %p for thread %" Px "\n", |
| 748 this, OSThread::CurrentCurrentThreadIdAsIntPtr()); |
| 749 } |
728 return &events_[length_++]; | 750 return &events_[length_++]; |
729 } | 751 } |
730 | 752 |
731 | 753 |
732 ThreadId TimelineEventBlock::thread() const { | 754 ThreadId TimelineEventBlock::thread() const { |
733 ASSERT(length_ > 0); | 755 ASSERT(length_ > 0); |
734 return events_[0].thread(); | 756 return events_[0].thread(); |
735 } | 757 } |
736 | 758 |
737 | 759 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
778 } | 800 } |
779 | 801 |
780 | 802 |
781 void TimelineEventBlock::Open(Isolate* isolate) { | 803 void TimelineEventBlock::Open(Isolate* isolate) { |
782 isolate_ = isolate; | 804 isolate_ = isolate; |
783 open_ = true; | 805 open_ = true; |
784 } | 806 } |
785 | 807 |
786 | 808 |
787 void TimelineEventBlock::Finish() { | 809 void TimelineEventBlock::Finish() { |
| 810 if (FLAG_trace_timeline) { |
| 811 OS::Print("Finish block %p\n", this); |
| 812 } |
788 open_ = false; | 813 open_ = false; |
789 } | 814 } |
790 | 815 |
791 | 816 |
792 TimelineEventBlockIterator::TimelineEventBlockIterator( | 817 TimelineEventBlockIterator::TimelineEventBlockIterator( |
793 TimelineEventRecorder* recorder) | 818 TimelineEventRecorder* recorder) |
794 : current_(NULL), | 819 : current_(NULL), |
795 recorder_(NULL) { | 820 recorder_(NULL) { |
796 Reset(recorder); | 821 Reset(recorder); |
797 } | 822 } |
(...skipping 28 matching lines...) Expand all Loading... |
826 | 851 |
827 | 852 |
828 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 853 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
829 ASSERT(current_ != NULL); | 854 ASSERT(current_ != NULL); |
830 TimelineEventBlock* r = current_; | 855 TimelineEventBlock* r = current_; |
831 current_ = current_->next(); | 856 current_ = current_->next(); |
832 return r; | 857 return r; |
833 } | 858 } |
834 | 859 |
835 } // namespace dart | 860 } // namespace dart |
OLD | NEW |