| // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | #include "vm/globals.h" | 
 | #if defined(HOST_OS_FUCHSIA) && defined(SUPPORT_TIMELINE) | 
 | #include <lib/trace-engine/context.h> | 
 | #include <lib/trace-engine/instrumentation.h> | 
 | #include <zircon/syscalls.h> | 
 |  | 
 | #include "platform/utils.h" | 
 | #include "vm/object.h" | 
 | #include "vm/timeline.h" | 
 |  | 
 | namespace dart { | 
 |  | 
 | void TimelineEventFuchsiaRecorder::OnEvent(TimelineEvent* event) { | 
 |   if (event == NULL) { | 
 |     return; | 
 |   } | 
 |   TimelineStream* stream = event->stream_; | 
 |   trace_string_ref_t category; | 
 |   trace_context_t* context = trace_acquire_context_for_category_cached( | 
 |       stream->fuchsia_name(), stream->trace_site(), &category); | 
 |   if (context == NULL) { | 
 |     return; | 
 |   } | 
 |  | 
 |   trace_string_ref_t name; | 
 |   if (event->owns_label()) { | 
 |     // If the event owns the name, then the name will be deallocated, so | 
 |     // instruct the system trace to make a copy. | 
 |     name = trace_context_make_registered_string_copy( | 
 |         context, event->label(), strlen(event->label())); | 
 |   } else { | 
 |     // If the event doesn't own the name, then it is a string literal, and | 
 |     // the system trace can use the pointer and not a copy. | 
 |     name = trace_context_make_registered_string_literal( | 
 |         context, event->label()); | 
 |   } | 
 |  | 
 |   trace_thread_ref_t thread; | 
 |   trace_context_register_current_thread(context, &thread); | 
 |  | 
 |   trace_arg_t args[TRACE_MAX_ARGS]; | 
 |   const intptr_t num_args = Utils::Minimum( | 
 |       event->arguments_length(), static_cast<intptr_t>(TRACE_MAX_ARGS)); | 
 |  | 
 |   for (intptr_t i = 0; i < num_args; i++) { | 
 |     const char* name = event->arguments()[i].name; | 
 |     const char* value = event->arguments()[i].value; | 
 |     trace_string_ref_t arg_name = | 
 |         trace_context_make_registered_string_literal(context, name); | 
 |     trace_string_ref_t arg_value = | 
 |         trace_make_inline_string_ref(value, strlen(value)); | 
 |     args[i] = trace_make_arg(arg_name, trace_make_string_arg_value(arg_value)); | 
 |   } | 
 |  | 
 |   const uint64_t time_scale = zx_ticks_per_second() / kMicrosecondsPerSecond; | 
 |   const uint64_t start_time = event->LowTime() * time_scale; | 
 |   const uint64_t end_time = event->HighTime() * time_scale; | 
 |  | 
 |   // 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. | 
 |   switch (event->event_type()) { | 
 |     case TimelineEvent::kBegin: | 
 |       trace_context_write_duration_begin_event_record( | 
 |           context, start_time, &thread, &category, &name, args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kEnd: | 
 |       trace_context_write_duration_end_event_record( | 
 |           context, start_time, &thread, &category, &name, args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kInstant: | 
 |       trace_context_write_instant_event_record( | 
 |           context, start_time, &thread, &category, &name, TRACE_SCOPE_THREAD, | 
 |           args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kAsyncBegin: | 
 |       trace_context_write_async_begin_event_record( | 
 |           context, start_time, &thread, &category, &name, event->AsyncId(), | 
 |           args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kAsyncEnd: | 
 |       trace_context_write_async_end_event_record( | 
 |           context, end_time, &thread, &category, &name, event->AsyncId(), args, | 
 |           num_args); | 
 |       break; | 
 |     case TimelineEvent::kAsyncInstant: | 
 |       trace_context_write_async_instant_event_record( | 
 |           context, start_time, &thread, &category, &name, event->AsyncId(), | 
 |           args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kDuration: | 
 |       trace_context_write_duration_event_record(context, start_time, end_time, | 
 |                                                 &thread, &category, &name, args, | 
 |                                                 num_args); | 
 |       break; | 
 |     case TimelineEvent::kFlowBegin: | 
 |       trace_context_write_flow_begin_event_record( | 
 |           context, start_time, &thread, &category, &name, event->AsyncId(), | 
 |           args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kFlowStep: | 
 |       trace_context_write_flow_step_event_record( | 
 |           context, start_time, &thread, &category, &name, event->AsyncId(), | 
 |           args, num_args); | 
 |       break; | 
 |     case TimelineEvent::kFlowEnd: | 
 |       trace_context_write_flow_end_event_record( | 
 |           context, start_time, &thread, &category, &name, event->AsyncId(), | 
 |           args, num_args); | 
 |       break; | 
 |     default: | 
 |       // TODO(zra): Figure out what to do with kCounter and kMetadata. | 
 |       break; | 
 |   } | 
 |   trace_release_context(context); | 
 | } | 
 |  | 
 | }  // namespace dart | 
 |  | 
 | #endif  // defined(HOST_OS_FUCHSIA) && defined(SUPPORT_TIMELINE) |