Add API to get the VM global timeline

BUG=
R=rmacnak@google.com

Review URL: https://codereview.chromium.org//1360813002 .
This commit is contained in:
John McCutchan 2015-09-22 10:53:24 -07:00
parent f02dd6b82c
commit 59ecb80998
3 changed files with 145 additions and 30 deletions

View file

@ -976,6 +976,23 @@ typedef void (*Dart_StreamConsumer)(
DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer,
void* user_data);
/**
* Get the timeline for entire VM (including all isolates).
*
* NOTE: The timeline retrieved from this API call may not include the most
* recent events.
*
* \param consumer A Dart_StreamConsumer.
* \param user_data User data passed into consumer.
*
* NOTE: The trace-event format is documented here: https://goo.gl/hDZw5M
*
* \return True if a stream was output.
*/
DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer,
void* user_data);
/**
* Add a duration timeline event to the embedder stream for the current isolate.
*

View file

@ -5714,34 +5714,10 @@ DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask) {
}
DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer,
void* user_data) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
if (consumer == NULL) {
return false;
}
TimelineEventRecorder* timeline_recorder = Timeline::recorder();
if (timeline_recorder == NULL) {
// Nothing has been recorded.
return false;
}
// Suspend execution of other threads while serializing to JSON.
isolate->thread_registry()->SafepointThreads();
JSONStream js;
IsolateTimelineEventFilter filter(isolate);
timeline_recorder->PrintJSON(&js, &filter);
// Resume execution of other threads.
isolate->thread_registry()->ResumeAllThreads();
// 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++;
}
static void StreamToConsumer(Dart_StreamConsumer consumer,
void* user_data,
char* output,
intptr_t output_length) {
// Start stream.
const char* kStreamName = "timeline";
const intptr_t kDataSize = 64 * KB;
@ -5775,8 +5751,6 @@ DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer,
}
ASSERT(cursor == output_length);
ASSERT(remaining == 0);
// We stole the JSONStream's output buffer, free it.
free(output);
// Finish stream.
consumer(Dart_StreamConsumer_kFinish,
@ -5784,6 +5758,76 @@ DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer,
NULL,
0,
user_data);
}
DART_EXPORT bool Dart_TimelineGetTrace(Dart_StreamConsumer consumer,
void* user_data) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
if (consumer == NULL) {
return false;
}
TimelineEventRecorder* timeline_recorder = Timeline::recorder();
if (timeline_recorder == NULL) {
// Nothing has been recorded.
return false;
}
// Suspend execution of other threads while serializing to JSON.
isolate->thread_registry()->SafepointThreads();
// TODO(johnmccutchan): Reclaim open blocks from isolate so we have a complete
// timeline.
JSONStream js;
IsolateTimelineEventFilter filter(isolate);
timeline_recorder->PrintJSON(&js, &filter);
// Resume execution of other threads.
isolate->thread_registry()->ResumeAllThreads();
// 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 true;
}
DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer,
void* user_data) {
if (consumer == NULL) {
return false;
}
TimelineEventRecorder* timeline_recorder = Timeline::recorder();
if (timeline_recorder == NULL) {
// Nothing has been recorded.
return false;
}
// TODO(johnmccutchan): Reclaim all open blocks from the system so we have
// a complete timeline.
JSONStream js;
TimelineEventFilter filter;
timeline_recorder->PrintJSON(&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 true;
}

View file

@ -9483,4 +9483,58 @@ TEST_CASE(Timeline_Dart_TimelineGetTraceGlobalOverride) {
free(data.buffer);
}
UNIT_TEST_CASE(Timeline_Dart_GlobalTimelineGetTrace) {
const char* buffer = NULL;
intptr_t buffer_length = 0;
bool success = false;
// Enable all streams.
Dart_GlobalTimelineSetRecordedStreams(DART_TIMELINE_STREAM_ALL |
DART_TIMELINE_STREAM_VM);
{
// Create isolate.
TestIsolateScope __test_isolate__;
Thread* __thread__ = Thread::Current();
ASSERT(__thread__->isolate() == __test_isolate__.isolate());
StackZone __zone__(__thread__);
HandleScope __hs__(__thread__);
// Load test script.
const char* kScriptChars =
"foo() => 'a';\n"
"main() => foo();\n";
Dart_Handle lib =
TestCase::LoadTestScript(kScriptChars, NULL);
// Invoke main, which will be compiled resulting in a compiler event in
// the timeline.
Dart_Handle result = Dart_Invoke(lib,
NewString("main"),
0,
NULL);
EXPECT_VALID(result);
}
// Isolate is shutdown now.
// Grab the global trace.
AppendData data;
success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
EXPECT(success);
buffer = reinterpret_cast<char*>(data.buffer);
buffer_length = data.buffer_length;
EXPECT(buffer_length > 0);
EXPECT(buffer != NULL);
// Heartbeat test.
EXPECT_SUBSTRING("\"name\":\"InitializeIsolate\"", buffer);
EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
// Free buffer allocated by AppendStreamConsumer
free(data.buffer);
}
} // namespace dart