// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_TIMELINE_ANALYSIS_H_ #define RUNTIME_VM_TIMELINE_ANALYSIS_H_ #include "vm/growable_array.h" #include "vm/timeline.h" namespace dart { class TimelineAnalysisThread : public ZoneAllocated { public: explicit TimelineAnalysisThread(ThreadId id); ~TimelineAnalysisThread(); ThreadId id() const { return id_; } intptr_t NumBlocks() const { return blocks_.length(); } TimelineEventBlock* At(intptr_t i) const { return blocks_.At(i); } private: void AddBlock(TimelineEventBlock* block); void Finalize(); const ThreadId id_; ZoneGrowableArray blocks_; friend class TimelineAnalysis; }; class TimelineAnalysisThreadEventIterator : public ValueObject { public: explicit TimelineAnalysisThreadEventIterator(TimelineAnalysisThread* thread); ~TimelineAnalysisThreadEventIterator(); void Reset(TimelineAnalysisThread* thread); bool HasNext() const; TimelineEvent* Next(); private: TimelineAnalysisThread* thread_; TimelineEvent* current_; intptr_t block_cursor_; intptr_t event_cursor_; }; // Base of all timeline analysis classes. Base functionality: // - discovery of all thread ids in a recording. // - collecting all ThreadEventBlocks by thread id. class TimelineAnalysis : public ValueObject { public: TimelineAnalysis(Zone* zone, Isolate* isolate, TimelineEventRecorder* recorder); ~TimelineAnalysis(); void BuildThreads(); intptr_t NumThreads() const { return threads_.length(); } TimelineAnalysisThread* At(intptr_t i) const { return threads_[i]; } TimelineAnalysisThread* GetThread(ThreadId tid); bool has_error() const { return has_error_; } const char* error_msg() const { return error_msg_; } protected: TimelineAnalysisThread* GetOrAddThread(ThreadId tid); void DiscoverThreads(); void FinalizeThreads(); void SetError(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); Zone* zone_; Isolate* isolate_; TimelineEventRecorder* recorder_; bool has_error_; const char* error_msg_; ZoneGrowableArray threads_; }; class TimelineLabelPauseInfo : public ZoneAllocated { public: explicit TimelineLabelPauseInfo(const char* name); const char* name() const { return name_; } int64_t inclusive_micros() const { return inclusive_micros_; } int64_t exclusive_micros() const { return exclusive_micros_; } int64_t max_inclusive_micros() const { return max_inclusive_micros_; } int64_t max_exclusive_micros() const { return max_exclusive_micros_; } private: // Adjusts |inclusive_micros_| and |exclusive_micros_| by |micros|. // Also, may adjust, max_inclusive_micros_. void OnPush(int64_t micros, bool already_on_stack); // Adjusts |exclusive_micros_| by |exclusive_micros|. // Also, may adjust |max_exclusive_micros_|. void OnPop(int64_t exclusive_micros); // Adjusts |inclusive_micros_| and |exclusive_micros_| by |micros|. // Also, may adjust, |max_inclusive_micros_|. void OnBeginPop(int64_t inclusive_micros, int64_t exclusive_micros, bool already_on_stack); void UpdateInclusiveMicros(int64_t inclusive_micros, bool already_on_stack); void UpdateExclusiveMicros(int64_t exclusive_micros); // Adjust inclusive micros. void add_inclusive_micros(int64_t delta_micros) { inclusive_micros_ += delta_micros; ASSERT(inclusive_micros_ >= 0); } // Adjust exclusive micros. void add_exclusive_micros(int64_t delta_micros) { exclusive_micros_ += delta_micros; ASSERT(exclusive_micros_ >= 0); } void Aggregate(const TimelineLabelPauseInfo* thread_pause_info); const char* name_; int64_t inclusive_micros_; int64_t exclusive_micros_; int64_t max_inclusive_micros_; int64_t max_exclusive_micros_; friend class TimelinePauses; friend class TimelinePauseTrace; }; class TimelinePauses : public TimelineAnalysis { public: TimelinePauses(Zone* zone, Isolate* isolate, TimelineEventRecorder* recorder); void Setup(); void CalculatePauseTimesForThread(ThreadId tid); TimelineLabelPauseInfo* GetLabelPauseInfo(const char* name) const; int64_t InclusiveTime(const char* name) const; int64_t ExclusiveTime(const char* name) const; int64_t MaxInclusiveTime(const char* name) const; int64_t MaxExclusiveTime(const char* name) const; intptr_t NumPauseInfos() const { return labels_.length(); } const TimelineLabelPauseInfo* PauseInfoAt(intptr_t i) const { return labels_.At(i); } private: struct StackItem { TimelineEvent* event; TimelineLabelPauseInfo* pause_info; int64_t exclusive_micros; }; void ProcessThread(TimelineAnalysisThread* thread); bool CheckStack(TimelineEvent* event); void PopFinishedDurations(int64_t start); void PopBegin(const char* label, int64_t end); void Push(TimelineEvent* event); bool IsLabelOnStack(const char* label) const; intptr_t StackDepth() const; StackItem& GetStackTop(); TimelineLabelPauseInfo* GetOrAddLabelPauseInfo(const char* name); ZoneGrowableArray stack_; ZoneGrowableArray labels_; }; class TimelinePauseTrace : public ValueObject { public: TimelinePauseTrace(); ~TimelinePauseTrace(); void Print(); private: TimelineLabelPauseInfo* GetOrAddLabelPauseInfo(const char* name); void Aggregate(const TimelineLabelPauseInfo* thread_pause_info); void PrintPauseInfo(const TimelineLabelPauseInfo* pause_info); ZoneGrowableArray isolate_labels_; }; } // namespace dart #endif // RUNTIME_VM_TIMELINE_ANALYSIS_H_