mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Dart invokes Start/StopTracing callbacks within the _setVMTimelineFlags service method whenever the embedder timeline stream toggles on or off. Flutter's implementation of these callbacks was modifying the set of enabled streams, which could override the intended behavior of _setVMTimelineFlags. Start/StopTracing will now only control Flutter's embedder-specific log. Also needed to change the Flutter engine's --trace-startup flag to set the corresponding timeline stream flag on the Dart VM.
234 lines
7.0 KiB
C++
234 lines
7.0 KiB
C++
// 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 "sky/shell/tracing_controller.h"
|
|
|
|
#include "base/threading/platform_thread.h"
|
|
#include "base/trace_event/trace_event.h"
|
|
#include "dart/runtime/include/dart_tools_api.h"
|
|
#include "sky/engine/core/script/dart_init.h"
|
|
#include "sky/engine/wtf/MakeUnique.h"
|
|
#include "sky/shell/shell.h"
|
|
|
|
#include <string>
|
|
|
|
namespace sky {
|
|
namespace shell {
|
|
|
|
TracingController::TracingController()
|
|
: picture_tracing_enabled_(false), tracing_active_(false) {
|
|
auto start =
|
|
base::Bind(&TracingController::StartTracing, base::Unretained(this));
|
|
auto stop =
|
|
base::Bind(&TracingController::StopTracing, base::Unretained(this));
|
|
|
|
blink::SetEmbedderTracingCallbacks(
|
|
WTF::MakeUnique<blink::EmbedderTracingCallbacks>(start, stop));
|
|
}
|
|
|
|
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.
|
|
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 TraceThreadMetadataToObservatory() {
|
|
const char* name = base::PlatformThread::GetName();
|
|
if (name == nullptr) {
|
|
return;
|
|
}
|
|
Dart_SetThreadName(name);
|
|
}
|
|
|
|
static void AddTraceMetadata() {
|
|
Shell::Shared().gpu_task_runner()->PostTask(
|
|
FROM_HERE, base::Bind(&TraceThreadMetadataToObservatory));
|
|
Shell::Shared().ui_task_runner()->PostTask(
|
|
FROM_HERE, base::Bind(&TraceThreadMetadataToObservatory));
|
|
Shell::Shared().io_task_runner()->PostTask(
|
|
FROM_HERE, base::Bind(&TraceThreadMetadataToObservatory));
|
|
}
|
|
|
|
void TracingController::StartTracing() {
|
|
if (tracing_active_) {
|
|
return;
|
|
}
|
|
|
|
tracing_active_ = true;
|
|
|
|
StartBaseTracing();
|
|
|
|
AddTraceMetadata();
|
|
}
|
|
|
|
void TracingController::StartBaseTracing() {
|
|
namespace TE = base::trace_event;
|
|
auto config = TE::TraceConfig("*", TE::RECORD_CONTINUOUSLY);
|
|
|
|
auto log = TE::TraceLog::GetInstance();
|
|
|
|
log->SetEnabled(config, TE::TraceLog::MONITORING_MODE);
|
|
log->SetEventCallbackEnabled(config, &BaseTraceEventCallback);
|
|
}
|
|
|
|
void TracingController::StopTracing() {
|
|
if (!tracing_active_) {
|
|
return;
|
|
}
|
|
|
|
tracing_active_ = false;
|
|
|
|
StopBaseTracing();
|
|
}
|
|
|
|
void TracingController::StopBaseTracing() {
|
|
auto log = base::trace_event::TraceLog::GetInstance();
|
|
|
|
log->SetDisabled();
|
|
log->SetEventCallbackDisabled();
|
|
}
|
|
|
|
base::FilePath TracingController::TracePathWithExtension(
|
|
base::FilePath dir,
|
|
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 << "trace_" << exploded.year << "-" << exploded.month << "-"
|
|
<< exploded.day_of_month << "_at_" << exploded.hour << "."
|
|
<< exploded.minute << "." << exploded.second << "."
|
|
<< exploded.millisecond << "." << extension;
|
|
return dir.Append(stream.str());
|
|
}
|
|
|
|
base::FilePath TracingController::PictureTracingPathForCurrentTime() const {
|
|
return PictureTracingPathForCurrentTime(traces_base_path_);
|
|
}
|
|
|
|
base::FilePath TracingController::PictureTracingPathForCurrentTime(
|
|
base::FilePath dir) const {
|
|
return TracePathWithExtension(dir, "skp");
|
|
}
|
|
|
|
} // namespace shell
|
|
} // namespace sky
|