Chromium Code Reviews| Index: runtime/vm/timeline.h |
| diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h |
| index a57b651e5d6eaf17266c9cdbbafefa0b32986a24..c551fa5a32c0fb239353884765e0f77eee988935 100644 |
| --- a/runtime/vm/timeline.h |
| +++ b/runtime/vm/timeline.h |
| @@ -22,6 +22,30 @@ class TimelineEventBlock; |
| class TimelineEventRecorder; |
| class TimelineStream; |
| + |
| +class Timeline : public AllStatic { |
| + public: |
| + // Initialize timeline system. Not thread safe. |
| + static void InitOnce(); |
| + |
| + // Shutdown timeline system. Not thread safe. |
| + static void Shutdown(); |
| + |
| + // Access the global recorder. Not thread safe. |
| + static TimelineEventRecorder* recorder(); |
| + |
| + static bool EnableStreamByDefault(const char* stream_name); |
| + |
| + static TimelineStream* GetVMStream(); |
| + |
| + private: |
| + static TimelineEventRecorder* recorder_; |
| + static TimelineStream* vm_stream_; |
| + |
| + friend class TimelineRecorderOverride; |
| +}; |
| + |
| + |
| // You should get a |TimelineEvent| from a |TimelineStream|. |
| class TimelineEvent { |
| public: |
| @@ -45,9 +69,8 @@ class TimelineEvent { |
| return (event_type() > kNone) && (event_type() < kNumEventTypes); |
| } |
| - // Marks the beginning of an asynchronous operation. |
| - // Returns |async_id| which must be passed to |AsyncInstant| and |AsyncEnd|. |
| - int64_t AsyncBegin(const char* label); |
| + // Marks the beginning of an asynchronous operation with \async_id|. |
| + void AsyncBegin(const char* label, int64_t async_id); |
| // Marks an instantaneous event associated with |async_id|. |
| void AsyncInstant(const char* label, |
| int64_t async_id); |
| @@ -139,8 +162,9 @@ class TimelineEvent { |
| intptr_t arguments_length_; |
| uword state_; |
| const char* label_; |
| - TimelineStream* stream_; |
| + const char* category_; |
| ThreadId thread_; |
| + Isolate* isolate_; |
| void FreeArguments(); |
| @@ -185,28 +209,13 @@ class TimelineStream { |
| enabled_ = enabled; |
| } |
| - TimelineEventRecorder* recorder() const { |
| - return recorder_; |
| - } |
| - |
| - // TODO(johnmccutchan): Disallow setting recorder after Init? |
| - void set_recorder(TimelineEventRecorder* recorder) { |
| - recorder_ = recorder; |
| - } |
| - |
| // Records an event. Will return |NULL| if not enabled. The returned |
| // |TimelineEvent| is in an undefined state and must be initialized. |
| TimelineEvent* StartEvent(); |
| - void CompleteEvent(TimelineEvent* event); |
| - |
| - int64_t GetNextSeq(); |
| - |
| private: |
| - TimelineEventRecorder* recorder_; |
| const char* name_; |
| bool enabled_; |
| - int64_t seq_; |
| }; |
| @@ -228,9 +237,12 @@ class TimelineStream { |
| tds.CopyArgument( \ |
| 0, \ |
| "function", \ |
| - const_cast<char*>(function.QualifiedUserVisibleNameCString())); \ |
| + const_cast<char*>(function.ToLibNamePrefixedQualifiedCString())); \ |
| } |
| + |
| +// TODO(johnmccutchan): TimelineDurationScope should only allocate the |
| +// event when complete. |
| class TimelineDurationScope : public StackResource { |
| public: |
| TimelineDurationScope(Isolate* isolate, |
| @@ -247,6 +259,12 @@ class TimelineDurationScope : public StackResource { |
| Init(stream, label); |
| } |
| + TimelineDurationScope(TimelineStream* stream, |
| + const char* label) |
| + : StackResource(reinterpret_cast<Thread*>(NULL)) { |
| + Init(stream, label); |
| + } |
| + |
| void Init(TimelineStream* stream, const char* label) { |
| event_ = stream->StartEvent(); |
| if (event_ == NULL) { |
| @@ -353,6 +371,16 @@ class TimelineEventBlock { |
| // Call Reset on all events and set length to 0. |
| void Reset(); |
| + // Only safe to access under the recorder's lock. |
| + bool open() const { |
| + return open_; |
| + } |
| + |
| + // Only safe to access under the recorder's lock. |
| + Isolate* isolate() const { |
| + return isolate_; |
| + } |
| + |
| protected: |
| TimelineEvent* StartEvent(); |
| @@ -361,8 +389,17 @@ class TimelineEventBlock { |
| intptr_t length_; |
| intptr_t block_index_; |
| - friend class TimelineEventEndlessRecorder; |
| + // Only accessed under the recorder's lock. |
| + Isolate* isolate_; |
| + bool open_; |
| + |
| + void Open(Isolate* isolate); |
| + void Finish(); |
| + |
| + friend class ThreadRegistry; |
| friend class TimelineEventRecorder; |
| + friend class TimelineEventRingRecorder; |
| + friend class TimelineEventEndlessRecorder; |
| friend class TimelineTestHelper; |
| private: |
| @@ -370,30 +407,84 @@ class TimelineEventBlock { |
| }; |
| +class TimelineEventFilter : public ValueObject { |
| + public: |
| + TimelineEventFilter(); |
| + virtual ~TimelineEventFilter(); |
| + |
| + virtual bool VisitBlock(TimelineEventBlock* block) { |
|
rmacnak
2015/08/18 21:09:00
'IncludeBlock'? VisitBlock sounds like it is run
Cutch
2015/08/18 21:50:18
Done.
|
| + if (block == NULL) { |
| + return false; |
| + } |
| + // Not empty and not open. |
| + return !block->IsEmpty() && !block->open(); |
| + } |
| + |
| + virtual bool VisitEvent(TimelineEvent* event) { |
|
rmacnak
2015/08/18 21:09:00
'IncludeEvent'?
Cutch
2015/08/18 21:50:18
Done.
|
| + if (event == NULL) { |
| + return false; |
| + } |
| + return event->IsValid(); |
| + } |
| + |
| + private: |
| +}; |
| + |
| + |
| +class IsolateTimelineEventFilter : public TimelineEventFilter { |
| + public: |
| + explicit IsolateTimelineEventFilter(Isolate* isolate); |
| + |
| + bool VisitBlock(TimelineEventBlock* block) { |
| + if (block == NULL) { |
| + return false; |
| + } |
| + // Not empty, not open, and isolate match. |
| + return !block->IsEmpty() && |
| + !block->open() && |
| + (block->isolate() == isolate_); |
| + } |
| + |
| + private: |
| + Isolate* isolate_; |
| +}; |
| + |
| + |
| // Recorder of |TimelineEvent|s. |
| class TimelineEventRecorder { |
| public: |
| TimelineEventRecorder(); |
| virtual ~TimelineEventRecorder() {} |
| + TimelineEventBlock* GetNewBlock(); |
| + |
| // Interface method(s) which must be implemented. |
| - virtual void PrintJSON(JSONStream* js) = 0; |
| - virtual TimelineEventBlock* GetNewBlock() = 0; |
| - virtual TimelineEventBlock* GetHeadBlock() = 0; |
| + virtual void PrintJSON(JSONStream* js, TimelineEventFilter* filter) = 0; |
| void WriteTo(const char* directory); |
| + int64_t GetNextAsyncId(); |
| + |
| protected: |
| // Interface method(s) which must be implemented. |
| virtual TimelineEvent* StartEvent() = 0; |
| virtual void CompleteEvent(TimelineEvent* event) = 0; |
| + virtual TimelineEventBlock* GetHeadBlockLocked() = 0; |
| + virtual TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) = 0; |
| // Utility method(s). |
| void PrintJSONMeta(JSONArray* array) const; |
| TimelineEvent* ThreadBlockStartEvent(); |
| + TimelineEvent* GlobalBlockStartEvent(); |
| Mutex lock_; |
| + // Only accessed under |lock_|. |
| + TimelineEventBlock* global_block_; |
| + |
| + uintptr_t async_id_; |
| + friend class ThreadRegistry; |
| + friend class TimelineEvent; |
| friend class TimelineEventBlockIterator; |
| friend class TimelineStream; |
| friend class TimelineTestHelper; |
| @@ -412,21 +503,18 @@ class TimelineEventRingRecorder : public TimelineEventRecorder { |
| explicit TimelineEventRingRecorder(intptr_t capacity = kDefaultCapacity); |
| ~TimelineEventRingRecorder(); |
| - void PrintJSON(JSONStream* js); |
| - TimelineEventBlock* GetNewBlock(); |
| - TimelineEventBlock* GetHeadBlock(); |
| + void PrintJSON(JSONStream* js, TimelineEventFilter* filter); |
| protected: |
| TimelineEvent* StartEvent(); |
| void CompleteEvent(TimelineEvent* event); |
| - |
| + TimelineEventBlock* GetHeadBlockLocked(); |
| intptr_t FindOldestBlockIndex() const; |
| - TimelineEventBlock* GetNewBlockLocked(); |
| + TimelineEventBlock* GetNewBlockLocked(Isolate* isolate); |
| - void PrintJSONEvents(JSONArray* array) const; |
| + void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const; |
| TimelineEventBlock** blocks_; |
| - RawArray* event_objects_; |
| intptr_t capacity_; |
| intptr_t num_blocks_; |
| intptr_t block_cursor_; |
| @@ -439,19 +527,19 @@ class TimelineEventStreamingRecorder : public TimelineEventRecorder { |
| TimelineEventStreamingRecorder(); |
| ~TimelineEventStreamingRecorder(); |
| - void PrintJSON(JSONStream* js); |
| - TimelineEventBlock* GetNewBlock() { |
| - return NULL; |
| - } |
| - TimelineEventBlock* GetHeadBlock() { |
| - return NULL; |
| - } |
| + void PrintJSON(JSONStream* js, TimelineEventFilter* filter); |
| // Called when |event| is ready to be streamed. It is unsafe to keep a |
| // reference to |event| as it may be freed as soon as this function returns. |
| virtual void StreamEvent(TimelineEvent* event) = 0; |
| protected: |
| + TimelineEventBlock* GetNewBlockLocked(Isolate* isolate) { |
| + return NULL; |
| + } |
| + TimelineEventBlock* GetHeadBlockLocked() { |
| + return NULL; |
| + } |
| TimelineEvent* StartEvent(); |
| void CompleteEvent(TimelineEvent* event); |
| }; |
| @@ -464,26 +552,18 @@ class TimelineEventEndlessRecorder : public TimelineEventRecorder { |
| public: |
| TimelineEventEndlessRecorder(); |
| - // Acquire a new block of events. |
| - // Takes a lock. |
| - // Recorder owns the block and it should be filled by only one thread. |
| - TimelineEventBlock* GetNewBlock(); |
| - |
| - TimelineEventBlock* GetHeadBlock(); |
| - |
| - // It is expected that this function is only called when an isolate is |
| - // shutting itself down. |
| // NOTE: Calling this while threads are filling in their blocks is not safe |
| // and there are no checks in place to ensure that doesn't happen. |
| // TODO(koda): Add isolate count to |ThreadRegistry| and verify that it is 1. |
| - void PrintJSON(JSONStream* js); |
| + void PrintJSON(JSONStream* js, TimelineEventFilter* filter); |
| protected: |
| TimelineEvent* StartEvent(); |
| void CompleteEvent(TimelineEvent* event); |
| + TimelineEventBlock* GetNewBlockLocked(Isolate* isolate); |
| + TimelineEventBlock* GetHeadBlockLocked(); |
| - TimelineEventBlock* GetNewBlockLocked(); |
| - void PrintJSONEvents(JSONArray* array) const; |
| + void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter) const; |
| // Useful only for testing. Only works for one thread. |
| void Clear(); |