Index: runtime/vm/timeline.cc |
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc |
index 8fb0768800b07af5f3d3883b9dc1f6ba56964e9d..caa19174a7f00366172fc1926c0be8a5d95a527b 100644 |
--- a/runtime/vm/timeline.cc |
+++ b/runtime/vm/timeline.cc |
@@ -27,6 +27,10 @@ DEFINE_FLAG(bool, timing, false, |
DEFINE_FLAG(charp, timeline_dir, NULL, |
"Enable all timeline trace streams and output VM global trace " |
"into specified directory."); |
+DEFINE_FLAG(charp, timeline_streams, NULL, |
+ "Comma separated list of timeline streams to record. " |
+ "Valid values: all, api, compiler, dart, debugger, embedder, " |
+ "gc, isolate, and vm."); |
// Implementation notes: |
// |
@@ -70,6 +74,60 @@ DEFINE_FLAG(charp, timeline_dir, NULL, |
// |TimelineEventRecorder::lock_| |
// |
+ |
+// Returns a caller freed array of stream names in FLAG_timeline_streams. |
+static MallocGrowableArray<char*>* GetEnabledByDefaultTimelineStreams() { |
+ MallocGrowableArray<char*>* result = new MallocGrowableArray<char*>(); |
+ if (FLAG_timeline_streams == NULL) { |
+ // Nothing set. |
+ return result; |
+ } |
+ char* save_ptr; // Needed for strtok_r. |
+ // strtok modifies arg 1 so we make a copy of it. |
+ char* streams = strdup(FLAG_timeline_streams); |
+ char* token = strtok_r(streams, ",", &save_ptr); |
+ while (token != NULL) { |
+ result->Add(strdup(token)); |
+ token = strtok_r(NULL, ",", &save_ptr); |
+ } |
+ free(streams); |
+ for (intptr_t i = 0; i < result->length(); i++) { |
+ const char* s = (*result)[i]; |
+ OS::Print("%s\n", s); |
zra
2016/02/12 18:57:56
Leftover debug print?
Cutch
2016/02/12 20:13:57
Done.
|
+ } |
+ return result; |
+} |
+ |
+ |
+// Frees the result of |GetEnabledByDefaultTimelineStreams|. |
+static void FreeEnabledByDefaultTimelineStreams( |
+ MallocGrowableArray<char*>* streams) { |
+ if (streams == NULL) { |
+ return; |
+ } |
+ for (intptr_t i = 0; i < streams->length(); i++) { |
+ free((*streams)[i]); |
+ } |
+ delete streams; |
+} |
+ |
+ |
+// Returns true if |streams| contains |stream| or "all". Not case sensitive. |
+static bool HasStream(MallocGrowableArray<char*>* streams, const char* stream) { |
+ if ((FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline) { |
+ return true; |
+ } |
+ for (intptr_t i = 0; i < streams->length(); i++) { |
+ const char* checked_stream = (*streams)[i]; |
+ if ((strcasestr(checked_stream, "all") != NULL) || |
+ (strcasestr(checked_stream, stream) != NULL)) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+ |
void Timeline::InitOnce() { |
ASSERT(recorder_ == NULL); |
// Default to ring recorder being enabled. |
@@ -82,15 +140,23 @@ void Timeline::InitOnce() { |
} else if (use_ring_recorder) { |
recorder_ = new TimelineEventRingRecorder(); |
} |
- vm_stream_.Init("VM", EnableStreamByDefault("VM"), NULL); |
+ MallocGrowableArray<char*>* enabled_streams = |
+ GetEnabledByDefaultTimelineStreams(); |
+ vm_stream_.Init("VM", HasStream(enabled_streams, "VM"), NULL); |
vm_api_stream_.Init("API", |
- EnableStreamByDefault("API"), |
+ HasStream(enabled_streams, "API"), |
&stream_API_enabled_); |
// Global overrides. |
#define ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ |
- stream_##name##_enabled_ = EnableStreamByDefault(#name); |
+ stream_##name##_enabled_ = HasStream(enabled_streams, #name); |
ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT) |
#undef ISOLATE_TIMELINE_STREAM_FLAG_DEFAULT |
+ FreeEnabledByDefaultTimelineStreams(enabled_streams); |
zra
2016/02/12 18:57:56
Will this ever be different? Why not cache it some
Cutch
2016/02/12 20:13:57
Done.
|
+} |
+ |
+ |
+void Timeline::SetVMStreamEnabled(bool enabled) { |
+ vm_stream_.set_enabled(enabled); |
} |
@@ -115,10 +181,19 @@ TimelineEventRecorder* Timeline::recorder() { |
return recorder_; |
} |
zra
2016/02/12 18:57:56
Missing newline
Cutch
2016/02/12 20:13:57
Done.
|
+void Timeline::SetupIsolateStreams(Isolate* isolate) { |
+ MallocGrowableArray<char*>* enabled_streams = |
+ GetEnabledByDefaultTimelineStreams(); |
-bool Timeline::EnableStreamByDefault(const char* stream_name) { |
- // TODO(johnmccutchan): Allow for command line control over streams. |
- return (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; |
+#define ISOLATE_TIMELINE_STREAM_INIT(name, enabled_by_default) \ |
+ isolate->Get##name##Stream()->Init( \ |
+ #name, \ |
+ (enabled_by_default || HasStream(enabled_streams, #name)), \ |
+ Timeline::Stream##name##EnabledFlag()); |
+ ISOLATE_TIMELINE_STREAM_LIST(ISOLATE_TIMELINE_STREAM_INIT); |
+#undef ISOLATE_TIMELINE_STREAM_INIT |
+ |
+ FreeEnabledByDefaultTimelineStreams(enabled_streams); |
} |
@@ -154,6 +229,37 @@ void Timeline::ReclaimCachedBlocksFromThreads() { |
} |
+void Timeline::PrintFlagsToJSON(JSONStream* js) { |
+ JSONObject obj(js); |
+ obj.AddProperty("type", "TimelineFlags"); |
+ TimelineEventRecorder* recorder = Timeline::recorder(); |
+ if (recorder == NULL) { |
+ obj.AddProperty("recorderName", "null"); |
+ } else { |
+ obj.AddProperty("recorderName", recorder->name()); |
+ } |
+ { |
+ JSONArray availableStreams(&obj, "availableStreams"); |
+#define ADD_STREAM_NAME(name, not_used) \ |
+ availableStreams.AddValue(#name); |
+ISOLATE_TIMELINE_STREAM_LIST(ADD_STREAM_NAME); |
+#undef ADD_STREAM_NAME |
+ availableStreams.AddValue("VM"); |
+ } |
+ { |
+ JSONArray recordedStreams(&obj, "recordedStreams"); |
+#define ADD_RECORDED_STREAM_NAME(name, not_used) \ |
+ if (stream_##name##_enabled_) { \ |
+ recordedStreams.AddValue(#name); \ |
+ } |
+ISOLATE_TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME); |
+#undef ADD_RECORDED_STREAM_NAME |
+ if (vm_stream_.enabled()) { |
+ recordedStreams.AddValue("VM"); |
+ } |
+ } |
+} |
+ |
zra
2016/02/12 18:57:56
Missing newline
Cutch
2016/02/12 20:13:57
Done.
|
void Timeline::Clear() { |
TimelineEventRecorder* recorder = Timeline::recorder(); |
if (recorder == NULL) { |