Index: runtime/vm/dart_api_impl.cc |
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc |
index b7d4325f28c8bca6131a78fca83c6a2d69f7e26d..3aa65160d8cd131307c1bbb8d71e3d38085064dc 100644 |
--- a/runtime/vm/dart_api_impl.cc |
+++ b/runtime/vm/dart_api_impl.cc |
@@ -5668,6 +5668,8 @@ DART_EXPORT void Dart_TimelineSetRecordedStreams(int64_t stream_mask) { |
(stream_mask & DART_TIMELINE_STREAM_API) != 0); |
isolate->GetCompilerStream()->set_enabled( |
(stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0); |
+ isolate->GetDartStream()->set_enabled( |
+ (stream_mask & DART_TIMELINE_STREAM_DART) != 0); |
isolate->GetEmbedderStream()->set_enabled( |
(stream_mask & DART_TIMELINE_STREAM_EMBEDDER) != 0); |
isolate->GetGCStream()->set_enabled( |
@@ -5682,6 +5684,8 @@ DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask) { |
const bool api_enabled = (stream_mask & DART_TIMELINE_STREAM_API) != 0; |
const bool compiler_enabled = |
(stream_mask & DART_TIMELINE_STREAM_COMPILER) != 0; |
+ const bool dart_enabled = |
+ (stream_mask & DART_TIMELINE_STREAM_DART) != 0; |
const bool embedder_enabled = |
(stream_mask & DART_TIMELINE_STREAM_EMBEDDER) != 0; |
const bool gc_enabled = (stream_mask & DART_TIMELINE_STREAM_GC) != 0; |
@@ -5689,6 +5693,7 @@ DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask) { |
(stream_mask & DART_TIMELINE_STREAM_ISOLATE) != 0; |
Timeline::SetStreamAPIEnabled(api_enabled); |
Timeline::SetStreamCompilerEnabled(compiler_enabled); |
+ Timeline::SetStreamDartEnabled(dart_enabled); |
Timeline::SetStreamEmbedderEnabled(embedder_enabled); |
Timeline::SetStreamGCEnabled(gc_enabled); |
Timeline::SetStreamIsolateEnabled(isolate_enabled); |
@@ -5702,40 +5707,71 @@ DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask) { |
// '[' + ']' + '\0'. |
#define MINIMUM_OUTPUT_LENGTH 3 |
-static void StreamToConsumer(Dart_StreamConsumer consumer, |
- void* user_data, |
- char* output, |
- intptr_t output_length) { |
- if (output == NULL) { |
- return; |
- } |
- if (output_length <= MINIMUM_OUTPUT_LENGTH) { |
- return; |
- } |
+// Trims the '[' and ']' characters and, depending on whether or not more events |
+// will follow, adjusts the last character of the string to either a '\0' or |
+// ','. |
+static char* TrimOutput(char* output, |
+ intptr_t* output_length, |
+ bool events_will_follow) { |
+ ASSERT(output != NULL); |
+ ASSERT(output_length != NULL); |
+ ASSERT(*output_length > MINIMUM_OUTPUT_LENGTH); |
// We expect the first character to be the opening of an array. |
ASSERT(output[0] == '['); |
// We expect the last character to be the closing of an array. |
- ASSERT(output[output_length - 2] == ']'); |
+ ASSERT(output[*output_length - 2] == ']'); |
+ if (events_will_follow) { |
+ // Replace array closing character (']') with ','. |
+ output[*output_length - 2] = ','; |
+ } else { |
+ // Replace array closing character (']') with '\0'. |
+ output[*output_length - 2] = '\0'; |
+ } |
+ // Skip the array opening character ('['). |
+ *output_length -= 2; |
+ return &output[1]; |
+} |
+ |
+ |
+static void StartStreamToConsumer(Dart_StreamConsumer consumer, |
+ void* user_data, |
+ const char* stream_name) { |
// Start stream. |
- const char* kStreamName = "timeline"; |
- const intptr_t kDataSize = 64 * KB; |
consumer(Dart_StreamConsumer_kStart, |
- kStreamName, |
+ stream_name, |
+ NULL, |
+ 0, |
+ user_data); |
+} |
+ |
+ |
+static void FinishStreamToConsumer(Dart_StreamConsumer consumer, |
+ void* user_data, |
+ const char* stream_name) { |
+ // Finish stream. |
+ consumer(Dart_StreamConsumer_kFinish, |
+ stream_name, |
NULL, |
0, |
user_data); |
+} |
- // Stream out data. Skipping the array characters. |
- // Replace array close with '\0'. |
- output[output_length - 2] = '\0'; |
- intptr_t cursor = 1; |
- output_length -= 1; |
- intptr_t remaining = output_length - 1; |
+static void DataStreamToConsumer(Dart_StreamConsumer consumer, |
+ void* user_data, |
+ const char* output, |
+ intptr_t output_length, |
+ const char* stream_name) { |
+ if (output == NULL) { |
+ return; |
+ } |
+ const intptr_t kDataSize = 64 * KB; |
+ intptr_t cursor = 0; |
+ intptr_t remaining = output_length; |
while (remaining >= kDataSize) { |
consumer(Dart_StreamConsumer_kData, |
- kStreamName, |
- reinterpret_cast<uint8_t*>(&output[cursor]), |
+ stream_name, |
+ reinterpret_cast<const uint8_t*>(&output[cursor]), |
kDataSize, |
user_data); |
cursor += kDataSize; |
@@ -5744,8 +5780,8 @@ static void StreamToConsumer(Dart_StreamConsumer consumer, |
if (remaining > 0) { |
ASSERT(remaining < kDataSize); |
consumer(Dart_StreamConsumer_kData, |
- kStreamName, |
- reinterpret_cast<uint8_t*>(&output[cursor]), |
+ stream_name, |
+ reinterpret_cast<const uint8_t*>(&output[cursor]), |
remaining, |
user_data); |
cursor += remaining; |
@@ -5753,13 +5789,53 @@ static void StreamToConsumer(Dart_StreamConsumer consumer, |
} |
ASSERT(cursor == output_length); |
ASSERT(remaining == 0); |
+} |
- // Finish stream. |
- consumer(Dart_StreamConsumer_kFinish, |
- kStreamName, |
- NULL, |
- 0, |
- user_data); |
+ |
+static bool StreamTraceEvents(Dart_StreamConsumer consumer, |
+ void* user_data, |
+ JSONStream* js, |
+ const char* dart_events) { |
+ ASSERT(js != NULL); |
+ // Steal output from JSONStream. |
+ char* output = NULL; |
+ intptr_t output_length = 0; |
+ js->Steal(const_cast<const char**>(&output), &output_length); |
+ |
+ const bool output_vm = output_length > MINIMUM_OUTPUT_LENGTH; |
+ const bool output_dart = dart_events != NULL; |
+ |
+ if (!output_vm && !output_dart) { |
+ // We stole the JSONStream's output buffer, free it. |
+ free(output); |
+ // Nothing will be emitted. |
+ return false; |
+ } |
+ |
+ // Start the stream. |
+ StartStreamToConsumer(consumer, user_data, "timeline"); |
+ |
+ // Send events from the VM. |
+ if (output_vm) { |
+ // Add one for the '\0' character. |
+ output_length++; |
+ char* trimmed_output = TrimOutput(output, &output_length, output_dart); |
+ DataStreamToConsumer(consumer, user_data, |
+ trimmed_output, output_length, "timeline"); |
+ } |
+ // We stole the JSONStream's output buffer, free it. |
+ free(output); |
+ |
+ // Send events from dart. |
+ if (output_dart) { |
+ const intptr_t dart_events_len = strlen(dart_events) + 1; // +1 for '\0'. |
+ DataStreamToConsumer(consumer, user_data, |
+ dart_events, dart_events_len, "timeline"); |
+ } |
+ |
+ // Finish the stream. |
+ FinishStreamToConsumer(consumer, user_data, "timeline"); |
+ return true; |
} |
@@ -5775,25 +5851,18 @@ DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer, |
// Nothing has been recorded. |
return false; |
} |
+ Thread* T = Thread::Current(); |
+ StackZone zone(T); |
// Reclaim all blocks cached by isolate. |
Timeline::ReclaimIsolateBlocks(); |
JSONStream js; |
IsolateTimelineEventFilter filter(isolate); |
timeline_recorder->PrintTraceEvent(&js, &filter); |
- |
- // Copy output. |
- char* output = NULL; |
- intptr_t output_length = 0; |
- js.Steal(const_cast<const char**>(&output), &output_length); |
- if (output != NULL) { |
- // Add one for the '\0' character. |
- output_length++; |
- StreamToConsumer(consumer, user_data, output, output_length); |
- // We stole the JSONStream's output buffer, free it. |
- free(output); |
- return output_length > MINIMUM_OUTPUT_LENGTH; |
- } |
- return false; |
+ const char* dart_events = |
+ DartTimelineEventIterator::PrintTraceEvents(timeline_recorder, |
+ zone.GetZone(), |
+ isolate); |
+ return StreamTraceEvents(consumer, user_data, &js, dart_events); |
} |
@@ -5807,26 +5876,18 @@ DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer, |
// Nothing has been recorded. |
return false; |
} |
- |
+ Thread* T = Thread::Current(); |
+ StackZone zone(T); |
// Reclaim all blocks cached in the system. |
Timeline::ReclaimAllBlocks(); |
JSONStream js; |
TimelineEventFilter filter; |
timeline_recorder->PrintTraceEvent(&js, &filter); |
- |
- // Copy output. |
- char* output = NULL; |
- intptr_t output_length = 0; |
- js.Steal(const_cast<const char**>(&output), &output_length); |
- if (output != NULL) { |
- // Add one for the '\0' character. |
- output_length++; |
- StreamToConsumer(consumer, user_data, output, output_length); |
- // We stole the JSONStream's output buffer, free it. |
- free(output); |
- return output_length > MINIMUM_OUTPUT_LENGTH; |
- } |
- return false; |
+ const char* dart_events = |
+ DartTimelineEventIterator::PrintTraceEvents(timeline_recorder, |
+ zone.GetZone(), |
+ NULL); |
+ return StreamTraceEvents(consumer, user_data, &js, dart_events); |
} |