Chromium Code Reviews| 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 "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" | 8 #include "vm/log.h" |
| 9 #include "vm/os_thread.h" | 9 #include "vm/os_thread.h" |
| 10 | 10 |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 | 192 |
| 193 | 193 |
| 194 void TimelineAnalysis::SetError(const char* format, ...) { | 194 void TimelineAnalysis::SetError(const char* format, ...) { |
| 195 ASSERT(!has_error_); | 195 ASSERT(!has_error_); |
| 196 ASSERT(error_msg_ == NULL); | 196 ASSERT(error_msg_ == NULL); |
| 197 has_error_ = true; | 197 has_error_ = true; |
| 198 va_list args; | 198 va_list args; |
| 199 va_start(args, format); | 199 va_start(args, format); |
| 200 error_msg_ = zone_->VPrint(format, args); | 200 error_msg_ = zone_->VPrint(format, args); |
| 201 ASSERT(error_msg_ != NULL); | 201 ASSERT(error_msg_ != NULL); |
| 202 if (FLAG_trace_timeline_analysis) { | |
| 203 OS::Print("TimelineAnalysis error = %s\n", error_msg_); | |
| 204 } | |
| 202 } | 205 } |
| 203 | 206 |
| 204 | 207 |
| 205 TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name) | 208 TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name) |
| 206 : name_(name), | 209 : name_(name), |
| 207 inclusive_micros_(0), | 210 inclusive_micros_(0), |
| 208 exclusive_micros_(0), | 211 exclusive_micros_(0), |
| 209 max_inclusive_micros_(0), | 212 max_inclusive_micros_(0), |
| 210 max_exclusive_micros_(0) { | 213 max_exclusive_micros_(0) { |
| 211 ASSERT(name_ != NULL); | 214 ASSERT(name_ != NULL); |
| 212 } | 215 } |
| 213 | 216 |
| 214 | 217 |
| 215 void TimelineLabelPauseInfo::OnPush(int64_t micros, bool already_on_stack) { | 218 void TimelineLabelPauseInfo::OnPush(int64_t micros, bool already_on_stack) { |
| 219 UpdateInclusiveMicros(micros, already_on_stack); | |
| 220 } | |
| 221 | |
| 222 | |
| 223 void TimelineLabelPauseInfo::OnPop(int64_t exclusive_micros) { | |
| 224 UpdateExclusiveMicros(exclusive_micros); | |
| 225 } | |
| 226 | |
| 227 | |
| 228 void TimelineLabelPauseInfo::OnBeginPop(int64_t inclusive_micros, | |
| 229 int64_t exclusive_micros, | |
| 230 bool already_on_stack) { | |
| 231 UpdateInclusiveMicros(inclusive_micros, already_on_stack); | |
| 232 UpdateExclusiveMicros(exclusive_micros); | |
| 233 } | |
| 234 | |
| 235 | |
| 236 void TimelineLabelPauseInfo::UpdateInclusiveMicros(int64_t inclusive_micros, | |
| 237 bool already_on_stack) { | |
| 216 if (!already_on_stack) { | 238 if (!already_on_stack) { |
| 217 // Only adjust inclusive counts if we aren't already on the stack. | 239 // Only adjust inclusive counts if we aren't already on the stack. |
| 218 add_inclusive_micros(micros); | 240 add_inclusive_micros(inclusive_micros); |
| 219 if (micros > max_inclusive_micros_) { | 241 if (inclusive_micros > max_inclusive_micros_) { |
| 220 max_inclusive_micros_ = micros; | 242 max_inclusive_micros_ = inclusive_micros; |
| 221 } | 243 } |
| 222 } | 244 } |
| 223 } | 245 } |
| 224 | 246 |
| 225 | 247 |
| 226 void TimelineLabelPauseInfo::OnPop(int64_t exclusive_micros) { | 248 void TimelineLabelPauseInfo::UpdateExclusiveMicros(int64_t exclusive_micros) { |
| 227 add_exclusive_micros(exclusive_micros); | 249 add_exclusive_micros(exclusive_micros); |
| 228 if (exclusive_micros > max_exclusive_micros_) { | 250 if (exclusive_micros > max_exclusive_micros_) { |
| 229 max_exclusive_micros_ = exclusive_micros; | 251 max_exclusive_micros_ = exclusive_micros; |
| 230 } | 252 } |
| 231 } | 253 } |
| 232 | 254 |
| 233 | 255 |
| 234 void TimelineLabelPauseInfo::Aggregate( | 256 void TimelineLabelPauseInfo::Aggregate( |
| 235 const TimelineLabelPauseInfo* thread_pause_info) { | 257 const TimelineLabelPauseInfo* thread_pause_info) { |
| 236 ASSERT(thread_pause_info != NULL); | 258 ASSERT(thread_pause_info != NULL); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 316 ASSERT(thread != NULL); | 338 ASSERT(thread != NULL); |
| 317 stack_.Clear(); | 339 stack_.Clear(); |
| 318 labels_.Clear(); | 340 labels_.Clear(); |
| 319 | 341 |
| 320 TimelineAnalysisThreadEventIterator it(thread); | 342 TimelineAnalysisThreadEventIterator it(thread); |
| 321 if (FLAG_trace_timeline_analysis) { | 343 if (FLAG_trace_timeline_analysis) { |
| 322 THR_Print(">>> TimelinePauses::ProcessThread %" Px "\n", | 344 THR_Print(">>> TimelinePauses::ProcessThread %" Px "\n", |
| 323 OSThread::ThreadIdToIntPtr(thread->id())); | 345 OSThread::ThreadIdToIntPtr(thread->id())); |
| 324 } | 346 } |
| 325 intptr_t event_count = 0; | 347 intptr_t event_count = 0; |
| 326 while (it.HasNext()) { | 348 while (!has_error() && it.HasNext()) { |
| 327 TimelineEvent* event = it.Next(); | 349 TimelineEvent* event = it.Next(); |
| 328 if (!event->IsFinishedDuration()) { | 350 if (!event->IsFinishedDuration() && !event->IsBeginOrEnd()) { |
|
rmacnak
2015/10/07 16:49:40
Would be clearer as
if (event->IsFinishedDuration
Cutch
2015/10/07 16:59:01
Done.
| |
| 329 // We only care about finished duration events. | 351 // We only care about finished duration events or begin / end. |
| 330 continue; | 352 continue; |
| 331 } | 353 } |
| 332 int64_t start = event->TimeOrigin(); | 354 if (event->IsFinishedDuration()) { |
| 333 PopFinished(start); | 355 int64_t start = event->TimeOrigin(); |
| 334 if (!CheckStack(event)) { | 356 PopFinishedDurations(start); |
| 335 SetError("Duration check fail."); | 357 if (!CheckStack(event)) { |
| 336 return; | 358 SetError("Duration check fail."); |
| 359 return; | |
| 360 } | |
| 361 event_count++; | |
| 362 Push(event); | |
| 363 } else { | |
| 364 ASSERT(event->IsBeginOrEnd()); | |
| 365 event_count++; | |
| 366 if (event->IsBegin()) { | |
| 367 PopFinishedDurations(event->TimeOrigin()); | |
| 368 Push(event); | |
| 369 } else { | |
| 370 ASSERT(event->IsEnd()); | |
| 371 PopFinishedDurations(event->TimeOrigin()); | |
| 372 PopBegin(event->label(), event->TimeOrigin()); | |
| 373 } | |
| 337 } | 374 } |
| 338 event_count++; | |
| 339 Push(event); | |
| 340 } | 375 } |
| 341 // Pop remaining stack. | 376 // Pop remaining duration stack. |
| 342 PopFinished(kMaxInt64); | 377 PopFinishedDurations(kMaxInt64); |
| 343 if (FLAG_trace_timeline_analysis) { | 378 if (FLAG_trace_timeline_analysis) { |
| 344 THR_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n", | 379 THR_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n", |
| 345 OSThread::ThreadIdToIntPtr(thread->id()), | 380 OSThread::ThreadIdToIntPtr(thread->id()), |
| 346 event_count); | 381 event_count); |
| 347 } | 382 } |
| 348 } | 383 } |
| 349 | 384 |
| 350 | 385 |
| 351 // Verify that |event| is contained within all parent events on the stack. | 386 // Verify that |event| is contained within all parent events on the stack. |
| 352 bool TimelinePauses::CheckStack(TimelineEvent* event) { | 387 bool TimelinePauses::CheckStack(TimelineEvent* event) { |
| 353 ASSERT(event != NULL); | 388 ASSERT(event != NULL); |
| 354 for (intptr_t i = 0; i < stack_.length(); i++) { | 389 for (intptr_t i = 0; i < stack_.length(); i++) { |
| 355 const StackItem& slot = stack_.At(i); | 390 const StackItem& slot = stack_.At(i); |
| 356 if (!slot.event->DurationContains(event)) { | 391 if (slot.event->IsDuration()) { |
| 357 return false; | 392 if (!slot.event->DurationContains(event)) { |
| 393 return false; | |
| 394 } | |
| 395 } else { | |
| 396 ASSERT(slot.event->IsBegin()); | |
| 397 if (slot.event->TimeOrigin() > event->TimeOrigin()) { | |
| 398 return false; | |
| 399 } | |
| 358 } | 400 } |
| 359 } | 401 } |
| 360 return true; | 402 return true; |
| 361 } | 403 } |
| 362 | 404 |
| 363 | 405 |
| 364 void TimelinePauses::PopFinished(int64_t start) { | 406 void TimelinePauses::PopFinishedDurations(int64_t start) { |
| 365 while (stack_.length() > 0) { | 407 while (stack_.length() > 0) { |
| 366 const StackItem& top = stack_.Last(); | 408 const StackItem& top = stack_.Last(); |
| 367 if (top.event->DurationFinishedBefore(start)) { | 409 if (top.event->IsDuration() && top.event->DurationFinishedBefore(start)) { |
| 368 top.pause_info->OnPop(top.exclusive_micros); | 410 top.pause_info->OnPop(top.exclusive_micros); |
| 369 // Top of stack completes before |start|. | 411 // Top of stack completes before |start|. |
| 370 stack_.RemoveLast(); | 412 stack_.RemoveLast(); |
| 371 if (FLAG_trace_timeline_analysis) { | 413 if (FLAG_trace_timeline_analysis) { |
| 372 THR_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n", | 414 THR_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n", |
| 373 top.event->label(), | 415 top.event->label(), |
| 374 top.event->TimeEnd(), | 416 top.event->TimeEnd(), |
| 375 start); | 417 start); |
| 376 } | 418 } |
| 377 } else { | 419 } else { |
| 378 return; | 420 return; |
| 379 } | 421 } |
| 380 } | 422 } |
| 381 } | 423 } |
| 382 | 424 |
| 383 | 425 |
| 426 void TimelinePauses::PopBegin(const char* label, int64_t end) { | |
| 427 if (stack_.length() == 0) { | |
| 428 SetError("PopBegin(%s, ...) called with empty stack.", label); | |
| 429 return; | |
| 430 } | |
| 431 ASSERT(stack_.length() > 0); | |
| 432 const StackItem& top = stack_.Last(); | |
| 433 const char* top_label = top.event->label(); | |
| 434 const bool top_is_begin = top.event->IsBegin(); | |
| 435 const int64_t start = top.event->TimeOrigin(); | |
| 436 if (start > end) { | |
| 437 SetError("Bad time stamps for PopBegin(%s, ...) %" Pd64 " > %" Pd64 "", | |
| 438 label, start, end); | |
| 439 return; | |
| 440 } | |
| 441 const int64_t duration = end - start; | |
| 442 // Sanity checks. | |
| 443 if (strcmp(top_label, label) != 0) { | |
| 444 SetError("PopBegin(%s, ...) called with %s at the top of stack", | |
| 445 label, top.event->label()); | |
| 446 return; | |
| 447 } | |
| 448 if (!top_is_begin) { | |
| 449 SetError("kEnd event not paired with kBegin event for label %s", | |
| 450 label); | |
| 451 return; | |
| 452 } | |
| 453 // Pop this event. | |
| 454 // Add duration to exclusive micros. | |
| 455 if (FLAG_trace_timeline_analysis) { | |
| 456 THR_Print("Popping %s (%" Pd64 ")\n", | |
| 457 top.event->label(), | |
| 458 duration); | |
| 459 } | |
| 460 const int64_t exclusive_micros = top.exclusive_micros + duration; | |
| 461 stack_.RemoveLast(); | |
| 462 top.pause_info->OnBeginPop(duration, | |
| 463 exclusive_micros, | |
| 464 IsLabelOnStack(top_label)); | |
| 465 if (StackDepth() > 0) { | |
| 466 StackItem& top = GetStackTop(); | |
| 467 // |top| is under the popped |event|'s shadow, adjust the exclusive micros. | |
| 468 top.exclusive_micros -= duration; | |
| 469 } | |
| 470 } | |
| 471 | |
| 472 | |
| 384 void TimelinePauses::Push(TimelineEvent* event) { | 473 void TimelinePauses::Push(TimelineEvent* event) { |
| 385 TimelineLabelPauseInfo* pause_info = GetOrAddLabelPauseInfo(event->label()); | 474 TimelineLabelPauseInfo* pause_info = GetOrAddLabelPauseInfo(event->label()); |
| 386 ASSERT(pause_info != NULL); | 475 ASSERT(pause_info != NULL); |
| 387 // |pause_info| will be running for |event->TimeDuration()|. | 476 // |pause_info| will be running for |event->TimeDuration()|. |
| 388 if (FLAG_trace_timeline_analysis) { | 477 if (FLAG_trace_timeline_analysis) { |
| 389 THR_Print("Pushing %s %" Pd64 " us\n", | 478 THR_Print("Pushing %s %" Pd64 " us\n", |
| 390 pause_info->name(), | 479 pause_info->name(), |
| 391 event->TimeDuration()); | 480 event->TimeDuration()); |
| 392 } | 481 } |
| 393 pause_info->OnPush(event->TimeDuration(), IsLabelOnStack(event->label())); | 482 if (event->IsDuration()) { |
| 394 if (StackDepth() > 0) { | 483 pause_info->OnPush(event->TimeDuration(), IsLabelOnStack(event->label())); |
| 395 StackItem& top = GetStackTop(); | 484 if (StackDepth() > 0) { |
| 396 // |top| is under |event|'s shadow, adjust the exclusive micros. | 485 StackItem& top = GetStackTop(); |
| 397 top.exclusive_micros -= event->TimeDuration(); | 486 // |top| is under |event|'s shadow, adjust the exclusive micros. |
| 487 top.exclusive_micros -= event->TimeDuration(); | |
| 488 } | |
| 489 // Push onto the stack. | |
| 490 StackItem item; | |
| 491 item.event = event; | |
| 492 item.pause_info = pause_info; | |
| 493 item.exclusive_micros = event->TimeDuration(); | |
| 494 stack_.Add(item); | |
| 495 } else { | |
| 496 ASSERT(event->IsBegin()); | |
| 497 pause_info->OnPush(0, IsLabelOnStack(event->label())); | |
| 498 // Push onto the stack. | |
| 499 StackItem item; | |
| 500 item.event = event; | |
| 501 item.pause_info = pause_info; | |
| 502 item.exclusive_micros = 0; | |
| 503 stack_.Add(item); | |
| 398 } | 504 } |
| 399 // Push onto the stack. | |
| 400 StackItem item; | |
| 401 item.event = event; | |
| 402 item.pause_info = pause_info; | |
| 403 item.exclusive_micros = event->TimeDuration(); | |
| 404 stack_.Add(item); | |
| 405 } | 505 } |
| 406 | 506 |
| 407 | 507 |
| 408 bool TimelinePauses::IsLabelOnStack(const char* label) const { | 508 bool TimelinePauses::IsLabelOnStack(const char* label) const { |
| 409 ASSERT(label != NULL); | 509 ASSERT(label != NULL); |
| 410 for (intptr_t i = 0; i < stack_.length(); i++) { | 510 for (intptr_t i = 0; i < stack_.length(); i++) { |
| 411 const StackItem& slot = stack_.At(i); | 511 const StackItem& slot = stack_.At(i); |
| 412 if (strcmp(slot.event->label(), label) == 0) { | 512 if (strcmp(slot.event->label(), label) == 0) { |
| 413 return true; | 513 return true; |
| 414 } | 514 } |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 MicrosecondsToMilliseconds(pause_info->inclusive_micros())); | 626 MicrosecondsToMilliseconds(pause_info->inclusive_micros())); |
| 527 THR_Print("%.3f ms total executing; ", | 627 THR_Print("%.3f ms total executing; ", |
| 528 MicrosecondsToMilliseconds(pause_info->exclusive_micros())); | 628 MicrosecondsToMilliseconds(pause_info->exclusive_micros())); |
| 529 THR_Print("%.3f ms max on stack; ", | 629 THR_Print("%.3f ms max on stack; ", |
| 530 MicrosecondsToMilliseconds(pause_info->max_inclusive_micros())); | 630 MicrosecondsToMilliseconds(pause_info->max_inclusive_micros())); |
| 531 THR_Print("%.3f ms max executing.\n", | 631 THR_Print("%.3f ms max executing.\n", |
| 532 MicrosecondsToMilliseconds(pause_info->max_exclusive_micros())); | 632 MicrosecondsToMilliseconds(pause_info->max_exclusive_micros())); |
| 533 } | 633 } |
| 534 | 634 |
| 535 } // namespace dart | 635 } // namespace dart |
| OLD | NEW |