OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 #include "platform/globals.h" |
| 6 #if defined(HOST_OS_FUCHSIA) && !defined(PRODUCT) |
| 7 |
| 8 #include "apps/tracing/lib/trace/cwriter.h" |
| 9 #include "apps/tracing/lib/trace/event.h" |
| 10 #include "vm/object.h" |
| 11 #include "vm/timeline.h" |
| 12 |
| 13 namespace dart { |
| 14 |
| 15 // A recorder that sends events to Fuchsia's tracing app. Events are also stored |
| 16 // in a buffer of fixed capacity. When the buffer is full, new events overwrite |
| 17 // old events. |
| 18 // See: https://fuchsia.googlesource.com/tracing/+/HEAD/docs/usage_guide.md |
| 19 |
| 20 TimelineEventPlatformRecorder::TimelineEventPlatformRecorder(intptr_t capacity) |
| 21 : TimelineEventFixedBufferRecorder(capacity) {} |
| 22 |
| 23 TimelineEventPlatformRecorder::~TimelineEventPlatformRecorder() {} |
| 24 |
| 25 TimelineEventPlatformRecorder* |
| 26 TimelineEventPlatformRecorder::CreatePlatformRecorder(intptr_t capacity) { |
| 27 return new TimelineEventPlatformRecorder(capacity); |
| 28 } |
| 29 |
| 30 const char* TimelineEventPlatformRecorder::name() const { |
| 31 return "Fuchsia"; |
| 32 } |
| 33 |
| 34 TimelineEventBlock* TimelineEventPlatformRecorder::GetNewBlockLocked() { |
| 35 // TODO(johnmccutchan): This function should only hand out blocks |
| 36 // which have been marked as finished. |
| 37 if (block_cursor_ == num_blocks_) { |
| 38 block_cursor_ = 0; |
| 39 } |
| 40 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 41 block->Reset(); |
| 42 block->Open(); |
| 43 return block; |
| 44 } |
| 45 |
| 46 void TimelineEventPlatformRecorder::CompleteEvent(TimelineEvent* event) { |
| 47 if (event == NULL) { |
| 48 return; |
| 49 } |
| 50 if (!ctrace_is_enabled()) { |
| 51 ThreadBlockCompleteEvent(event); |
| 52 return; |
| 53 } |
| 54 auto writer = ctrace_writer_acquire(); |
| 55 |
| 56 // XXX: use ctrace_register_category_string(); |
| 57 ctrace_stringref_t category; |
| 58 ctrace_register_string(writer, "dart", &category); |
| 59 |
| 60 ctrace_stringref_t name; |
| 61 ctrace_register_string(writer, event->label(), &name); |
| 62 |
| 63 ctrace_threadref_t thread; |
| 64 ctrace_register_current_thread(writer, &thread); |
| 65 |
| 66 ctrace_argspec_t args[2]; |
| 67 ctrace_arglist_t arglist = {0, args}; |
| 68 |
| 69 if (event->arguments_length() >= 1) { |
| 70 args[0].type = CTRACE_ARGUMENT_STRING; |
| 71 args[0].name = event->arguments()[0].name; |
| 72 args[0].u.s = event->arguments()[0].value; |
| 73 arglist.n_args += 1; |
| 74 } |
| 75 if (event->arguments_length() >= 2) { |
| 76 args[1].type = CTRACE_ARGUMENT_STRING; |
| 77 args[1].name = event->arguments()[1].name; |
| 78 args[1].u.s = event->arguments()[1].value; |
| 79 arglist.n_args += 1; |
| 80 } |
| 81 |
| 82 const uint64_t time_scale = mx_ticks_per_second() / kMicrosecondsPerSecond; |
| 83 const uint64_t start_time = event->LowTime() * time_scale; |
| 84 const uint64_t end_time = event->HighTime() * time_scale; |
| 85 |
| 86 // TODO(zra): The functions below emit Dart's timeline events all as category |
| 87 // "dart". Instead, we could have finer-grained categories that make use of |
| 88 // the name of the timeline stream, e.g. "VM", "GC", etc. |
| 89 switch (event->event_type()) { |
| 90 case TimelineEvent::kBegin: |
| 91 ctrace_write_duration_begin_event_record(writer, start_time, &thread, |
| 92 &category, &name, &arglist); |
| 93 break; |
| 94 case TimelineEvent::kEnd: |
| 95 ctrace_write_duration_end_event_record(writer, end_time, &thread, |
| 96 &category, &name, &arglist); |
| 97 break; |
| 98 case TimelineEvent::kInstant: |
| 99 ctrace_write_instant_event_record(writer, start_time, &thread, &category, |
| 100 &name, CTRACE_SCOPE_THREAD, &arglist); |
| 101 break; |
| 102 case TimelineEvent::kAsyncBegin: |
| 103 ctrace_write_async_begin_event_record(writer, start_time, &thread, |
| 104 &category, &name, event->AsyncId(), |
| 105 &arglist); |
| 106 break; |
| 107 case TimelineEvent::kAsyncEnd: |
| 108 ctrace_write_async_end_event_record(writer, end_time, &thread, &category, |
| 109 &name, event->AsyncId(), &arglist); |
| 110 break; |
| 111 case TimelineEvent::kAsyncInstant: |
| 112 ctrace_write_async_instant_event_record(writer, start_time, &thread, |
| 113 &category, &name, |
| 114 event->AsyncId(), &arglist); |
| 115 break; |
| 116 case TimelineEvent::kDuration: |
| 117 ctrace_write_duration_event_record(writer, start_time, end_time, &thread, |
| 118 &category, &name, &arglist); |
| 119 break; |
| 120 case TimelineEvent::kFlowBegin: |
| 121 ctrace_write_flow_begin_event_record(writer, start_time, &thread, |
| 122 &category, &name, event->AsyncId(), |
| 123 &arglist); |
| 124 break; |
| 125 case TimelineEvent::kFlowStep: |
| 126 ctrace_write_flow_step_event_record(writer, start_time, &thread, |
| 127 &category, &name, event->AsyncId(), |
| 128 &arglist); |
| 129 break; |
| 130 case TimelineEvent::kFlowEnd: |
| 131 ctrace_write_flow_end_event_record(writer, start_time, &thread, &category, |
| 132 &name, event->AsyncId(), &arglist); |
| 133 break; |
| 134 default: |
| 135 // TODO(zra): Figure out what to do with kCounter and kMetadata. |
| 136 break; |
| 137 } |
| 138 ctrace_writer_release(writer); |
| 139 ThreadBlockCompleteEvent(event); |
| 140 } |
| 141 |
| 142 void DartTimelineEventHelpers::ReportTaskEvent(Thread* thread, |
| 143 Zone* zone, |
| 144 TimelineEvent* event, |
| 145 int64_t start, |
| 146 int64_t id, |
| 147 const char* phase, |
| 148 const char* category, |
| 149 const char* name, |
| 150 const char* args) { |
| 151 char* name_string = strdup(name); |
| 152 ASSERT(phase != NULL); |
| 153 ASSERT((phase[0] == 'n') || (phase[0] == 'b') || (phase[0] == 'e')); |
| 154 ASSERT(phase[1] == '\0'); |
| 155 switch (phase[0]) { |
| 156 case 'n': |
| 157 event->AsyncInstant(name_string, id, start); |
| 158 break; |
| 159 case 'b': |
| 160 event->AsyncBegin(name_string, id, start); |
| 161 break; |
| 162 case 'e': |
| 163 event->AsyncEnd(name_string, id, start); |
| 164 break; |
| 165 default: |
| 166 UNREACHABLE(); |
| 167 } |
| 168 event->set_owns_label(true); |
| 169 event->SetNumArguments(1); |
| 170 event->CopyArgument(0, "args", args); |
| 171 event->Complete(); |
| 172 } |
| 173 |
| 174 void DartTimelineEventHelpers::ReportCompleteEvent(Thread* thread, |
| 175 Zone* zone, |
| 176 TimelineEvent* event, |
| 177 int64_t start, |
| 178 int64_t start_cpu, |
| 179 const char* category, |
| 180 const char* name, |
| 181 const char* args) { |
| 182 const int64_t end = OS::GetCurrentMonotonicMicros(); |
| 183 const int64_t end_cpu = OS::GetCurrentThreadCPUMicros(); |
| 184 event->Duration(strdup(name), start, end, start_cpu, end_cpu); |
| 185 event->set_owns_label(true); |
| 186 event->SetNumArguments(1); |
| 187 event->CopyArgument(0, "args", args); |
| 188 event->Complete(); |
| 189 } |
| 190 |
| 191 void DartTimelineEventHelpers::ReportInstantEvent(Thread* thread, |
| 192 Zone* zone, |
| 193 TimelineEvent* event, |
| 194 int64_t start, |
| 195 const char* category, |
| 196 const char* name, |
| 197 const char* args) { |
| 198 event->Instant(strdup(name), start); |
| 199 event->set_owns_label(true); |
| 200 event->SetNumArguments(1); |
| 201 event->CopyArgument(0, "args", args); |
| 202 event->Complete(); |
| 203 } |
| 204 |
| 205 } // namespace dart |
| 206 |
| 207 #endif // defined(HOST_OS_FUCHSIA) && !defined(PRODUCT) |
OLD | NEW |