| 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 |