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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/timeline_analysis.h ('k') | runtime/vm/timeline_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/timeline_analysis.cc
diff --git a/runtime/vm/timeline_analysis.cc b/runtime/vm/timeline_analysis.cc
index 34bedda4bf06c973163a1e8201621528f17129a5..5cb2e2fb12bbb944e6646b525aad074f1452e0d5 100644
--- a/runtime/vm/timeline_analysis.cc
+++ b/runtime/vm/timeline_analysis.cc
@@ -5,11 +5,12 @@
#include "vm/timeline_analysis.h"
#include "vm/flags.h"
+#include "vm/log.h"
+#include "vm/os_thread.h"
namespace dart {
-DECLARE_FLAG(bool, trace_timeline);
-
+DEFINE_FLAG(bool, trace_timeline_analysis, false, "Trace timeline analysis");
TimelineAnalysisThread::TimelineAnalysisThread(ThreadId id)
: id_(id) {
@@ -37,6 +38,9 @@ static int CompareBlocksLowerTimeBound(TimelineEventBlock* const* a,
void TimelineAnalysisThread::Finalize() {
blocks_.Sort(CompareBlocksLowerTimeBound);
+ ISL_Print("Thread %" Px " has %" Pd " blocks\n",
+ OSThread::ThreadIdToIntPtr(id_),
+ blocks_.length());
}
@@ -156,9 +160,13 @@ void TimelineAnalysis::DiscoverThreads() {
continue;
}
if (!block->CheckBlock()) {
- // Skip bad blocks.
- // TODO(johnmccutchan): Make this into an error?
- continue;
+ if (FLAG_trace_timeline_analysis) {
+ ISL_Print("DiscoverThreads block %" Pd " "
+ "violates invariants.\n", block->block_index());
+ }
+ SetError("Block %" Pd " violates invariants. See "
+ "TimelineEventBlock::CheckBlock", block->block_index());
+ return;
}
TimelineAnalysisThread* thread = GetOrAddThread(block->thread());
ASSERT(thread != NULL);
@@ -187,6 +195,30 @@ void TimelineAnalysis::SetError(const char* format, ...) {
}
+TimelineLabelPauseInfo::TimelineLabelPauseInfo(const char* name)
+ : name_(name),
+ inclusive_micros_(0),
+ exclusive_micros_(0),
+ max_duration_micros_(0) {
+ ASSERT(name_ != NULL);
+}
+
+
+void TimelineLabelPauseInfo::OnPush(int64_t micros) {
+ add_inclusive_micros(micros);
+ add_exclusive_micros(micros);
+ if (micros > max_duration_micros_) {
+ max_duration_micros_ = micros;
+ }
+}
+
+
+void TimelineLabelPauseInfo::OnChildPush(int64_t micros) {
+ ASSERT(micros >= 0);
+ add_exclusive_micros(-micros);
+}
+
+
TimelinePauses::TimelinePauses(Zone* zone,
Isolate* isolate,
TimelineEventRecorder* recorder)
@@ -194,7 +226,170 @@ TimelinePauses::TimelinePauses(Zone* zone,
}
-void TimelinePauses::CalculatePauseTimes() {
+void TimelinePauses::Setup() {
+ BuildThreads();
+}
+
+
+void TimelinePauses::CalculatePauseTimesForThread(ThreadId tid) {
+ if (has_error()) {
+ return;
+ }
+ TimelineAnalysisThread* thread = GetThread(tid);
+ if (thread == NULL) {
+ SetError("Thread %" Px " does not exist.", OSThread::ThreadIdToIntPtr(tid));
+ return;
+ }
+ ProcessThread(thread);
+}
+
+
+TimelineLabelPauseInfo* TimelinePauses::GetLabel(const char* name) const {
+ ASSERT(name != NULL);
+ // Linear lookup because we expect N (# of labels in an isolate) to be small.
+ for (intptr_t i = 0; i < labels_.length(); i++) {
+ TimelineLabelPauseInfo* label = labels_.At(i);
+ if (strcmp(label->name(), name) == 0) {
+ return label;
+ }
+ }
+ return NULL;
+}
+
+
+int64_t TimelinePauses::InclusiveTime(const char* name) const {
+ TimelineLabelPauseInfo* pause_info = GetLabel(name);
+ ASSERT(pause_info != NULL);
+ return pause_info->inclusive_micros();
+}
+
+
+int64_t TimelinePauses::ExclusiveTime(const char* name) const {
+ TimelineLabelPauseInfo* pause_info = GetLabel(name);
+ ASSERT(pause_info != NULL);
+ return pause_info->exclusive_micros();
+}
+
+
+int64_t TimelinePauses::MaxDurationTime(const char* name) const {
+ TimelineLabelPauseInfo* pause_info = GetLabel(name);
+ ASSERT(pause_info != NULL);
+ return pause_info->max_duration_micros();
+}
+
+
+void TimelinePauses::ProcessThread(TimelineAnalysisThread* thread) {
+ ASSERT(thread != NULL);
+ stack_.Clear();
+ labels_.Clear();
+
+ TimelineAnalysisThreadEventIterator it(thread);
+ if (FLAG_trace_timeline_analysis) {
+ ISL_Print(">>> TimelinePauses::ProcessThread %" Px "\n",
+ OSThread::ThreadIdToIntPtr(thread->id()));
+ }
+ intptr_t event_count = 0;
+ while (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;
+ }
+ event_count++;
+ Push(event);
+ }
+ // Pop remaining stack.
+ PopFinished(kMaxInt64);
+ if (FLAG_trace_timeline_analysis) {
+ ISL_Print("<<< TimelinePauses::ProcessThread %" Px " had %" Pd " events\n",
+ OSThread::ThreadIdToIntPtr(thread->id()),
+ event_count);
+ }
+}
+
+
+// Verify that |event| is contained within all parent events on the stack.
+bool TimelinePauses::CheckStack(TimelineEvent* event) {
+ ASSERT(event != NULL);
+ for (intptr_t i = 0; i < stack_.length(); i++) {
+ TimelineEvent* slot = stack_.At(i);
+ if (!slot->DurationContains(event)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+void TimelinePauses::PopFinished(int64_t start) {
+ while (stack_.length() > 0) {
+ TimelineEvent* top = stack_.Last();
+ if (top->DurationFinishedBefore(start)) {
+ // Top of stack completes before |start|.
+ stack_.RemoveLast();
+ if (FLAG_trace_timeline_analysis) {
+ ISL_Print("Popping %s (%" Pd64 " <= %" Pd64 ")\n",
+ top->label(),
+ top->TimeEnd(),
+ start);
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+
+void TimelinePauses::Push(TimelineEvent* event) {
+ TimelineLabelPauseInfo* pause_info = GetOrAddLabel(event->label());
+ ASSERT(pause_info != NULL);
+ // |pause_info| will be running for |event->TimeDuration()|.
+ if (FLAG_trace_timeline_analysis) {
+ ISL_Print("Pushing %s %" Pd64 " us\n",
+ pause_info->name(),
+ event->TimeDuration());
+ }
+ pause_info->OnPush(event->TimeDuration());
+ TimelineLabelPauseInfo* top_pause_info = GetTopLabel();
+ if (top_pause_info != NULL) {
+ // |top_pause_info| is under |event|'s shadow, adjust the exclusive micros.
+ if (FLAG_trace_timeline_analysis) {
+ ISL_Print("Adjusting %s by %" Pd64 " us\n",
+ top_pause_info->name(),
+ event->TimeDuration());
+ }
+ top_pause_info->OnChildPush(event->TimeDuration());
+ }
+ // Push onto the stack.
+ stack_.Add(event);
+}
+
+
+TimelineLabelPauseInfo* TimelinePauses::GetTopLabel() {
+ if (stack_.length() == 0) {
+ return NULL;
+ }
+ TimelineEvent* event = stack_.Last();
+ return GetLabel(event->label());
+}
+
+
+TimelineLabelPauseInfo* TimelinePauses::GetOrAddLabel(const char* name) {
+ ASSERT(name != NULL);
+ TimelineLabelPauseInfo* label = GetLabel(name);
+ if (label != NULL) {
+ return label;
+ }
+ // New label.
+ label = new TimelineLabelPauseInfo(name);
+ labels_.Add(label);
+ return label;
}
} // namespace dart
« 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