| 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);
|
| }
|
|
|
|
|
|
|