| // 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(DART_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 == nullptr) { | |
| 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 == nullptr) { | |
| 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->Id(), args, num_args); | |
| break; | |
| case TimelineEvent::kAsyncEnd: | |
| trace_context_write_async_end_event_record(context, end_time, &thread, | |
| &category, &name, event->Id(), | |
| args, num_args); | |
| break; | |
| case TimelineEvent::kAsyncInstant: | |
| trace_context_write_async_instant_event_record( | |
| context, start_time, &thread, &category, &name, event->Id(), 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->Id(), | |
| args, num_args); | |
| break; | |
| case TimelineEvent::kFlowStep: | |
| trace_context_write_flow_step_event_record(context, start_time, &thread, | |
| &category, &name, event->Id(), | |
| args, num_args); | |
| break; | |
| case TimelineEvent::kFlowEnd: | |
| trace_context_write_flow_end_event_record(context, start_time, &thread, | |
| &category, &name, event->Id(), | |
| 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(DART_HOST_OS_FUCHSIA) && defined(SUPPORT_TIMELINE) |