| 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 "vm/globals.h" |
| 6 | #if defined(HOST_OS_FUCHSIA) && defined(SUPPORT_TIMELINE) |
| 7 | #include <lib/trace-engine/context.h> |
| 8 | #include <lib/trace-engine/instrumentation.h> |
| 9 | #include <zircon/syscalls.h> |
| 10 | |
| 11 | #include "platform/utils.h" |
| 12 | #include "vm/object.h" |
| 13 | #include "vm/timeline.h" |
| 14 | |
| 15 | namespace dart { |
| 16 | |
| 17 | void TimelineEventFuchsiaRecorder::OnEvent(TimelineEvent* event) { |
| 18 | if (event == NULL) { |
| 19 | return; |
| 20 | } |
| 21 | TimelineStream* stream = event->stream_; |
| 22 | trace_string_ref_t category; |
| 23 | trace_context_t* context = trace_acquire_context_for_category_cached( |
| 24 | stream->fuchsia_name(), stream->trace_site(), &category); |
| 25 | if (context == NULL) { |
| 26 | return; |
| 27 | } |
| 28 | |
| 29 | trace_string_ref_t name; |
| 30 | if (event->owns_label()) { |
| 31 | // If the event owns the name, then the name will be deallocated, so |
| 32 | // instruct the system trace to make a copy. |
| 33 | name = trace_context_make_registered_string_copy( |
| 34 | context, event->label(), strlen(event->label())); |
| 35 | } else { |
| 36 | // If the event doesn't own the name, then it is a string literal, and |
| 37 | // the system trace can use the pointer and not a copy. |
| 38 | name = trace_context_make_registered_string_literal( |
| 39 | context, event->label()); |
| 40 | } |
| 41 | |
| 42 | trace_thread_ref_t thread; |
| 43 | trace_context_register_current_thread(context, &thread); |
| 44 | |
| 45 | trace_arg_t args[TRACE_MAX_ARGS]; |
| 46 | const intptr_t num_args = Utils::Minimum( |
| 47 | event->arguments_length(), static_cast<intptr_t>(TRACE_MAX_ARGS)); |
| 48 | |
| 49 | for (intptr_t i = 0; i < num_args; i++) { |
| 50 | const char* name = event->arguments()[i].name; |
| 51 | const char* value = event->arguments()[i].value; |
| 52 | trace_string_ref_t arg_name = |
| 53 | trace_context_make_registered_string_literal(context, name); |
| 54 | trace_string_ref_t arg_value = |
| 55 | trace_make_inline_string_ref(value, strlen(value)); |
| 56 | args[i] = trace_make_arg(arg_name, trace_make_string_arg_value(arg_value)); |
| 57 | } |
| 58 | |
| 59 | const uint64_t time_scale = zx_ticks_per_second() / kMicrosecondsPerSecond; |
| 60 | const uint64_t start_time = event->LowTime() * time_scale; |
| 61 | const uint64_t end_time = event->HighTime() * time_scale; |
| 62 | |
| 63 | // TODO(zra): The functions below emit Dart's timeline events all as category |
| 64 | // "dart". Instead, we could have finer-grained categories that make use of |
| 65 | // the name of the timeline stream, e.g. "VM", "GC", etc. |
| 66 | switch (event->event_type()) { |
| 67 | case TimelineEvent::kBegin: |
| 68 | trace_context_write_duration_begin_event_record( |
| 69 | context, start_time, &thread, &category, &name, args, num_args); |
| 70 | break; |
| 71 | case TimelineEvent::kEnd: |
| 72 | trace_context_write_duration_end_event_record( |
| 73 | context, start_time, &thread, &category, &name, args, num_args); |
| 74 | break; |
| 75 | case TimelineEvent::kInstant: |
| 76 | trace_context_write_instant_event_record( |
| 77 | context, start_time, &thread, &category, &name, TRACE_SCOPE_THREAD, |
| 78 | args, num_args); |
| 79 | break; |
| 80 | case TimelineEvent::kAsyncBegin: |
| 81 | trace_context_write_async_begin_event_record( |
| 82 | context, start_time, &thread, &category, &name, event->AsyncId(), |
| 83 | args, num_args); |
| 84 | break; |
| 85 | case TimelineEvent::kAsyncEnd: |
| 86 | trace_context_write_async_end_event_record( |
| 87 | context, end_time, &thread, &category, &name, event->AsyncId(), args, |
| 88 | num_args); |
| 89 | break; |
| 90 | case TimelineEvent::kAsyncInstant: |
| 91 | trace_context_write_async_instant_event_record( |
| 92 | context, start_time, &thread, &category, &name, event->AsyncId(), |
| 93 | args, num_args); |
| 94 | break; |
| 95 | case TimelineEvent::kDuration: |
| 96 | trace_context_write_duration_event_record(context, start_time, end_time, |
| 97 | &thread, &category, &name, args, |
| 98 | num_args); |
| 99 | break; |
| 100 | case TimelineEvent::kFlowBegin: |
| 101 | trace_context_write_flow_begin_event_record( |
| 102 | context, start_time, &thread, &category, &name, event->AsyncId(), |
| 103 | args, num_args); |
| 104 | break; |
| 105 | case TimelineEvent::kFlowStep: |
| 106 | trace_context_write_flow_step_event_record( |
| 107 | context, start_time, &thread, &category, &name, event->AsyncId(), |
| 108 | args, num_args); |
| 109 | break; |
| 110 | case TimelineEvent::kFlowEnd: |
| 111 | trace_context_write_flow_end_event_record( |
| 112 | context, start_time, &thread, &category, &name, event->AsyncId(), |
| 113 | args, num_args); |
| 114 | break; |
| 115 | default: |
| 116 | // TODO(zra): Figure out what to do with kCounter and kMetadata. |
| 117 | break; |
| 118 | } |
| 119 | trace_release_context(context); |
| 120 | } |
| 121 | |
| 122 | } // namespace dart |
| 123 | |
| 124 | #endif // defined(HOST_OS_FUCHSIA) && defined(SUPPORT_TIMELINE) |
| 125 | |