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 |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_VM_TIMELINE_ANALYSIS_H_ |
6 | #define RUNTIME_VM_TIMELINE_ANALYSIS_H_ |
7 | |
8 | #include "vm/growable_array.h" |
9 | #include "vm/timeline.h" |
10 | |
11 | namespace dart { |
12 | |
13 | class TimelineAnalysisThread : public ZoneAllocated { |
14 | public: |
15 | explicit TimelineAnalysisThread(ThreadId id); |
16 | ~TimelineAnalysisThread(); |
17 | |
18 | ThreadId id() const { return id_; } |
19 | |
20 | intptr_t NumBlocks() const { return blocks_.length(); } |
21 | |
22 | TimelineEventBlock* At(intptr_t i) const { return blocks_.At(i); } |
23 | |
24 | private: |
25 | void AddBlock(TimelineEventBlock* block); |
26 | void Finalize(); |
27 | |
28 | const ThreadId id_; |
29 | ZoneGrowableArray<TimelineEventBlock*> blocks_; |
30 | |
31 | friend class TimelineAnalysis; |
32 | }; |
33 | |
34 | class TimelineAnalysisThreadEventIterator : public ValueObject { |
35 | public: |
36 | explicit TimelineAnalysisThreadEventIterator(TimelineAnalysisThread* thread); |
37 | ~TimelineAnalysisThreadEventIterator(); |
38 | |
39 | void Reset(TimelineAnalysisThread* thread); |
40 | |
41 | bool HasNext() const; |
42 | |
43 | TimelineEvent* Next(); |
44 | |
45 | private: |
46 | TimelineAnalysisThread* thread_; |
47 | TimelineEvent* current_; |
48 | intptr_t block_cursor_; |
49 | intptr_t event_cursor_; |
50 | }; |
51 | |
52 | // Base of all timeline analysis classes. Base functionality: |
53 | // - discovery of all thread ids in a recording. |
54 | // - collecting all ThreadEventBlocks by thread id. |
55 | class TimelineAnalysis : public ValueObject { |
56 | public: |
57 | TimelineAnalysis(Zone* zone, |
58 | Isolate* isolate, |
59 | TimelineEventRecorder* recorder); |
60 | ~TimelineAnalysis(); |
61 | |
62 | void BuildThreads(); |
63 | |
64 | intptr_t NumThreads() const { return threads_.length(); } |
65 | |
66 | TimelineAnalysisThread* At(intptr_t i) const { return threads_[i]; } |
67 | |
68 | TimelineAnalysisThread* GetThread(ThreadId tid); |
69 | |
70 | bool has_error() const { return has_error_; } |
71 | |
72 | const char* error_msg() const { return error_msg_; } |
73 | |
74 | protected: |
75 | TimelineAnalysisThread* GetOrAddThread(ThreadId tid); |
76 | |
77 | void DiscoverThreads(); |
78 | void FinalizeThreads(); |
79 | |
80 | void SetError(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
81 | |
82 | Zone* zone_; |
83 | Isolate* isolate_; |
84 | TimelineEventRecorder* recorder_; |
85 | bool has_error_; |
86 | const char* error_msg_; |
87 | |
88 | ZoneGrowableArray<TimelineAnalysisThread*> threads_; |
89 | }; |
90 | |
91 | class TimelineLabelPauseInfo : public ZoneAllocated { |
92 | public: |
93 | explicit TimelineLabelPauseInfo(const char* name); |
94 | |
95 | const char* name() const { return name_; } |
96 | |
97 | int64_t inclusive_micros() const { return inclusive_micros_; } |
98 | |
99 | int64_t exclusive_micros() const { return exclusive_micros_; } |
100 | |
101 | int64_t max_inclusive_micros() const { return max_inclusive_micros_; } |
102 | |
103 | int64_t max_exclusive_micros() const { return max_exclusive_micros_; } |
104 | |
105 | private: |
106 | // Adjusts |inclusive_micros_| and |exclusive_micros_| by |micros|. |
107 | // Also, may adjust, max_inclusive_micros_. |
108 | void OnPush(int64_t micros, bool already_on_stack); |
109 | |
110 | // Adjusts |exclusive_micros_| by |exclusive_micros|. |
111 | // Also, may adjust |max_exclusive_micros_|. |
112 | void OnPop(int64_t exclusive_micros); |
113 | |
114 | // Adjusts |inclusive_micros_| and |exclusive_micros_| by |micros|. |
115 | // Also, may adjust, |max_inclusive_micros_|. |
116 | void OnBeginPop(int64_t inclusive_micros, |
117 | int64_t exclusive_micros, |
118 | bool already_on_stack); |
119 | |
120 | void UpdateInclusiveMicros(int64_t inclusive_micros, bool already_on_stack); |
121 | void UpdateExclusiveMicros(int64_t exclusive_micros); |
122 | |
123 | // Adjust inclusive micros. |
124 | void add_inclusive_micros(int64_t delta_micros) { |
125 | inclusive_micros_ += delta_micros; |
126 | ASSERT(inclusive_micros_ >= 0); |
127 | } |
128 | |
129 | // Adjust exclusive micros. |
130 | void add_exclusive_micros(int64_t delta_micros) { |
131 | exclusive_micros_ += delta_micros; |
132 | ASSERT(exclusive_micros_ >= 0); |
133 | } |
134 | |
135 | void Aggregate(const TimelineLabelPauseInfo* thread_pause_info); |
136 | |
137 | const char* name_; |
138 | int64_t inclusive_micros_; |
139 | int64_t exclusive_micros_; |
140 | int64_t max_inclusive_micros_; |
141 | int64_t max_exclusive_micros_; |
142 | |
143 | friend class TimelinePauses; |
144 | friend class TimelinePauseTrace; |
145 | }; |
146 | |
147 | class TimelinePauses : public TimelineAnalysis { |
148 | public: |
149 | TimelinePauses(Zone* zone, Isolate* isolate, TimelineEventRecorder* recorder); |
150 | |
151 | void Setup(); |
152 | |
153 | void CalculatePauseTimesForThread(ThreadId tid); |
154 | |
155 | TimelineLabelPauseInfo* GetLabelPauseInfo(const char* name) const; |
156 | |
157 | int64_t InclusiveTime(const char* name) const; |
158 | int64_t ExclusiveTime(const char* name) const; |
159 | int64_t MaxInclusiveTime(const char* name) const; |
160 | int64_t MaxExclusiveTime(const char* name) const; |
161 | |
162 | intptr_t NumPauseInfos() const { return labels_.length(); } |
163 | |
164 | const TimelineLabelPauseInfo* PauseInfoAt(intptr_t i) const { |
165 | return labels_.At(i); |
166 | } |
167 | |
168 | private: |
169 | struct StackItem { |
170 | TimelineEvent* event; |
171 | TimelineLabelPauseInfo* pause_info; |
172 | int64_t exclusive_micros; |
173 | }; |
174 | |
175 | void ProcessThread(TimelineAnalysisThread* thread); |
176 | bool CheckStack(TimelineEvent* event); |
177 | void PopFinishedDurations(int64_t start); |
178 | void PopBegin(const char* label, int64_t end); |
179 | void Push(TimelineEvent* event); |
180 | bool IsLabelOnStack(const char* label) const; |
181 | intptr_t StackDepth() const; |
182 | StackItem& GetStackTop(); |
183 | TimelineLabelPauseInfo* GetOrAddLabelPauseInfo(const char* name); |
184 | |
185 | ZoneGrowableArray<StackItem> stack_; |
186 | ZoneGrowableArray<TimelineLabelPauseInfo*> labels_; |
187 | }; |
188 | |
189 | class TimelinePauseTrace : public ValueObject { |
190 | public: |
191 | TimelinePauseTrace(); |
192 | ~TimelinePauseTrace(); |
193 | |
194 | void Print(); |
195 | |
196 | private: |
197 | TimelineLabelPauseInfo* GetOrAddLabelPauseInfo(const char* name); |
198 | void Aggregate(const TimelineLabelPauseInfo* thread_pause_info); |
199 | void PrintPauseInfo(const TimelineLabelPauseInfo* pause_info); |
200 | |
201 | ZoneGrowableArray<TimelineLabelPauseInfo*> isolate_labels_; |
202 | }; |
203 | |
204 | } // namespace dart |
205 | |
206 | #endif // RUNTIME_VM_TIMELINE_ANALYSIS_H_ |
207 | |