blob: 218657bed2cf56023528d2e03a28de2b1baf01ca [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/sky/shell/tracing_controller.h"
#include <string>
#include "base/trace_event/trace_event.h"
#include "dart/runtime/include/dart_tools_api.h"
#include "flutter/common/threads.h"
#include "flutter/runtime/dart_init.h"
#include "flutter/sky/shell/shell.h"
#include "lib/ftl/logging.h"
namespace sky {
namespace shell {
TracingController::TracingController()
: picture_tracing_enabled_(false), tracing_active_(false) {
blink::SetEmbedderTracingCallbacks(
std::unique_ptr<blink::EmbedderTracingCallbacks>(
new blink::EmbedderTracingCallbacks([this]() { StartTracing(); },
[this]() { StopTracing(); })));
}
TracingController::~TracingController() {
blink::SetEmbedderTracingCallbacks(nullptr);
}
static const char* WARN_UNUSED_RESULT
ConstructDartTimelineValue(std::vector<void*>& free_list,
const char* format,
...) {
static const char* kConversionError = "Argument Conversion Error";
const char* return_value = nullptr;
va_list args;
va_start(args, format);
char* string;
if (vasprintf(&string, format, args) != -1) {
return_value = string;
free_list.push_back(string);
} else {
return_value = kConversionError;
}
va_end(args);
return return_value;
}
static void BaseTraceEventCallback(base::TraceTicks timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
int num_args,
const char* const arg_names[],
const unsigned char arg_types[],
const unsigned long long arg_values[],
unsigned int flags) {
Dart_Timeline_Event_Type type = Dart_Timeline_Event_Begin;
switch (phase) {
case TRACE_EVENT_PHASE_BEGIN:
type = Dart_Timeline_Event_Begin;
break;
case TRACE_EVENT_PHASE_END:
type = Dart_Timeline_Event_End;
break;
case TRACE_EVENT_PHASE_INSTANT:
type = Dart_Timeline_Event_Instant;
break;
case TRACE_EVENT_PHASE_ASYNC_BEGIN:
type = Dart_Timeline_Event_Async_Begin;
break;
case TRACE_EVENT_PHASE_ASYNC_END:
type = Dart_Timeline_Event_Async_End;
break;
case TRACE_EVENT_PHASE_COUNTER:
type = Dart_Timeline_Event_Counter;
break;
default:
// For TRACE_EVENT_PHASE_COMPLETE events, this callback still receives
// discrete begin-end pairs. This greatly simplifies things. We dont have
// to track the second timestamp to pass to the Dart timeline event
// because we never see a Dart_Timeline_Event_Duration event.
FTL_DCHECK(false) << "Unknown trace event phase";
return;
}
// Try to convert all arguments to strings to pass to the Dart timeline.
char const* dart_argument_values[num_args];
std::vector<void*> free_list;
#define CONVERT_VAL(format) \
dart_argument_values[i] = \
ConstructDartTimelineValue(free_list, format, arg_values[i])
for (int i = 0; i < num_args; i++) {
switch (arg_types[i]) {
case TRACE_VALUE_TYPE_BOOL:
CONVERT_VAL("%d");
break;
case TRACE_VALUE_TYPE_UINT:
CONVERT_VAL("%u");
break;
case TRACE_VALUE_TYPE_INT:
CONVERT_VAL("%d");
break;
case TRACE_VALUE_TYPE_DOUBLE:
CONVERT_VAL("%f");
break;
case TRACE_VALUE_TYPE_POINTER:
CONVERT_VAL("%p");
break;
case TRACE_VALUE_TYPE_STRING:
case TRACE_VALUE_TYPE_COPY_STRING:
// We don't need to reallocate for strings since the string will be
// used within this scope.
dart_argument_values[i] = reinterpret_cast<char*>(arg_values[i]);
break;
default:
continue;
}
}
#undef CONVERT_VAL
Dart_TimelineEvent(name, // label
timestamp.ToInternalValue(), // timestamp0
0, // timestamp1_or_async_id
type, // event type
num_args, // argument_count
(const char**)(arg_names), // argument_names
(const char**)(dart_argument_values) // argument_values
);
// Free up the items that had to be heap allocated (if any)
for (void* item : free_list) {
free(item);
}
}
static void AddTraceMetadata() {
blink::Threads::Gpu()->PostTask([]() { Dart_SetThreadName("gpu_thread"); });
blink::Threads::UI()->PostTask([]() { Dart_SetThreadName("ui_thread"); });
blink::Threads::IO()->PostTask([]() { Dart_SetThreadName("io_thread"); });
}
void TracingController::StartTracing() {
if (tracing_active_)
return;
tracing_active_ = true;
StartBaseTracing();
AddTraceMetadata();
}
void TracingController::StartBaseTracing() {
auto config = base::trace_event::TraceConfig(
"*,disabled-by-default-skia", base::trace_event::RECORD_CONTINUOUSLY);
auto log = base::trace_event::TraceLog::GetInstance();
log->SetEnabled(config, base::trace_event::TraceLog::MONITORING_MODE);
log->SetEventCallbackEnabled(config, &BaseTraceEventCallback);
}
void TracingController::StopTracing() {
if (!tracing_active_) {
return;
}
tracing_active_ = false;
StopBaseTracing();
}
void TracingController::StopBaseTracing() {
auto trace_log = base::trace_event::TraceLog::GetInstance();
trace_log->SetDisabled();
trace_log->SetEventCallbackDisabled();
}
std::string TracingController::TracePathWithExtension(
const std::string& directory,
const std::string& extension) const {
base::Time::Exploded exploded;
base::Time now = base::Time::Now();
now.LocalExplode(&exploded);
std::stringstream stream;
// Example: trace_2015-10-08_at_11.38.25.121_.extension
stream << directory << "/trace_" << exploded.year << "-" << exploded.month
<< "-" << exploded.day_of_month << "_at_" << exploded.hour << "."
<< exploded.minute << "." << exploded.second << "."
<< exploded.millisecond << "." << extension;
return stream.str();
}
std::string TracingController::PictureTracingPathForCurrentTime() const {
return PictureTracingPathForCurrentTime(traces_base_path_);
}
std::string TracingController::PictureTracingPathForCurrentTime(
const std::string& directory) const {
return TracePathWithExtension(directory, "skp");
}
} // namespace shell
} // namespace sky