| Index: runtime/vm/timeline_analysis.cc
|
| diff --git a/runtime/vm/timeline_analysis.cc b/runtime/vm/timeline_analysis.cc
|
| index 1ca8442a2d8ba32f7898839b04ce0774bb2e027c..faf2f5e504c2aa3e78a16103a1122a57c379a1d9 100644
|
| --- a/runtime/vm/timeline_analysis.cc
|
| +++ b/runtime/vm/timeline_analysis.cc
|
| @@ -199,6 +199,9 @@ void TimelineAnalysis::SetError(const char* format, ...) {
|
| va_start(args, format);
|
| error_msg_ = zone_->VPrint(format, args);
|
| ASSERT(error_msg_ != NULL);
|
| + if (FLAG_trace_timeline_analysis) {
|
| + OS::Print("TimelineAnalysis error = %s\n", error_msg_);
|
| + }
|
| }
|
|
|
|
|
| @@ -213,17 +216,36 @@ TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name)
|
|
|
|
|
| void TimelineLabelPauseInfo::OnPush(int64_t micros, bool already_on_stack) {
|
| + UpdateInclusiveMicros(micros, already_on_stack);
|
| +}
|
| +
|
| +
|
| +void TimelineLabelPauseInfo::OnPop(int64_t exclusive_micros) {
|
| + UpdateExclusiveMicros(exclusive_micros);
|
| +}
|
| +
|
| +
|
| +void TimelineLabelPauseInfo::OnBeginPop(int64_t inclusive_micros,
|
| + int64_t exclusive_micros,
|
| + bool already_on_stack) {
|
| + UpdateInclusiveMicros(inclusive_micros, already_on_stack);
|
| + UpdateExclusiveMicros(exclusive_micros);
|
| +}
|
| +
|
| +
|
| +void TimelineLabelPauseInfo::UpdateInclusiveMicros(int64_t inclusive_micros,
|
| + bool already_on_stack) {
|
| if (!already_on_stack) {
|
| // Only adjust inclusive counts if we aren't already on the stack.
|
| - add_inclusive_micros(micros);
|
| - if (micros > max_inclusive_micros_) {
|
| - max_inclusive_micros_ = micros;
|
| + add_inclusive_micros(inclusive_micros);
|
| + if (inclusive_micros > max_inclusive_micros_) {
|
| + max_inclusive_micros_ = inclusive_micros;
|
| }
|
| }
|
| }
|
|
|
|
|
| -void TimelineLabelPauseInfo::OnPop(int64_t exclusive_micros) {
|
| +void TimelineLabelPauseInfo::UpdateExclusiveMicros(int64_t exclusive_micros) {
|
| add_exclusive_micros(exclusive_micros);
|
| if (exclusive_micros > max_exclusive_micros_) {
|
| max_exclusive_micros_ = exclusive_micros;
|
| @@ -323,23 +345,33 @@ void TimelinePauses::ProcessThread(TimelineAnalysisThread* thread) {
|
| OSThread::ThreadIdToIntPtr(thread->id()));
|
| }
|
| intptr_t event_count = 0;
|
| - while (it.HasNext()) {
|
| + while (!has_error() && it.HasNext()) {
|
| TimelineEvent* event = it.Next();
|
| - if (!event->IsFinishedDuration()) {
|
| - // We only care about finished duration events.
|
| - continue;
|
| - }
|
| - int64_t start = event->TimeOrigin();
|
| - PopFinished(start);
|
| - if (!CheckStack(event)) {
|
| - SetError("Duration check fail.");
|
| - return;
|
| + if (event->IsFinishedDuration()) {
|
| + int64_t start = event->TimeOrigin();
|
| + PopFinishedDurations(start);
|
| + if (!CheckStack(event)) {
|
| + SetError("Duration check fail.");
|
| + return;
|
| + }
|
| + event_count++;
|
| + Push(event);
|
| + } else if (event->IsBeginOrEnd()) {
|
| + event_count++;
|
| + if (event->IsBegin()) {
|
| + PopFinishedDurations(event->TimeOrigin());
|
| + Push(event);
|
| + } else {
|
| + ASSERT(event->IsEnd());
|
| + PopFinishedDurations(event->TimeOrigin());
|
| + PopBegin(event->label(), event->TimeOrigin());
|
| + }
|
| + } else {
|
| + // Skip other event kinds.
|
| }
|
| - event_count++;
|
| - Push(event);
|
| }
|
| - // Pop remaining stack.
|
| - PopFinished(kMaxInt64);
|
| + // Pop remaining duration stack.
|
| + PopFinishedDurations(kMaxInt64);
|
| if (FLAG_trace_timeline_analysis) {
|
| THR_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n",
|
| OSThread::ThreadIdToIntPtr(thread->id()),
|
| @@ -353,18 +385,25 @@ bool TimelinePauses::CheckStack(TimelineEvent* event) {
|
| ASSERT(event != NULL);
|
| for (intptr_t i = 0; i < stack_.length(); i++) {
|
| const StackItem& slot = stack_.At(i);
|
| - if (!slot.event->DurationContains(event)) {
|
| - return false;
|
| + if (slot.event->IsDuration()) {
|
| + if (!slot.event->DurationContains(event)) {
|
| + return false;
|
| + }
|
| + } else {
|
| + ASSERT(slot.event->IsBegin());
|
| + if (slot.event->TimeOrigin() > event->TimeOrigin()) {
|
| + return false;
|
| + }
|
| }
|
| }
|
| return true;
|
| }
|
|
|
|
|
| -void TimelinePauses::PopFinished(int64_t start) {
|
| +void TimelinePauses::PopFinishedDurations(int64_t start) {
|
| while (stack_.length() > 0) {
|
| const StackItem& top = stack_.Last();
|
| - if (top.event->DurationFinishedBefore(start)) {
|
| + if (top.event->IsDuration() && top.event->DurationFinishedBefore(start)) {
|
| top.pause_info->OnPop(top.exclusive_micros);
|
| // Top of stack completes before |start|.
|
| stack_.RemoveLast();
|
| @@ -381,6 +420,53 @@ void TimelinePauses::PopFinished(int64_t start) {
|
| }
|
|
|
|
|
| +void TimelinePauses::PopBegin(const char* label, int64_t end) {
|
| + if (stack_.length() == 0) {
|
| + SetError("PopBegin(%s, ...) called with empty stack.", label);
|
| + return;
|
| + }
|
| + ASSERT(stack_.length() > 0);
|
| + const StackItem& top = stack_.Last();
|
| + const char* top_label = top.event->label();
|
| + const bool top_is_begin = top.event->IsBegin();
|
| + const int64_t start = top.event->TimeOrigin();
|
| + if (start > end) {
|
| + SetError("Bad time stamps for PopBegin(%s, ...) %" Pd64 " > %" Pd64 "",
|
| + label, start, end);
|
| + return;
|
| + }
|
| + const int64_t duration = end - start;
|
| + // Sanity checks.
|
| + if (strcmp(top_label, label) != 0) {
|
| + SetError("PopBegin(%s, ...) called with %s at the top of stack",
|
| + label, top.event->label());
|
| + return;
|
| + }
|
| + if (!top_is_begin) {
|
| + SetError("kEnd event not paired with kBegin event for label %s",
|
| + label);
|
| + return;
|
| + }
|
| + // Pop this event.
|
| + // Add duration to exclusive micros.
|
| + if (FLAG_trace_timeline_analysis) {
|
| + THR_Print("Popping %s (%" Pd64 ")\n",
|
| + top.event->label(),
|
| + duration);
|
| + }
|
| + const int64_t exclusive_micros = top.exclusive_micros + duration;
|
| + stack_.RemoveLast();
|
| + top.pause_info->OnBeginPop(duration,
|
| + exclusive_micros,
|
| + IsLabelOnStack(top_label));
|
| + if (StackDepth() > 0) {
|
| + StackItem& top = GetStackTop();
|
| + // |top| is under the popped |event|'s shadow, adjust the exclusive micros.
|
| + top.exclusive_micros -= duration;
|
| + }
|
| +}
|
| +
|
| +
|
| void TimelinePauses::Push(TimelineEvent* event) {
|
| TimelineLabelPauseInfo* pause_info = GetOrAddLabelPauseInfo(event->label());
|
| ASSERT(pause_info != NULL);
|
| @@ -390,18 +476,29 @@ void TimelinePauses::Push(TimelineEvent* event) {
|
| pause_info->name(),
|
| event->TimeDuration());
|
| }
|
| - pause_info->OnPush(event->TimeDuration(), IsLabelOnStack(event->label()));
|
| - if (StackDepth() > 0) {
|
| - StackItem& top = GetStackTop();
|
| - // |top| is under |event|'s shadow, adjust the exclusive micros.
|
| - top.exclusive_micros -= event->TimeDuration();
|
| - }
|
| - // Push onto the stack.
|
| - StackItem item;
|
| - item.event = event;
|
| - item.pause_info = pause_info;
|
| - item.exclusive_micros = event->TimeDuration();
|
| - stack_.Add(item);
|
| + if (event->IsDuration()) {
|
| + pause_info->OnPush(event->TimeDuration(), IsLabelOnStack(event->label()));
|
| + if (StackDepth() > 0) {
|
| + StackItem& top = GetStackTop();
|
| + // |top| is under |event|'s shadow, adjust the exclusive micros.
|
| + top.exclusive_micros -= event->TimeDuration();
|
| + }
|
| + // Push onto the stack.
|
| + StackItem item;
|
| + item.event = event;
|
| + item.pause_info = pause_info;
|
| + item.exclusive_micros = event->TimeDuration();
|
| + stack_.Add(item);
|
| + } else {
|
| + ASSERT(event->IsBegin());
|
| + pause_info->OnPush(0, IsLabelOnStack(event->label()));
|
| + // Push onto the stack.
|
| + StackItem item;
|
| + item.event = event;
|
| + item.pause_info = pause_info;
|
| + item.exclusive_micros = 0;
|
| + stack_.Add(item);
|
| + }
|
| }
|
|
|
|
|
|
|