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" |
(...skipping 12 matching lines...) Expand all Loading... |
23 DEFINE_FLAG(bool, timing, false, | 23 DEFINE_FLAG(bool, timing, false, |
24 "Dump isolate timing information from timeline."); | 24 "Dump isolate timing information from timeline."); |
25 DEFINE_FLAG(charp, timeline_dir, NULL, | 25 DEFINE_FLAG(charp, timeline_dir, NULL, |
26 "Enable all timeline trace streams and output VM global trace " | 26 "Enable all timeline trace streams and output VM global trace " |
27 "into specified directory."); | 27 "into specified directory."); |
28 | 28 |
29 // Implementation notes: | 29 // Implementation notes: |
30 // | 30 // |
31 // Writing events: | 31 // Writing events: |
32 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches | 32 // |TimelineEvent|s are written into |TimelineEventBlock|s. Each |Thread| caches |
33 // a |TimelineEventBlock| in TLS so that it can write events without | 33 // a |TimelineEventBlock| object so that it can write events without |
34 // synchronizing with other threads in the system. Even though the |Thread| owns | 34 // synchronizing with other threads in the system. Even though the |Thread| owns |
35 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting | 35 // the |TimelineEventBlock| the block may need to be reclaimed by the reporting |
36 // system. To support that, a |Thread| must hold its |timeline_block_lock_| | 36 // system. To support that, a |Thread| must hold its |timeline_block_lock_| |
37 // when operating on the |TimelineEventBlock|. This lock will only ever be | 37 // when operating on the |TimelineEventBlock|. This lock will only ever be |
38 // busy if blocks are being reclaimed by the reporting system. | 38 // busy if blocks are being reclaimed by the reporting system. |
39 // | 39 // |
40 // Reporting: | 40 // Reporting: |
41 // When requested, the timeline is serialized in the trace-event format | 41 // When requested, the timeline is serialized in the trace-event format |
42 // (https://goo.gl/hDZw5M). The request can be for a VM-wide timeline or an | 42 // (https://goo.gl/hDZw5M). The request can be for a VM-wide timeline or an |
43 // isolate specific timeline. In both cases it may be that a thread has | 43 // isolate specific timeline. In both cases it may be that a thread has |
44 // a |TimelineEventBlock| cached in TLS. In order to report a complete timeline | 44 // a |TimelineEventBlock| cached in TLS partially filled with events. In order |
45 // the cached |TimelineEventBlock|s need to be reclaimed. | 45 // to report a complete timeline the cached |TimelineEventBlock|s need to be |
| 46 // reclaimed. |
46 // | 47 // |
47 // Reclaiming open |TimelineEventBlock|s for an isolate: | 48 // Reclaiming open |TimelineEventBlock|s from threads: |
48 // | 49 // |
49 // Cached |TimelineEventBlock|s can be in two places: | 50 // Each |Thread| can have one |TimelineEventBlock| cached in it. |
50 // 1) In a |Thread| (Thread currently in an |Isolate|) | |
51 // 2) In a |Thread::State| (Thread not currently in an |Isolate|). | |
52 // | 51 // |
53 // As a |Thread| enters and exits an |Isolate|, a |TimelineEventBlock| | 52 // To reclaim blocks, we iterate over all threads and remove the cached |
54 // will move between (1) and (2). | 53 // |TimelineEventBlock| from each thread. This is safe because we hold the |
55 // | 54 // |Thread|'s |timeline_block_lock_| meaning the block can't be being modified. |
56 // The first case occurs for |Thread|s that are currently running inside an | |
57 // isolate. The second case occurs for |Thread|s that are not currently | |
58 // running inside an isolate. | |
59 // | |
60 // To reclaim the first case, we take the |Thread|'s |timeline_block_lock_| | |
61 // and reclaim the cached block. | |
62 // | |
63 // To reclaim the second case, we can take the |ThreadRegistry| lock and | |
64 // reclaim these blocks. | |
65 // | |
66 // |Timeline::ReclaimIsolateBlocks| and |Timeline::ReclaimAllBlocks| are | |
67 // the two utility methods used to reclaim blocks before reporting. | |
68 // | 55 // |
69 // Locking notes: | 56 // Locking notes: |
70 // The following locks are used by the timeline system: | 57 // The following locks are used by the timeline system: |
71 // - |TimelineEventRecorder::lock_| This lock is held whenever a | 58 // - |TimelineEventRecorder::lock_| This lock is held whenever a |
72 // |TimelineEventBlock| is being requested or reclaimed. | 59 // |TimelineEventBlock| is being requested or reclaimed. |
73 // - |Thread::timeline_block_lock_| This lock is held whenever a |Thread|'s | 60 // - |Thread::timeline_block_lock_| This lock is held whenever a |Thread|'s |
74 // cached block is being operated on. | 61 // cached block is being operated on. |
75 // - |ThreadRegistry::monitor_| This lock protects the cached block for | 62 // - |Thread::thread_list_lock_| This lock is held when iterating over |
76 // unscheduled threads of an isolate. | 63 // |Thread|s. |
77 // - |Isolate::isolates_list_monitor_| This lock protects the list of | |
78 // isolates in the system. | |
79 // | 64 // |
80 // Locks must always be taken in the following order: | 65 // Locks must always be taken in the following order: |
81 // |Isolate::isolates_list_monitor_| | 66 // |Thread::thread_list_lock_| |
82 // |ThreadRegistry::monitor_| | |
83 // |Thread::timeline_block_lock_| | 67 // |Thread::timeline_block_lock_| |
84 // |TimelineEventRecorder::lock_| | 68 // |TimelineEventRecorder::lock_| |
85 // | 69 // |
86 | 70 |
87 void Timeline::InitOnce() { | 71 void Timeline::InitOnce() { |
88 ASSERT(recorder_ == NULL); | 72 ASSERT(recorder_ == NULL); |
89 // Default to ring recorder being enabled. | 73 // Default to ring recorder being enabled. |
90 const bool use_ring_recorder = true; | 74 const bool use_ring_recorder = true; |
91 // Some flags require that we use the endless recorder. | 75 // Some flags require that we use the endless recorder. |
92 const bool use_endless_recorder = | 76 const bool use_endless_recorder = |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 return (FLAG_timeline_dir != NULL) || FLAG_timing; | 112 return (FLAG_timeline_dir != NULL) || FLAG_timing; |
129 } | 113 } |
130 | 114 |
131 | 115 |
132 TimelineStream* Timeline::GetVMStream() { | 116 TimelineStream* Timeline::GetVMStream() { |
133 ASSERT(vm_stream_ != NULL); | 117 ASSERT(vm_stream_ != NULL); |
134 return vm_stream_; | 118 return vm_stream_; |
135 } | 119 } |
136 | 120 |
137 | 121 |
138 void Timeline::ReclaimIsolateBlocks() { | 122 void Timeline::ReclaimCachedBlocksFromThreads() { |
139 ReclaimBlocksForIsolate(Isolate::Current()); | 123 TimelineEventRecorder* recorder = Timeline::recorder(); |
| 124 if (recorder == NULL) { |
| 125 return; |
| 126 } |
| 127 |
| 128 // Iterate over threads. |
| 129 ThreadIterator it; |
| 130 while (it.HasNext()) { |
| 131 Thread* thread = it.Next(); |
| 132 MutexLocker ml(thread->timeline_block_lock()); |
| 133 // Grab block and clear it. |
| 134 TimelineEventBlock* block = thread->timeline_block(); |
| 135 thread->set_timeline_block(NULL); |
| 136 // TODO(johnmccutchan): Consider dropping the timeline_block_lock here |
| 137 // if we can do it everywhere. This would simplify the lock ordering |
| 138 // requirements. |
| 139 recorder->FinishBlock(block); |
| 140 } |
140 } | 141 } |
141 | 142 |
142 | 143 |
143 class ReclaimBlocksIsolateVisitor : public IsolateVisitor { | |
144 public: | |
145 ReclaimBlocksIsolateVisitor() {} | |
146 | |
147 virtual void VisitIsolate(Isolate* isolate) { | |
148 Timeline::ReclaimBlocksForIsolate(isolate); | |
149 } | |
150 | |
151 private: | |
152 }; | |
153 | |
154 | |
155 void Timeline::ReclaimAllBlocks() { | |
156 if (recorder() == NULL) { | |
157 return; | |
158 } | |
159 // Reclaim all blocks cached for all isolates. | |
160 ReclaimBlocksIsolateVisitor visitor; | |
161 Isolate::VisitIsolates(&visitor); | |
162 // Reclaim the global VM block. | |
163 recorder()->ReclaimGlobalBlock(); | |
164 } | |
165 | |
166 | |
167 void Timeline::ReclaimBlocksForIsolate(Isolate* isolate) { | |
168 if (recorder() == NULL) { | |
169 return; | |
170 } | |
171 ASSERT(isolate != NULL); | |
172 isolate->ReclaimTimelineBlocks(); | |
173 } | |
174 | |
175 | |
176 TimelineEventRecorder* Timeline::recorder_ = NULL; | 144 TimelineEventRecorder* Timeline::recorder_ = NULL; |
177 TimelineStream* Timeline::vm_stream_ = NULL; | 145 TimelineStream* Timeline::vm_stream_ = NULL; |
178 | 146 |
179 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \ | 147 #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \ |
180 bool Timeline::stream_##name##_enabled_ = false; | 148 bool Timeline::stream_##name##_enabled_ = false; |
181 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG) | 149 ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_DEFINE_FLAG) |
182 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG | 150 #undef ISOLATE_TIMELINE_STREAM_DEFINE_FLAG |
183 | 151 |
184 TimelineEvent::TimelineEvent() | 152 TimelineEvent::TimelineEvent() |
185 : timestamp0_(0), | 153 : timestamp0_(0), |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 | 617 |
650 void DartTimelineEvent::Init(Isolate* isolate, const char* event) { | 618 void DartTimelineEvent::Init(Isolate* isolate, const char* event) { |
651 ASSERT(isolate_ == NULL); | 619 ASSERT(isolate_ == NULL); |
652 ASSERT(event != NULL); | 620 ASSERT(event != NULL); |
653 isolate_ = isolate; | 621 isolate_ = isolate; |
654 event_as_json_ = strdup(event); | 622 event_as_json_ = strdup(event); |
655 } | 623 } |
656 | 624 |
657 | 625 |
658 TimelineEventRecorder::TimelineEventRecorder() | 626 TimelineEventRecorder::TimelineEventRecorder() |
659 : global_block_(NULL), | 627 : async_id_(0) { |
660 async_id_(0) { | |
661 } | 628 } |
662 | 629 |
663 | 630 |
664 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { | 631 void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const { |
665 } | 632 } |
666 | 633 |
667 | 634 |
668 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { | 635 TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() { |
669 // Grab the current thread. | 636 // Grab the current thread. |
670 Thread* thread = Thread::Current(); | 637 Thread* thread = Thread::Current(); |
(...skipping 18 matching lines...) Expand all Loading... |
689 } else if (thread_block == NULL) { | 656 } else if (thread_block == NULL) { |
690 MutexLocker ml(&lock_); | 657 MutexLocker ml(&lock_); |
691 // Thread has no block. Attempt to allocate one. | 658 // Thread has no block. Attempt to allocate one. |
692 thread_block = GetNewBlockLocked(thread->isolate()); | 659 thread_block = GetNewBlockLocked(thread->isolate()); |
693 thread->set_timeline_block(thread_block); | 660 thread->set_timeline_block(thread_block); |
694 } | 661 } |
695 if (thread_block != NULL) { | 662 if (thread_block != NULL) { |
696 // NOTE: We are exiting this function with the thread's block lock held. | 663 // NOTE: We are exiting this function with the thread's block lock held. |
697 ASSERT(!thread_block->IsFull()); | 664 ASSERT(!thread_block->IsFull()); |
698 TimelineEvent* event = thread_block->StartEvent(); | 665 TimelineEvent* event = thread_block->StartEvent(); |
699 if (event != NULL) { | |
700 event->set_global_block(false); | |
701 } | |
702 return event; | 666 return event; |
703 } | 667 } |
704 // Drop lock here as no event is being handed out. | 668 // Drop lock here as no event is being handed out. |
705 thread_block_lock->Unlock(); | 669 thread_block_lock->Unlock(); |
706 return NULL; | 670 return NULL; |
707 } | 671 } |
708 | 672 |
709 | 673 |
710 TimelineEvent* TimelineEventRecorder::GlobalBlockStartEvent() { | |
711 // Take recorder lock. This lock will be held until the call to | |
712 // |CompleteEvent| is made. | |
713 lock_.Lock(); | |
714 if (FLAG_trace_timeline) { | |
715 OS::Print("GlobalBlockStartEvent in block %p for thread %" Px "\n", | |
716 global_block_, OSThread::CurrentCurrentThreadIdAsIntPtr()); | |
717 } | |
718 if ((global_block_ != NULL) && global_block_->IsFull()) { | |
719 // Global block is full. | |
720 global_block_->Finish(); | |
721 global_block_ = NULL; | |
722 } | |
723 if (global_block_ == NULL) { | |
724 // Allocate a new block. | |
725 global_block_ = GetNewBlockLocked(NULL); | |
726 ASSERT(global_block_ != NULL); | |
727 } | |
728 if (global_block_ != NULL) { | |
729 // NOTE: We are exiting this function with the recorder's lock held. | |
730 ASSERT(!global_block_->IsFull()); | |
731 TimelineEvent* event = global_block_->StartEvent(); | |
732 if (event != NULL) { | |
733 event->set_global_block(true); | |
734 } | |
735 return event; | |
736 } | |
737 // Drop lock here as no event is being handed out. | |
738 lock_.Unlock(); | |
739 return NULL; | |
740 } | |
741 | |
742 | |
743 void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) { | 674 void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) { |
744 if (event == NULL) { | 675 if (event == NULL) { |
745 return; | 676 return; |
746 } | 677 } |
747 ASSERT(!event->global_block()); | |
748 // Grab the current thread. | 678 // Grab the current thread. |
749 Thread* thread = Thread::Current(); | 679 Thread* thread = Thread::Current(); |
750 ASSERT(thread != NULL); | 680 ASSERT(thread != NULL); |
751 ASSERT(thread->isolate() != NULL); | 681 // Unlock the thread's block lock. |
752 // This event came from the isolate's thread local block. Unlock the | |
753 // thread's block lock. | |
754 Mutex* thread_block_lock = thread->timeline_block_lock(); | 682 Mutex* thread_block_lock = thread->timeline_block_lock(); |
755 ASSERT(thread_block_lock != NULL); | 683 ASSERT(thread_block_lock != NULL); |
756 thread_block_lock->Unlock(); | 684 thread_block_lock->Unlock(); |
757 } | 685 } |
758 | 686 |
759 | 687 |
760 void TimelineEventRecorder::GlobalBlockCompleteEvent(TimelineEvent* event) { | |
761 if (event == NULL) { | |
762 return; | |
763 } | |
764 ASSERT(event->global_block()); | |
765 // This event came from the global block, unlock the recorder's lock now | |
766 // that the event is filled. | |
767 lock_.Unlock(); | |
768 } | |
769 | |
770 | |
771 // Trims the ']' character. | 688 // Trims the ']' character. |
772 static void TrimOutput(char* output, | 689 static void TrimOutput(char* output, |
773 intptr_t* output_length) { | 690 intptr_t* output_length) { |
774 ASSERT(output != NULL); | 691 ASSERT(output != NULL); |
775 ASSERT(output_length != NULL); | 692 ASSERT(output_length != NULL); |
776 ASSERT(*output_length >= 2); | 693 ASSERT(*output_length >= 2); |
777 // We expect the first character to be the opening of an array. | 694 // We expect the first character to be the opening of an array. |
778 ASSERT(output[0] == '['); | 695 ASSERT(output[0] == '['); |
779 // We expect the last character to be the closing of an array. | 696 // We expect the last character to be the closing of an array. |
780 ASSERT(output[*output_length - 1] == ']'); | 697 ASSERT(output[*output_length - 1] == ']'); |
781 // Skip the ]. | 698 // Skip the ]. |
782 *output_length -= 1; | 699 *output_length -= 1; |
783 } | 700 } |
784 | 701 |
785 | 702 |
786 void TimelineEventRecorder::WriteTo(const char* directory) { | 703 void TimelineEventRecorder::WriteTo(const char* directory) { |
787 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); | 704 Dart_FileOpenCallback file_open = Isolate::file_open_callback(); |
788 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); | 705 Dart_FileWriteCallback file_write = Isolate::file_write_callback(); |
789 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); | 706 Dart_FileCloseCallback file_close = Isolate::file_close_callback(); |
790 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { | 707 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) { |
791 return; | 708 return; |
792 } | 709 } |
793 Thread* T = Thread::Current(); | 710 Thread* T = Thread::Current(); |
794 StackZone zone(T); | 711 StackZone zone(T); |
795 | 712 |
796 Timeline::ReclaimAllBlocks(); | 713 Timeline::ReclaimCachedBlocksFromThreads(); |
797 | 714 |
798 intptr_t pid = OS::ProcessId(); | 715 intptr_t pid = OS::ProcessId(); |
799 char* filename = OS::SCreate(NULL, | 716 char* filename = OS::SCreate(NULL, |
800 "%s/dart-timeline-%" Pd ".json", directory, pid); | 717 "%s/dart-timeline-%" Pd ".json", directory, pid); |
801 void* file = (*file_open)(filename, true); | 718 void* file = (*file_open)(filename, true); |
802 if (file == NULL) { | 719 if (file == NULL) { |
803 OS::Print("Failed to write timeline file: %s\n", filename); | 720 OS::Print("Failed to write timeline file: %s\n", filename); |
804 free(filename); | 721 free(filename); |
805 return; | 722 return; |
806 } | 723 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
838 | 755 |
839 // Write out the ']' character. | 756 // Write out the ']' character. |
840 const char* array_close = "]"; | 757 const char* array_close = "]"; |
841 (*file_write)(array_close, 1, file); | 758 (*file_write)(array_close, 1, file); |
842 (*file_close)(file); | 759 (*file_close)(file); |
843 | 760 |
844 return; | 761 return; |
845 } | 762 } |
846 | 763 |
847 | 764 |
848 void TimelineEventRecorder::ReclaimGlobalBlock() { | |
849 MutexLocker ml(&lock_); | |
850 if (global_block_ != NULL) { | |
851 global_block_->Finish(); | |
852 global_block_ = NULL; | |
853 } | |
854 } | |
855 | |
856 | |
857 int64_t TimelineEventRecorder::GetNextAsyncId() { | 765 int64_t TimelineEventRecorder::GetNextAsyncId() { |
858 // TODO(johnmccutchan): Gracefully handle wrap around. | 766 // TODO(johnmccutchan): Gracefully handle wrap around. |
859 uint32_t next = static_cast<uint32_t>( | 767 uint32_t next = static_cast<uint32_t>( |
860 AtomicOperations::FetchAndIncrement(&async_id_)); | 768 AtomicOperations::FetchAndIncrement(&async_id_)); |
861 return static_cast<int64_t>(next); | 769 return static_cast<int64_t>(next); |
862 } | 770 } |
863 | 771 |
864 | 772 |
865 void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) { | 773 void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) { |
866 if (block == NULL) { | 774 if (block == NULL) { |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1031 } | 939 } |
1032 } | 940 } |
1033 return earliest_index; | 941 return earliest_index; |
1034 } | 942 } |
1035 | 943 |
1036 | 944 |
1037 TimelineEvent* TimelineEventRingRecorder::StartEvent() { | 945 TimelineEvent* TimelineEventRingRecorder::StartEvent() { |
1038 // Grab the current thread. | 946 // Grab the current thread. |
1039 Thread* thread = Thread::Current(); | 947 Thread* thread = Thread::Current(); |
1040 ASSERT(thread != NULL); | 948 ASSERT(thread != NULL); |
1041 if (thread->isolate() == NULL) { | |
1042 // Non-isolate thread case. This should be infrequent. | |
1043 return GlobalBlockStartEvent(); | |
1044 } | |
1045 return ThreadBlockStartEvent(); | 949 return ThreadBlockStartEvent(); |
1046 } | 950 } |
1047 | 951 |
1048 | 952 |
1049 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) { | 953 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) { |
1050 if (event == NULL) { | 954 if (event == NULL) { |
1051 return; | 955 return; |
1052 } | 956 } |
1053 if (event->global_block()) { | 957 ThreadBlockCompleteEvent(event); |
1054 GlobalBlockCompleteEvent(event); | |
1055 } else { | |
1056 ThreadBlockCompleteEvent(event); | |
1057 } | |
1058 } | 958 } |
1059 | 959 |
1060 | 960 |
1061 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { | 961 TimelineEventStreamingRecorder::TimelineEventStreamingRecorder() { |
1062 } | 962 } |
1063 | 963 |
1064 | 964 |
1065 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { | 965 TimelineEventStreamingRecorder::~TimelineEventStreamingRecorder() { |
1066 } | 966 } |
1067 | 967 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1172 | 1072 |
1173 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { | 1073 TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { |
1174 return head_; | 1074 return head_; |
1175 } | 1075 } |
1176 | 1076 |
1177 | 1077 |
1178 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { | 1078 TimelineEvent* TimelineEventEndlessRecorder::StartEvent() { |
1179 // Grab the current thread. | 1079 // Grab the current thread. |
1180 Thread* thread = Thread::Current(); | 1080 Thread* thread = Thread::Current(); |
1181 ASSERT(thread != NULL); | 1081 ASSERT(thread != NULL); |
1182 if (thread->isolate() == NULL) { | |
1183 // Non-isolate thread case. This should be infrequent. | |
1184 return GlobalBlockStartEvent(); | |
1185 } | |
1186 return ThreadBlockStartEvent(); | 1082 return ThreadBlockStartEvent(); |
1187 } | 1083 } |
1188 | 1084 |
1189 | 1085 |
1190 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { | 1086 void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent* event) { |
1191 if (event == NULL) { | 1087 if (event == NULL) { |
1192 return; | 1088 return; |
1193 } | 1089 } |
1194 if (event->global_block()) { | 1090 ThreadBlockCompleteEvent(event); |
1195 GlobalBlockCompleteEvent(event); | |
1196 } else { | |
1197 ThreadBlockCompleteEvent(event); | |
1198 } | |
1199 } | 1091 } |
1200 | 1092 |
1201 | 1093 |
1202 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( | 1094 TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked( |
1203 Isolate* isolate) { | 1095 Isolate* isolate) { |
1204 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); | 1096 TimelineEventBlock* block = new TimelineEventBlock(block_index_++); |
1205 block->set_next(head_); | 1097 block->set_next(head_); |
1206 block->Open(isolate); | 1098 block->Open(isolate); |
1207 head_ = block; | 1099 head_ = block; |
1208 if (FLAG_trace_timeline) { | 1100 if (FLAG_trace_timeline) { |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1467 // If an isolate was specified, skip events from other isolates. | 1359 // If an isolate was specified, skip events from other isolates. |
1468 continue; | 1360 continue; |
1469 } | 1361 } |
1470 ASSERT(event->event_as_json() != NULL); | 1362 ASSERT(event->event_as_json() != NULL); |
1471 result = zone->ConcatStrings(result, event->event_as_json()); | 1363 result = zone->ConcatStrings(result, event->event_as_json()); |
1472 } | 1364 } |
1473 return result; | 1365 return result; |
1474 } | 1366 } |
1475 | 1367 |
1476 } // namespace dart | 1368 } // namespace dart |
OLD | NEW |