Chromium Code Reviews| Index: runtime/vm/dart_api_impl.cc |
| diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc |
| index b55cdb0719863064229830e43c8b88279b42fd47..7d265fbf0916d06b005c1ec6138801e633d53c7f 100644 |
| --- a/runtime/vm/dart_api_impl.cc |
| +++ b/runtime/vm/dart_api_impl.cc |
| @@ -5680,6 +5680,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( |
| @@ -5694,6 +5696,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; |
| @@ -5701,6 +5705,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); |
| @@ -5714,40 +5719,72 @@ 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); |
| +} |
| + |
| - // 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 FinishStreamToConsumer(Dart_StreamConsumer consumer, |
| + void* user_data, |
| + const char* stream_name) { |
| + // Finish stream. |
| + consumer(Dart_StreamConsumer_kFinish, |
| + stream_name, |
| + NULL, |
| + 0, |
| + user_data); |
| +} |
| + |
| +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; |
|
rmacnak
2015/09/29 22:36:41
X
Cutch
2015/09/30 14:42:29
Done.
|
| + const intptr_t kDataSize = 16; |
| + 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; |
| @@ -5756,8 +5793,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; |
| @@ -5765,13 +5802,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; |
| } |
| @@ -5787,25 +5864,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); |
| } |
| @@ -5819,26 +5889,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); |
| } |