| Index: runtime/vm/timeline.cc
|
| diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
|
| index 8fb0768800b07af5f3d3883b9dc1f6ba56964e9d..43dd5656747684370b791bced2d27e2e3159fa23 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,56 @@ 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);
|
| + 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,18 +136,24 @@ void Timeline::InitOnce() {
|
| } else if (use_ring_recorder) {
|
| recorder_ = new TimelineEventRingRecorder();
|
| }
|
| - vm_stream_.Init("VM", EnableStreamByDefault("VM"), NULL);
|
| + 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
|
| }
|
|
|
|
|
| +void Timeline::SetVMStreamEnabled(bool enabled) {
|
| + vm_stream_.set_enabled(enabled);
|
| +}
|
| +
|
| +
|
| void Timeline::Shutdown() {
|
| ASSERT(recorder_ != NULL);
|
| if (FLAG_timeline_dir != NULL) {
|
| @@ -108,6 +168,10 @@ void Timeline::Shutdown() {
|
| #undef ISOLATE_TIMELINE_STREAM_DISABLE
|
| delete recorder_;
|
| recorder_ = NULL;
|
| + if (enabled_streams_ != NULL) {
|
| + FreeEnabledByDefaultTimelineStreams(enabled_streams_);
|
| + enabled_streams_ = NULL;
|
| + }
|
| }
|
|
|
|
|
| @@ -116,9 +180,14 @@ TimelineEventRecorder* Timeline::recorder() {
|
| }
|
|
|
|
|
| -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;
|
| +void Timeline::SetupIsolateStreams(Isolate* isolate) {
|
| +#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
|
| }
|
|
|
|
|
| @@ -154,6 +223,38 @@ 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");
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| void Timeline::Clear() {
|
| TimelineEventRecorder* recorder = Timeline::recorder();
|
| if (recorder == NULL) {
|
| @@ -167,6 +268,7 @@ void Timeline::Clear() {
|
| TimelineEventRecorder* Timeline::recorder_ = NULL;
|
| TimelineStream Timeline::vm_stream_;
|
| TimelineStream Timeline::vm_api_stream_;
|
| +MallocGrowableArray<char*>* Timeline::enabled_streams_ = NULL;
|
|
|
| #define ISOLATE_TIMELINE_STREAM_DEFINE_FLAG(name, enabled_by_default) \
|
| bool Timeline::stream_##name##_enabled_ = enabled_by_default;
|
|
|