diff --git a/sky/shell/shell.cc b/sky/shell/shell.cc index 63eb4b0e7d0..451ecf66dad 100644 --- a/sky/shell/shell.cc +++ b/sky/shell/shell.cc @@ -81,6 +81,9 @@ void Shell::InitStandalone() { settings.enable_dart_checked_mode = command_line.HasSwitch(switches::kEnableCheckedMode); Init(settings); + if (command_line.HasSwitch(switches::kTraceStartup)) { + Shared().tracing_controller().StartTracing(); + } } void Shell::Init(const Settings& settings) { diff --git a/sky/shell/switches.cc b/sky/shell/switches.cc index 7a6a062692e..642b345260e 100644 --- a/sky/shell/switches.cc +++ b/sky/shell/switches.cc @@ -15,6 +15,7 @@ const char kFLX[] = "flx"; const char kHelp[] = "help"; const char kNonInteractive[] = "non-interactive"; const char kPackageRoot[] = "package-root"; +const char kTraceStartup[] = "trace-startup"; void PrintUsage(const std::string& executable_name) { std::cerr << "Usage: " << executable_name diff --git a/sky/shell/switches.h b/sky/shell/switches.h index 10a9e256d09..577c4ab13e5 100644 --- a/sky/shell/switches.h +++ b/sky/shell/switches.h @@ -16,6 +16,7 @@ extern const char kFLX[]; extern const char kHelp[]; extern const char kNonInteractive[]; extern const char kPackageRoot[]; +extern const char kTraceStartup[]; void PrintUsage(const std::string& executable_name); diff --git a/sky/shell/tracing_controller.cc b/sky/shell/tracing_controller.cc index 6f298cf23d1..6a940c6fef0 100644 --- a/sky/shell/tracing_controller.cc +++ b/sky/shell/tracing_controller.cc @@ -2,14 +2,15 @@ // 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/files/file_util.h" #include "base/logging.h" #include "base/macros.h" #include "base/trace_event/trace_config.h" #include "base/trace_event/trace_event.h" -#include "sky/shell/shell.h" -#include "sky/shell/tracing_controller.h" #include "dart/runtime/include/dart_tools_api.h" +#include "sky/shell/shell.h" #include #include @@ -41,46 +42,52 @@ static const char* ObservatoryInvoke(const char* method, if (strncmp(method, kObservatoryMethodStartTracing, sizeof(kObservatoryMethodStartTracing)) == 0) { - tracing_controller->StartTracing(); - return strdup(kObservatoryResultOk); + if (!tracing_controller->tracing_active()) { + tracing_controller->StartTracing(); + return strdup(kObservatoryResultOk); + } } if (strncmp(method, kObservatoryMethodStopTracing, sizeof(kObservatoryMethodStopTracing)) == 0) { - // Flushing the trace log requires an active message loop. However, - // observatory callbacks are made on a dart worker thread. We setup a - // message loop manually and tell the flush completion handler to terminate - // the loop when done - base::MessageLoop worker_thread_loop; + if (tracing_controller->tracing_active()) { + // Flushing the trace log requires an active message loop. However, + // observatory callbacks are made on a dart worker thread. We setup a + // message loop manually and tell the flush completion handler to + // terminate + // the loop when done + base::MessageLoop worker_thread_loop; - base::FilePath temp_dir; - bool temp_access = base::GetTempDir(&temp_dir); - DCHECK(temp_access) << "Must be able to access the temp directory"; + base::FilePath temp_dir; + bool temp_access = base::GetTempDir(&temp_dir); + DCHECK(temp_access) << "Must be able to access the temp directory"; - base::FilePath path = tracing_controller->TracePathForCurrentTime(temp_dir); + base::FilePath path = + tracing_controller->TracePathForCurrentTime(temp_dir); - tracing_controller->StopTracing(path, true); + tracing_controller->StopTracing(path, true); - // Run the loop till the flush callback terminates the activation - worker_thread_loop.Run(); + // Run the loop till the flush callback terminates the activation + worker_thread_loop.Run(); - base::File file( - path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ); - int64 length = file.GetLength(); + base::File file( + path, base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ); + int64 length = file.GetLength(); + + if (length == 0) { + base::DeleteFile(path, false); + return strdup(kObservatoryResultFail); + } + + char* data = reinterpret_cast(malloc(length)); + int length_read = file.Read(0, data, length); + + DCHECK(length == length_read); - if (length == 0) { base::DeleteFile(path, false); - return strdup(kObservatoryResultFail); + + return data; } - - char* data = reinterpret_cast(malloc(length)); - int length_read = file.Read(0, data, length); - - DCHECK(length == length_read); - - base::DeleteFile(path, false); - - return data; } return strdup(kObservatoryResultFail); @@ -89,6 +96,8 @@ static const char* ObservatoryInvoke(const char* method, TracingController::TracingController() : picture_tracing_enabled_(false), terminate_loop_on_write_(false), + dart_initialized_(false), + tracing_active_(false), weak_factory_(this) { ManageObservatoryCallbacks(true); } @@ -97,6 +106,18 @@ TracingController::~TracingController() { ManageObservatoryCallbacks(false); } +void TracingController::SetDartInitialized() { + DCHECK(!dart_initialized_); + dart_initialized_ = true; + + // In case early lifecycle is being traced, base tracing has already begun + // but we have just been notified of initialization of the Dart VM. Start + // collecting traces in Dart. + if (tracing_active_) { + StartDartTracing(); + } +} + void TracingController::ManageObservatoryCallbacks(bool add) { void* baton = add ? this : nullptr; Dart_RegisterRootServiceRequestCallback(kObservatoryMethodStartTracing, @@ -106,8 +127,12 @@ void TracingController::ManageObservatoryCallbacks(bool add) { } void TracingController::StartTracing() { + DCHECK(!tracing_active_); + LOG(INFO) << "Starting trace"; + tracing_active_ = true; + StartDartTracing(); StartBaseTracing(); } @@ -138,6 +163,10 @@ void TracingController::StopTracingAsync(const base::FilePath& path, } void TracingController::StartDartTracing() { + if (!dart_initialized_) { + return; + } + Dart_GlobalTimelineSetRecordedStreams(~0); } @@ -161,6 +190,13 @@ static void TracingController_DartStreamConsumer( } void TracingController::StopDartTracing() { + if (!dart_initialized_) { + // This is checking for the highly unlikely case where the user starts and + // stops tracing before the dart VM is initialized. + FinalizeTraceFile(); + return; + } + if (trace_file_){ trace_file_->WriteAtCurrentPos(",", 1); } @@ -204,6 +240,8 @@ void TracingController::FinalizeTraceFile() { terminate_loop_on_write_ = false; } + tracing_active_ = false; + LOG(INFO) << "Trace complete"; } diff --git a/sky/shell/tracing_controller.h b/sky/shell/tracing_controller.h index baf75abd6cd..a6c5dbd7344 100644 --- a/sky/shell/tracing_controller.h +++ b/sky/shell/tracing_controller.h @@ -34,6 +34,10 @@ class TracingController { base::FilePath TracePathForCurrentTime(base::FilePath dir) const; + void SetDartInitialized(); + + bool tracing_active() const { return tracing_active_; } + void set_traces_base_path(const base::FilePath& base_path) { traces_base_path_ = base_path; } @@ -49,6 +53,8 @@ class TracingController { base::FilePath traces_base_path_; bool picture_tracing_enabled_; bool terminate_loop_on_write_; + bool dart_initialized_; + bool tracing_active_; void StartDartTracing(); void StartBaseTracing(); diff --git a/sky/shell/ui/engine.cc b/sky/shell/ui/engine.cc index 2e2e6f22e54..7dd69567f3c 100644 --- a/sky/shell/ui/engine.cc +++ b/sky/shell/ui/engine.cc @@ -78,6 +78,7 @@ void Engine::Init() { DCHECK(!g_platform_impl); g_platform_impl = new PlatformImpl(); blink::initialize(g_platform_impl); + Shell::Shared().tracing_controller().SetDartInitialized(); } std::unique_ptr Engine::BeginFrame(