Index: runtime/vm/timeline.cc |
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc |
index 87093a4b6bd1bf0e1af0192e76a200881617f355..e780f49e3d9541b56b9f026f614c46645bcf6773 100644 |
--- a/runtime/vm/timeline.cc |
+++ b/runtime/vm/timeline.cc |
@@ -5,15 +5,12 @@ |
#include "platform/globals.h" |
#ifndef PRODUCT |
+#include "vm/timeline.h" |
+ |
#include <errno.h> |
#include <fcntl.h> |
#include <cstdlib> |
-#if defined(HOST_OS_FUCHSIA) |
-#include "apps/tracing/lib/trace/cwriter.h" |
-#include "apps/tracing/lib/trace/event.h" |
-#endif |
- |
#include "vm/atomic.h" |
#include "vm/isolate.h" |
#include "vm/json_stream.h" |
@@ -22,7 +19,6 @@ |
#include "vm/object.h" |
#include "vm/service_event.h" |
#include "vm/thread.h" |
-#include "vm/timeline.h" |
namespace dart { |
@@ -116,11 +112,7 @@ static TimelineEventRecorder* CreateTimelineRecorder() { |
if (FLAG_trace_timeline) { |
THR_Print("Using the Systrace timeline recorder.\n"); |
} |
-#if defined(HOST_OS_FUCHSIA) |
- return new TimelineEventFuchsiaRecorder(); |
-#else |
- return new TimelineEventSystraceRecorder(); |
-#endif |
+ return TimelineEventPlatformRecorder::CreatePlatformRecorder(); |
} |
} |
@@ -525,123 +517,6 @@ void TimelineEvent::StealArguments(intptr_t arguments_length, |
arguments_ = arguments; |
} |
-#if defined(HOST_OS_FUCHSIA) |
-// TODO(zra): The functions below emit Dart's timeline events all as category |
-// "dart". Instead, we could have finer-grained categories that make use of |
-// the name of the timeline stream, e.g. "VM", "GC", etc. |
- |
-void TimelineEvent::EmitFuchsiaEvent() { |
- if (!ctrace_is_enabled()) { |
- return; |
- } |
- auto writer = ctrace_writer_acquire(); |
- |
- // XXX: use ctrace_register_category_string(); |
- ctrace_stringref_t category; |
- ctrace_register_string(writer, "dart", &category); |
- |
- ctrace_stringref_t name; |
- ctrace_register_string(writer, label_, &name); |
- |
- ctrace_threadref_t thread; |
- ctrace_register_current_thread(writer, &thread); |
- |
- ctrace_argspec_t args[2]; |
- ctrace_arglist_t arglist = {0, args}; |
- |
- if (arguments_length_ >= 1) { |
- args[0].type = CTRACE_ARGUMENT_STRING; |
- args[0].name = arguments_[0].name; |
- args[0].u.s = arguments_[0].value; |
- arglist.n_args += 1; |
- } |
- if (arguments_length_ >= 2) { |
- args[1].type = CTRACE_ARGUMENT_STRING; |
- args[1].name = arguments_[1].name; |
- args[1].u.s = arguments_[1].value; |
- arglist.n_args += 1; |
- } |
- |
- const uint64_t time_scale = mx_ticks_per_second() / kMicrosecondsPerSecond; |
- const uint64_t start_time = LowTime() * time_scale; |
- const uint64_t end_time = HighTime() * time_scale; |
- |
- switch (event_type()) { |
- case kBegin: |
- ctrace_write_duration_begin_event_record(writer, start_time, &thread, |
- &category, &name, &arglist); |
- break; |
- case kEnd: |
- ctrace_write_duration_end_event_record(writer, end_time, &thread, |
- &category, &name, &arglist); |
- break; |
- case kInstant: |
- ctrace_write_instant_event_record(writer, start_time, &thread, &category, |
- &name, CTRACE_SCOPE_THREAD, &arglist); |
- break; |
- case kAsyncBegin: |
- ctrace_write_async_begin_event_record( |
- writer, start_time, &thread, &category, &name, AsyncId(), &arglist); |
- break; |
- case kAsyncEnd: |
- ctrace_write_async_end_event_record(writer, end_time, &thread, &category, |
- &name, AsyncId(), &arglist); |
- break; |
- case kAsyncInstant: |
- ctrace_write_async_instant_event_record( |
- writer, start_time, &thread, &category, &name, AsyncId(), &arglist); |
- break; |
- case kDuration: |
- ctrace_write_duration_event_record(writer, start_time, end_time, &thread, |
- &category, &name, &arglist); |
- break; |
- case kFlowBegin: |
- ctrace_write_flow_begin_event_record( |
- writer, start_time, &thread, &category, &name, AsyncId(), &arglist); |
- break; |
- case kFlowStep: |
- ctrace_write_flow_step_event_record( |
- writer, start_time, &thread, &category, &name, AsyncId(), &arglist); |
- break; |
- case kFlowEnd: |
- ctrace_write_flow_end_event_record(writer, start_time, &thread, &category, |
- &name, AsyncId(), &arglist); |
- break; |
- default: |
- // TODO(zra): Figure out what to do with kCounter and kMetadata. |
- break; |
- } |
- ctrace_writer_release(writer); |
-} |
-#endif |
- |
-intptr_t TimelineEvent::PrintSystrace(char* buffer, intptr_t buffer_size) { |
- ASSERT(buffer != NULL); |
- ASSERT(buffer_size > 0); |
- buffer[0] = '\0'; |
- intptr_t length = 0; |
- int64_t pid = OS::ProcessId(); |
- switch (event_type()) { |
- case kBegin: { |
- length = OS::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid, label()); |
- } break; |
- case kEnd: { |
- length = OS::SNPrint(buffer, buffer_size, "E"); |
- } break; |
- case kCounter: { |
- if (arguments_length_ > 0) { |
- // We only report the first counter value. |
- length = OS::SNPrint(buffer, buffer_size, "C|%" Pd64 "|%s|%s", pid, |
- label(), arguments_[0].value); |
- } |
- } |
- default: |
- // Ignore event types that we cannot serialize to the Systrace format. |
- break; |
- } |
- return length; |
-} |
- |
void TimelineEvent::Complete() { |
TimelineEventRecorder* recorder = Timeline::recorder(); |
if (recorder != NULL) { |
@@ -1424,91 +1299,6 @@ void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent* event) { |
ThreadBlockCompleteEvent(event); |
} |
-TimelineEventSystraceRecorder::TimelineEventSystraceRecorder(intptr_t capacity) |
- : TimelineEventFixedBufferRecorder(capacity), systrace_fd_(-1) { |
-#if defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX) |
- const char* kSystracePath = "/sys/kernel/debug/tracing/trace_marker"; |
- systrace_fd_ = open(kSystracePath, O_WRONLY); |
- if ((systrace_fd_ < 0) && FLAG_trace_timeline) { |
- OS::PrintErr("TimelineEventSystraceRecorder: Could not open `%s`\n", |
- kSystracePath); |
- } |
-#else |
- OS::PrintErr( |
- "Warning: The systrace timeline recorder is equivalent to the" |
- "ring recorder on this platform."); |
-#endif |
-} |
- |
-TimelineEventSystraceRecorder::~TimelineEventSystraceRecorder() { |
-#if defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX) |
- if (systrace_fd_ >= 0) { |
- close(systrace_fd_); |
- } |
-#endif |
-} |
- |
-TimelineEventBlock* TimelineEventSystraceRecorder::GetNewBlockLocked() { |
- // TODO(johnmccutchan): This function should only hand out blocks |
- // which have been marked as finished. |
- if (block_cursor_ == num_blocks_) { |
- block_cursor_ = 0; |
- } |
- TimelineEventBlock* block = blocks_[block_cursor_++]; |
- block->Reset(); |
- block->Open(); |
- return block; |
-} |
- |
-void TimelineEventSystraceRecorder::CompleteEvent(TimelineEvent* event) { |
- if (event == NULL) { |
- return; |
- } |
-#if defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX) |
- if (systrace_fd_ >= 0) { |
- // Serialize to the systrace format. |
- const intptr_t kBufferLength = 1024; |
- char buffer[kBufferLength]; |
- const intptr_t event_length = |
- event->PrintSystrace(&buffer[0], kBufferLength); |
- if (event_length > 0) { |
- ssize_t __result; |
- // Repeatedly attempt the write while we are being interrupted. |
- do { |
- __result = write(systrace_fd_, buffer, event_length); |
- } while ((__result == -1L) && (errno == EINTR)); |
- } |
- } |
-#endif |
- ThreadBlockCompleteEvent(event); |
-} |
- |
-#if defined(HOST_OS_FUCHSIA) |
-TimelineEventFuchsiaRecorder::TimelineEventFuchsiaRecorder(intptr_t capacity) |
- : TimelineEventFixedBufferRecorder(capacity) {} |
- |
- |
-TimelineEventBlock* TimelineEventFuchsiaRecorder::GetNewBlockLocked() { |
- // TODO(johnmccutchan): This function should only hand out blocks |
- // which have been marked as finished. |
- if (block_cursor_ == num_blocks_) { |
- block_cursor_ = 0; |
- } |
- TimelineEventBlock* block = blocks_[block_cursor_++]; |
- block->Reset(); |
- block->Open(); |
- return block; |
-} |
- |
-void TimelineEventFuchsiaRecorder::CompleteEvent(TimelineEvent* event) { |
- if (event == NULL) { |
- return; |
- } |
- event->EmitFuchsiaEvent(); |
- ThreadBlockCompleteEvent(event); |
-} |
-#endif // defined(HOST_OS_FUCHSIA) |
- |
TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { |
// TODO(johnmccutchan): This function should only hand out blocks |
// which have been marked as finished. |
@@ -1822,6 +1612,112 @@ TimelineEventBlock* TimelineEventBlockIterator::Next() { |
return r; |
} |
+void DartCommonTimelineEventHelpers::ReportTaskEvent(Thread* thread, |
+ Zone* zone, |
+ TimelineEvent* event, |
+ int64_t start, |
+ int64_t id, |
+ const char* phase, |
+ const char* category, |
+ const char* name, |
+ const char* args) { |
+ const int64_t pid = OS::ProcessId(); |
+ OSThread* os_thread = thread->os_thread(); |
+ ASSERT(os_thread != NULL); |
+ const int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id()); |
+ ASSERT(phase != NULL); |
+ ASSERT((phase[0] == 'n') || (phase[0] == 'b') || (phase[0] == 'e')); |
+ ASSERT(phase[1] == '\0'); |
+ char* json = OS::SCreate( |
+ zone, |
+ "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 |
+ "," |
+ "\"ts\":%" Pd64 ",\"ph\":\"%s\",\"id\":%" Pd64 ", \"args\":%s}", |
+ name, category, tid, pid, start, phase, id, args); |
+ switch (phase[0]) { |
+ case 'n': |
+ event->AsyncInstant("", id, start); |
+ break; |
+ case 'b': |
+ event->AsyncBegin("", id, start); |
+ break; |
+ case 'e': |
+ event->AsyncEnd("", id, start); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ |
+ // json was allocated in the zone and a copy will be stored in event. |
+ event->CompleteWithPreSerializedJSON(json); |
+} |
+ |
+void DartCommonTimelineEventHelpers::ReportCompleteEvent(Thread* thread, |
+ Zone* zone, |
+ TimelineEvent* event, |
+ int64_t start, |
+ int64_t start_cpu, |
+ const char* category, |
+ const char* name, |
+ const char* args) { |
+ const int64_t end = OS::GetCurrentMonotonicMicros(); |
+ const int64_t end_cpu = OS::GetCurrentThreadCPUMicros(); |
+ const int64_t duration = end - start; |
+ const int64_t duration_cpu = end_cpu - start_cpu; |
+ const int64_t pid = OS::ProcessId(); |
+ OSThread* os_thread = thread->os_thread(); |
+ ASSERT(os_thread != NULL); |
+ const int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id()); |
+ |
+ char* json = NULL; |
+ if ((start_cpu != -1) && (end_cpu != -1)) { |
+ json = OS::SCreate( |
+ zone, |
+ "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 |
+ "," |
+ "\"ts\":%" Pd64 ",\"ph\":\"X\",\"dur\":%" Pd64 |
+ "," |
+ "\"tdur\":%" Pd64 ",\"args\":%s}", |
+ name, category, tid, pid, start, duration, duration_cpu, args); |
+ } else { |
+ json = OS::SCreate( |
+ zone, |
+ "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 |
+ "," |
+ "\"ts\":%" Pd64 ",\"ph\":\"X\",\"dur\":%" Pd64 ",\"args\":%s}", |
+ name, category, tid, pid, start, duration, args); |
+ } |
+ ASSERT(json != NULL); |
+ |
+ event->Duration("", start, end, start_cpu, end_cpu); |
+ // json was allocated in the zone and a copy will be stored in event. |
+ event->CompleteWithPreSerializedJSON(json); |
+} |
+ |
+void DartCommonTimelineEventHelpers::ReportInstantEvent(Thread* thread, |
+ Zone* zone, |
+ TimelineEvent* event, |
+ int64_t start, |
+ const char* category, |
+ const char* name, |
+ const char* args) { |
+ const int64_t pid = OS::ProcessId(); |
+ OSThread* os_thread = thread->os_thread(); |
+ ASSERT(os_thread != NULL); |
+ const int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id()); |
+ |
+ char* json = OS::SCreate(zone, |
+ "{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 |
+ ",\"pid\":%" Pd64 |
+ "," |
+ "\"ts\":%" Pd64 ",\"ph\":\"I\",\"args\":%s}", |
+ name, category, tid, pid, start, args); |
+ |
+ event->Instant("", start); |
+ // json was allocated in the zone and a copy will be stored in event. |
+ event->CompleteWithPreSerializedJSON(json); |
+} |
+ |
} // namespace dart |
#endif // !PRODUCT |