Chromium Code Reviews| 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) { |