Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: runtime/vm/timeline_analysis.cc

Issue 1289113003: Add TimelinePauses analysis and tests (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/timeline_analysis.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "vm/timeline_analysis.h" 5 #include "vm/timeline_analysis.h"
6 6
7 #include "vm/flags.h" 7 #include "vm/flags.h"
8 #include "vm/log.h"
9 #include "vm/os_thread.h"
8 10
9 namespace dart { 11 namespace dart {
10 12
11 DECLARE_FLAG(bool, trace_timeline); 13 DEFINE_FLAG(bool, trace_timeline_analysis, false, "Trace timeline analysis");
12
13 14
14 TimelineAnalysisThread::TimelineAnalysisThread(ThreadId id) 15 TimelineAnalysisThread::TimelineAnalysisThread(ThreadId id)
15 : id_(id) { 16 : id_(id) {
16 } 17 }
17 18
18 19
19 TimelineAnalysisThread::~TimelineAnalysisThread() { 20 TimelineAnalysisThread::~TimelineAnalysisThread() {
20 } 21 }
21 22
22 23
23 void TimelineAnalysisThread::AddBlock(TimelineEventBlock* block) { 24 void TimelineAnalysisThread::AddBlock(TimelineEventBlock* block) {
24 blocks_.Add(block); 25 blocks_.Add(block);
25 } 26 }
26 27
27 28
28 static int CompareBlocksLowerTimeBound(TimelineEventBlock* const* a, 29 static int CompareBlocksLowerTimeBound(TimelineEventBlock* const* a,
29 TimelineEventBlock* const* b) { 30 TimelineEventBlock* const* b) {
30 ASSERT(a != NULL); 31 ASSERT(a != NULL);
31 ASSERT(*a != NULL); 32 ASSERT(*a != NULL);
32 ASSERT(b != NULL); 33 ASSERT(b != NULL);
33 ASSERT(*b != NULL); 34 ASSERT(*b != NULL);
34 return (*a)->LowerTimeBound() - (*b)->LowerTimeBound(); 35 return (*a)->LowerTimeBound() - (*b)->LowerTimeBound();
35 } 36 }
36 37
37 38
38 void TimelineAnalysisThread::Finalize() { 39 void TimelineAnalysisThread::Finalize() {
39 blocks_.Sort(CompareBlocksLowerTimeBound); 40 blocks_.Sort(CompareBlocksLowerTimeBound);
41 ISL_Print("Thread %" Px " has %" Pd " blocks\n",
42 OSThread::ThreadIdToIntPtr(id_),
43 blocks_.length());
40 } 44 }
41 45
42 46
43 TimelineAnalysisThreadEventIterator::TimelineAnalysisThreadEventIterator( 47 TimelineAnalysisThreadEventIterator::TimelineAnalysisThreadEventIterator(
44 TimelineAnalysisThread* thread) { 48 TimelineAnalysisThread* thread) {
45 Reset(thread); 49 Reset(thread);
46 } 50 }
47 51
48 52
49 TimelineAnalysisThreadEventIterator::~TimelineAnalysisThreadEventIterator() { 53 TimelineAnalysisThreadEventIterator::~TimelineAnalysisThreadEventIterator() {
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 void TimelineAnalysis::DiscoverThreads() { 153 void TimelineAnalysis::DiscoverThreads() {
150 TimelineEventBlockIterator it(recorder_); 154 TimelineEventBlockIterator it(recorder_);
151 while (it.HasNext()) { 155 while (it.HasNext()) {
152 TimelineEventBlock* block = it.Next(); 156 TimelineEventBlock* block = it.Next();
153 ASSERT(block != NULL); 157 ASSERT(block != NULL);
154 if (block->IsEmpty()) { 158 if (block->IsEmpty()) {
155 // Skip empty blocks. 159 // Skip empty blocks.
156 continue; 160 continue;
157 } 161 }
158 if (!block->CheckBlock()) { 162 if (!block->CheckBlock()) {
159 // Skip bad blocks. 163 if (FLAG_trace_timeline_analysis) {
160 // TODO(johnmccutchan): Make this into an error? 164 ISL_Print("DiscoverThreads block %" Pd " "
161 continue; 165 "violates invariants.\n", block->block_index());
166 }
167 SetError("Block %" Pd " violates invariants. See "
168 "TimelineEventBlock::CheckBlock", block->block_index());
169 return;
162 } 170 }
163 TimelineAnalysisThread* thread = GetOrAddThread(block->thread()); 171 TimelineAnalysisThread* thread = GetOrAddThread(block->thread());
164 ASSERT(thread != NULL); 172 ASSERT(thread != NULL);
165 thread->AddBlock(block); 173 thread->AddBlock(block);
166 } 174 }
167 } 175 }
168 176
169 177
170 void TimelineAnalysis::FinalizeThreads() { 178 void TimelineAnalysis::FinalizeThreads() {
171 for (intptr_t i = 0; i < threads_.length(); i++) { 179 for (intptr_t i = 0; i < threads_.length(); i++) {
172 TimelineAnalysisThread* thread = threads_.At(i); 180 TimelineAnalysisThread* thread = threads_.At(i);
173 ASSERT(thread != NULL); 181 ASSERT(thread != NULL);
174 thread->Finalize(); 182 thread->Finalize();
175 } 183 }
176 } 184 }
177 185
178 186
179 void TimelineAnalysis::SetError(const char* format, ...) { 187 void TimelineAnalysis::SetError(const char* format, ...) {
180 ASSERT(!has_error_); 188 ASSERT(!has_error_);
181 ASSERT(error_msg_ == NULL); 189 ASSERT(error_msg_ == NULL);
182 has_error_ = true; 190 has_error_ = true;
183 va_list args; 191 va_list args;
184 va_start(args, format); 192 va_start(args, format);
185 error_msg_ = zone_->VPrint(format, args); 193 error_msg_ = zone_->VPrint(format, args);
186 ASSERT(error_msg_ != NULL); 194 ASSERT(error_msg_ != NULL);
187 } 195 }
188 196
189 197
198 TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name)
199 : name_(name),
200 inclusive_micros_(0),
201 exclusive_micros_(0),
202 max_duration_micros_(0) {
203 ASSERT(name_ != NULL);
204 }
205
206
207 void TimelineLabelPauseInfo::OnPush(int64_t micros) {
208 add_inclusive_micros(micros);
209 add_exclusive_micros(micros);
210 if (micros > max_duration_micros_) {
211 max_duration_micros_ = micros;
212 }
213 }
214
215
216 void TimelineLabelPauseInfo::OnChildPush(int64_t micros) {
217 ASSERT(micros >= 0);
218 add_exclusive_micros(-micros);
219 }
220
221
190 TimelinePauses::TimelinePauses(Zone* zone, 222 TimelinePauses::TimelinePauses(Zone* zone,
191 Isolate* isolate, 223 Isolate* isolate,
192 TimelineEventRecorder* recorder) 224 TimelineEventRecorder* recorder)
193 : TimelineAnalysis(zone, isolate, recorder) { 225 : TimelineAnalysis(zone, isolate, recorder) {
194 } 226 }
195 227
196 228
197 void TimelinePauses::CalculatePauseTimes() { 229 void TimelinePauses::Setup() {
230 BuildThreads();
231 }
232
233
234 void TimelinePauses::CalculatePauseTimesForThread(ThreadId tid) {
235 if (has_error()) {
236 return;
237 }
238 TimelineAnalysisThread* thread = GetThread(tid);
239 if (thread == NULL) {
240 SetError("Thread %" Px " does not exist.", OSThread::ThreadIdToIntPtr(tid));
241 return;
242 }
243 ProcessThread(thread);
244 }
245
246
247 TimelineLabelPauseInfo* TimelinePauses::GetLabel(const char* name) const {
248 ASSERT(name != NULL);
249 // Linear lookup because we expect N (# of labels in an isolate) to be small.
250 for (intptr_t i = 0; i < labels_.length(); i++) {
251 TimelineLabelPauseInfo* label = labels_.At(i);
252 if (strcmp(label->name(), name) == 0) {
253 return label;
254 }
255 }
256 return NULL;
257 }
258
259
260 int64_t TimelinePauses::InclusiveTime(const char* name) const {
261 TimelineLabelPauseInfo* pause_info = GetLabel(name);
262 ASSERT(pause_info != NULL);
263 return pause_info->inclusive_micros();
264 }
265
266
267 int64_t TimelinePauses::ExclusiveTime(const char* name) const {
268 TimelineLabelPauseInfo* pause_info = GetLabel(name);
269 ASSERT(pause_info != NULL);
270 return pause_info->exclusive_micros();
271 }
272
273
274 int64_t TimelinePauses::MaxDurationTime(const char* name) const {
275 TimelineLabelPauseInfo* pause_info = GetLabel(name);
276 ASSERT(pause_info != NULL);
277 return pause_info->max_duration_micros();
278 }
279
280
281 void TimelinePauses::ProcessThread(TimelineAnalysisThread* thread) {
282 ASSERT(thread != NULL);
283 stack_.Clear();
284 labels_.Clear();
285
286 TimelineAnalysisThreadEventIterator it(thread);
287 if (FLAG_trace_timeline_analysis) {
288 ISL_Print(">>> TimelinePauses::ProcessThread %" Px "\n",
289 OSThread::ThreadIdToIntPtr(thread->id()));
290 }
291 intptr_t event_count = 0;
292 while (it.HasNext()) {
293 TimelineEvent* event = it.Next();
294 if (!event->IsFinishedDuration()) {
295 // We only care about finished duration events.
296 continue;
297 }
298 int64_t start = event->TimeOrigin();
299 PopFinished(start);
300 if (!CheckStack(event)) {
301 SetError("Duration check fail.");
302 return;
303 }
304 event_count++;
305 Push(event);
306 }
307 // Pop remaining stack.
308 PopFinished(kMaxInt64);
309 if (FLAG_trace_timeline_analysis) {
310 ISL_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n",
311 OSThread::ThreadIdToIntPtr(thread->id()),
312 event_count);
313 }
314 }
315
316
317 // Verify that |event| is contained within all parent events on the stack.
318 bool TimelinePauses::CheckStack(TimelineEvent* event) {
319 ASSERT(event != NULL);
320 for (intptr_t i = 0; i < stack_.length(); i++) {
321 TimelineEvent* slot = stack_.At(i);
322 if (!slot->DurationContains(event)) {
323 return false;
324 }
325 }
326 return true;
327 }
328
329
330 void TimelinePauses::PopFinished(int64_t start) {
331 while (stack_.length() > 0) {
332 TimelineEvent* top = stack_.Last();
333 if (top->DurationFinishedBefore(start)) {
334 // Top of stack completes before |start|.
335 stack_.RemoveLast();
336 if (FLAG_trace_timeline_analysis) {
337 ISL_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n",
338 top->label(),
339 top->TimeEnd(),
340 start);
341 }
342 } else {
343 return;
344 }
345 }
346 }
347
348
349 void TimelinePauses::Push(TimelineEvent* event) {
350 TimelineLabelPauseInfo* pause_info = GetOrAddLabel(event->label());
351 ASSERT(pause_info != NULL);
352 // |pause_info| will be running for |event->TimeDuration()|.
353 if (FLAG_trace_timeline_analysis) {
354 ISL_Print("Pushing %s %" Pd64 " us\n",
355 pause_info->name(),
356 event->TimeDuration());
357 }
358 pause_info->OnPush(event->TimeDuration());
359 TimelineLabelPauseInfo* top_pause_info = GetTopLabel();
360 if (top_pause_info != NULL) {
361 // |top_pause_info| is under |event|'s shadow, adjust the exclusive micros.
362 if (FLAG_trace_timeline_analysis) {
363 ISL_Print("Adjusting %s by %" Pd64 " us\n",
364 top_pause_info->name(),
365 event->TimeDuration());
366 }
367 top_pause_info->OnChildPush(event->TimeDuration());
368 }
369 // Push onto the stack.
370 stack_.Add(event);
371 }
372
373
374 TimelineLabelPauseInfo* TimelinePauses::GetTopLabel() {
375 if (stack_.length() == 0) {
376 return NULL;
377 }
378 TimelineEvent* event = stack_.Last();
379 return GetLabel(event->label());
380 }
381
382
383 TimelineLabelPauseInfo* TimelinePauses::GetOrAddLabel(const char* name) {
384 ASSERT(name != NULL);
385 TimelineLabelPauseInfo* label = GetLabel(name);
386 if (label != NULL) {
387 return label;
388 }
389 // New label.
390 label = new TimelineLabelPauseInfo(name);
391 labels_.Add(label);
392 return label;
198 } 393 }
199 394
200 } // namespace dart 395 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/timeline_analysis.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698