From cfec10d80dd3735e1dade8ff7648117ad4dca1be Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Tue, 11 Aug 2015 14:00:37 -0700 Subject: [PATCH] Make |TracingController| platform agnostic and enable collecting traces from base and the shell view dart isolate simultaneously. Trace files contain samples from multiple sources and must be merged separately --- sky/engine/core/script/dart_controller.cc | 41 ++++++++ sky/engine/core/script/dart_controller.h | 3 + sky/engine/public/sky/sky_view.cc | 8 ++ sky/engine/public/sky/sky_view.h | 3 + sky/shell/BUILD.gn | 4 +- sky/shell/mac/tracing_controller.h | 19 ---- sky/shell/mac/tracing_controller.mm | 120 ---------------------- sky/shell/shell.cc | 4 + sky/shell/shell.h | 4 + sky/shell/shell_view.cc | 14 +++ sky/shell/shell_view.h | 4 + sky/shell/tracing_controller.cc | 120 ++++++++++++++++++++++ sky/shell/tracing_controller.h | 61 +++++++++++ sky/shell/ui/engine.cc | 8 ++ sky/shell/ui/engine.h | 4 + 15 files changed, 276 insertions(+), 141 deletions(-) delete mode 100644 sky/shell/mac/tracing_controller.h delete mode 100644 sky/shell/mac/tracing_controller.mm create mode 100644 sky/shell/tracing_controller.cc create mode 100644 sky/shell/tracing_controller.h diff --git a/sky/engine/core/script/dart_controller.cc b/sky/engine/core/script/dart_controller.cc index 045d09656..8f9bb0a53 100644 --- a/sky/engine/core/script/dart_controller.cc +++ b/sky/engine/core/script/dart_controller.cc @@ -8,6 +8,9 @@ #include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/trace_event/trace_event.h" +#include "dart/runtime/include/dart_tools_api.h" +#include "mojo/common/data_pipe_utils.h" +#include "mojo/public/cpp/system/data_pipe.h" #include "sky/engine/bindings/builtin.h" #include "sky/engine/bindings/builtin_natives.h" #include "sky/engine/bindings/builtin_sky.h" @@ -156,4 +159,42 @@ void DartController::InstallView(View* view) { builtin_sky_->InstallView(view); } +static void DartController_DartStreamConsumer( + Dart_StreamConsumer_State state, + const char* stream_name, + uint8_t* buffer, + intptr_t buffer_length, + mojo::ScopedDataPipeProducerHandle *handle) { + + if (!handle->is_valid()) { + // Simple flush. Nothing to do. + return; + } + + if (state == Dart_StreamConsumer_kData) { + const std::string data(reinterpret_cast(buffer), + buffer_length); + mojo::common::BlockingCopyFromString(data, *handle); + } +} + +void DartController::StartTracing() { + DartIsolateScope isolate_scope(dart_state()->isolate()); + DartApiScope dart_api_scope; + + Dart_TimelineSetRecordedStreams(DART_TIMELINE_STREAM_ALL); +} + +void DartController::StopTracing( + mojo::ScopedDataPipeProducerHandle producer) { + DartIsolateScope isolate_scope(dart_state()->isolate()); + DartApiScope dart_api_scope; + + Dart_TimelineSetRecordedStreams(DART_TIMELINE_STREAM_DISABLE); + + auto callback = + reinterpret_cast(&DartController_DartStreamConsumer); + Dart_TimelineGetTrace(callback, &producer); +} + } // namespace blink diff --git a/sky/engine/core/script/dart_controller.h b/sky/engine/core/script/dart_controller.h index ece380ec3..9244d6cb0 100644 --- a/sky/engine/core/script/dart_controller.h +++ b/sky/engine/core/script/dart_controller.h @@ -41,6 +41,9 @@ class DartController { DOMDartState* dart_state() const { return dom_dart_state_.get(); } + void StartTracing(); + void StopTracing(mojo::ScopedDataPipeProducerHandle producer); + private: void DidLoadMainLibrary(String url); void DidLoadSnapshot(); diff --git a/sky/engine/public/sky/sky_view.cc b/sky/engine/public/sky/sky_view.cc index 2c75a32a2..405cc8931 100644 --- a/sky/engine/public/sky/sky_view.cc +++ b/sky/engine/public/sky/sky_view.cc @@ -101,4 +101,12 @@ void SkyView::ScheduleFrame() { client_->ScheduleFrame(); } +void SkyView::StartDartTracing() { + dart_controller_->StartTracing(); +} + +void SkyView::StopDartTracing(mojo::ScopedDataPipeProducerHandle producer) { + dart_controller_->StopTracing(producer.Pass()); +} + } // namespace blink diff --git a/sky/engine/public/sky/sky_view.h b/sky/engine/public/sky/sky_view.h index 08adc3b09..2c0c3992d 100644 --- a/sky/engine/public/sky/sky_view.h +++ b/sky/engine/public/sky/sky_view.h @@ -44,6 +44,9 @@ class SkyView { skia::RefPtr Paint(); void HandleInputEvent(const WebInputEvent& event); + void StartDartTracing(); + void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer); + private: explicit SkyView(SkyViewClient* client); diff --git a/sky/shell/BUILD.gn b/sky/shell/BUILD.gn index 6684fbef3..a019b4117 100644 --- a/sky/shell/BUILD.gn +++ b/sky/shell/BUILD.gn @@ -48,6 +48,8 @@ source_set("common") { "shell_view.h", "switches.cc", "switches.h", + "tracing_controller.cc", + "tracing_controller.h", "ui/animator.cc", "ui/animator.h", "ui/engine.cc", @@ -191,8 +193,6 @@ if (is_android) { "mac/platform_service_provider_mac.cc", "mac/platform_view_mac.h", "mac/platform_view_mac.mm", - "mac/tracing_controller.h", - "mac/tracing_controller.mm", ] set_sources_assignment_filter(sources_assignment_filter) diff --git a/sky/shell/mac/tracing_controller.h b/sky/shell/mac/tracing_controller.h deleted file mode 100644 index e12153b2e..000000000 --- a/sky/shell/mac/tracing_controller.h +++ /dev/null @@ -1,19 +0,0 @@ -// 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. - -#ifndef __SKY_SHELL_MAC_TRACINGCONTROLLER__ -#define __SKY_SHELL_MAC_TRACINGCONTROLLER__ - -#import - -@interface TracingController : NSObject - -+ (instancetype)sharedController; - -- (void)startTracing; -- (void)stopTracing; - -@end - -#endif /* defined(__SKY_SHELL_MAC_TRACINGCONTROLLER__) */ diff --git a/sky/shell/mac/tracing_controller.mm b/sky/shell/mac/tracing_controller.mm deleted file mode 100644 index 412a35aea..000000000 --- a/sky/shell/mac/tracing_controller.mm +++ /dev/null @@ -1,120 +0,0 @@ -// 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. - -#import "tracing_controller.h" -#include -#include "base/macros.h" -#include "base/trace_event/trace_config.h" -#include "base/trace_event/trace_event.h" - -@interface TracingController () -@property(nonatomic, retain) NSFileHandle* currentFileHandle; -@end - -namespace sky { -namespace shell { - -const char kStart[] = "{\"traceEvents\":["; -const char kEnd[] = "]}"; - -static void Write(const std::string& data) { - NSFileHandle* handle = [TracingController sharedController].currentFileHandle; - [handle writeData:[NSData dataWithBytesNoCopy:(void*)data.data() - length:data.size() - freeWhenDone:false]]; -} - -static void HandleChunk(const scoped_refptr& chunk, - bool has_more_events) { - Write(chunk->data()); - - if (has_more_events) { - Write(","); - } else { - Write(kEnd); - [TracingController sharedController].currentFileHandle = nil; - } -} - -} // namespace shell -} // namespace sky - -@implementation TracingController - -@synthesize currentFileHandle = _currentFileHandle; - -+ (instancetype)sharedController { - static TracingController* controller = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - controller = [[TracingController alloc] init]; - }); - return controller; -} - -- (void)startTracing { - // Start Tracing - NSLog(@"Staring Trace"); - - base::trace_event::TraceLog::GetInstance()->SetEnabled( - base::trace_event::TraceConfig("*", base::trace_event::RECORD_UNTIL_FULL), - base::trace_event::TraceLog::RECORDING_MODE); -} - -- (void)stopTracing { - // Stop Tracing - NSLog(@"Stopping Trace"); - base::trace_event::TraceLog::GetInstance()->SetDisabled(); - - // Save Trace File - NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, - NSUserDomainMask, YES); - if (paths.count == 0) { - NSLog(@"Error: Could not find documents directory to write the trace file " - @"to"); - return; - } - - // Prepare a file path that looks sane in the documents directory - NSURL* pathURL = [NSURL URLWithString:paths[0]]; - NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:@"hh_mm_s"]; - NSString* dateString = - [NSString stringWithFormat:@"Trace_%@.json", - [formatter stringFromDate:[NSDate date]]]; - [formatter release]; - NSURL* fileURL = [NSURL URLWithString:dateString relativeToURL:pathURL]; - NSError* error = nil; - - // Create the file in the documents directory - BOOL created = - [[NSFileManager defaultManager] createFileAtPath:fileURL.absoluteString - contents:nil - attributes:nil]; - if (!created) { - NSLog(@"Error: Could not create file for writing trace file to"); - return; - } - - // Fetch a write handle to the created file - NSFileHandle* handle = - [NSFileHandle fileHandleForWritingToURL:fileURL error:&error]; - if (error != nil) { - NSLog(@"Error: Could not write trace file to documents directory: %@", - error.localizedDescription); - return; - } - - self.currentFileHandle = handle; - sky::shell::Write(sky::shell::kStart); - auto log = base::trace_event::TraceLog::GetInstance(); - log->Flush(base::Bind(&sky::shell::HandleChunk)); -} - -- (void)dealloc { - [_currentFileHandle release]; - [super dealloc]; -} - -@end diff --git a/sky/shell/shell.cc b/sky/shell/shell.cc index c9c2dc695..07658ad4d 100644 --- a/sky/shell/shell.cc +++ b/sky/shell/shell.cc @@ -85,5 +85,9 @@ Shell& Shell::Shared() { return *g_shell; } +TracingController& Shell::tracing_controller() { + return tracing_controller_; +} + } // namespace shell } // namespace sky diff --git a/sky/shell/shell.h b/sky/shell/shell.h index 36004da88..3df67633a 100644 --- a/sky/shell/shell.h +++ b/sky/shell/shell.h @@ -11,6 +11,7 @@ #include "base/message_loop/message_loop.h" #include "base/threading/thread.h" #include "sky/shell/service_provider.h" +#include "sky/shell/tracing_controller.h" namespace sky { namespace shell { @@ -36,6 +37,8 @@ class Shell { return service_provider_context_.get(); } + TracingController& tracing_controller(); + private: explicit Shell(scoped_ptr service_provider_context); @@ -45,6 +48,7 @@ class Shell { scoped_ptr gpu_thread_; scoped_ptr ui_thread_; scoped_ptr service_provider_context_; + TracingController tracing_controller_; DISALLOW_COPY_AND_ASSIGN(Shell); }; diff --git a/sky/shell/shell_view.cc b/sky/shell/shell_view.cc index bb83d422e..1a8e1b32d 100644 --- a/sky/shell/shell_view.cc +++ b/sky/shell/shell_view.cc @@ -22,12 +22,14 @@ void Drop(scoped_ptr ptr) { } ShellView::ShellView(Shell& shell) : shell_(shell) { + shell_.tracing_controller().RegisterShellView(this); rasterizer_.reset(new Rasterizer()); CreateEngine(); CreatePlatformView(); } ShellView::~ShellView() { + shell_.tracing_controller().UnregisterShellView(this); shell_.gpu_task_runner()->PostTask(FROM_HERE, base::Bind(&Drop, base::Passed(&rasterizer_))); shell_.ui_task_runner()->PostTask(FROM_HERE, @@ -49,5 +51,17 @@ void ShellView::CreatePlatformView() { view_.reset(PlatformView::Create(config)); } +void ShellView::StartDartTracing() { + shell_.ui_task_runner()->PostTask( + FROM_HERE, base::Bind(&Engine::StartDartTracing, engine_->GetWeakPtr())); +} + +void ShellView::StopDartTracing( + mojo::ScopedDataPipeProducerHandle producer) { + shell_.ui_task_runner()->PostTask( + FROM_HERE, base::Bind(&Engine::StopDartTracing, engine_->GetWeakPtr(), + base::Passed(&producer))); +} + } // namespace shell } // namespace sky diff --git a/sky/shell/shell_view.h b/sky/shell/shell_view.h index 221406fdd..e92497177 100644 --- a/sky/shell/shell_view.h +++ b/sky/shell/shell_view.h @@ -7,6 +7,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "mojo/public/cpp/system/data_pipe.h" namespace sky { namespace shell { @@ -22,6 +23,9 @@ class ShellView { PlatformView* view() const { return view_.get(); } + void StartDartTracing(); + void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer); + private: void CreateEngine(); void CreatePlatformView(); diff --git a/sky/shell/tracing_controller.cc b/sky/shell/tracing_controller.cc new file mode 100644 index 000000000..b0696b363 --- /dev/null +++ b/sky/shell/tracing_controller.cc @@ -0,0 +1,120 @@ +// 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 "base/logging.h" +#include "base/macros.h" +#include "base/trace_event/trace_config.h" +#include "base/trace_event/trace_event.h" +#include "sky/shell/tracing_controller.h" +#include "sky/shell/shell.h" +#include + +namespace sky { +namespace shell { + +const char kBaseTraceStart[] = "{\"traceEvents\":["; +const char kBaseTraceEnd[] = "]}"; +const char kSentinel[] = "\0"; + +TracingController::TracingController() : view_(nullptr) {} + +TracingController::~TracingController() {} + +void TracingController::StartTracing() { + DLOG(INFO) << "Collecting Traces"; + + StartDartTracing(); + StartBaseTracing(); +} + +void TracingController::StopTracing(const base::FilePath& path) { + DLOG(INFO) << "Stopping trace collection"; + + trace_file_ = std::unique_ptr(new base::File( + path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE)); + + StopBaseTracing(); +} + +void TracingController::OnDataAvailable(const void* data, size_t size) { + if (trace_file_ == nullptr) { + return; + } + + trace_file_->WriteAtCurrentPos(reinterpret_cast(data), size); +} + +void TracingController::OnDataComplete() { + trace_file_ = nullptr; + drainer_ = nullptr; +} + +void TracingController::StartDartTracing() { + if (view_ != nullptr) { + view_->StartDartTracing(); + } +} + +void TracingController::StopDartTracing() { + mojo::DataPipe pipe; + drainer_ = std::unique_ptr( + new mojo::common::DataPipeDrainer(this, pipe.consumer_handle.Pass())); + if (view_ != nullptr) { + view_->StopDartTracing(pipe.producer_handle.Pass()); + } +} + +void TracingController::StartBaseTracing() { + base::trace_event::TraceLog::GetInstance()->SetEnabled( + base::trace_event::TraceConfig("*", base::trace_event::RECORD_UNTIL_FULL), + base::trace_event::TraceLog::RECORDING_MODE); +} + +void TracingController::StopBaseTracing() { + base::trace_event::TraceLog* log = base::trace_event::TraceLog::GetInstance(); + log->SetDisabled(); + + if (trace_file_ != nullptr) { + trace_file_->WriteAtCurrentPos(kBaseTraceStart, + sizeof(kBaseTraceStart) - 1); + } + log->Flush(base::Bind(&TracingController::OnBaseTraceChunk)); +} + +void TracingController::OnBaseTraceChunk( + const scoped_refptr& chunk, + bool has_more_events) { + // Unfortunately, there does not seem to be a way to pass a user args + // reference to the callback. So we make this static and use the |Shared()| + // accessor + TracingController& controller = Shell::Shared().tracing_controller(); + + if (controller.trace_file_ != nullptr) { + std::string& str = chunk->data(); + controller.trace_file_->WriteAtCurrentPos(str.data(), str.size()); + if (has_more_events) { + controller.trace_file_->WriteAtCurrentPos(",", 1); + } else { + controller.trace_file_->WriteAtCurrentPos(kBaseTraceEnd, + sizeof(kBaseTraceEnd) - 1); + controller.trace_file_->WriteAtCurrentPos(kSentinel, + sizeof(kSentinel) - 1); + } + } + + if (!has_more_events) { + controller.StopDartTracing(); + } +} + +void TracingController::RegisterShellView(ShellView* view) { + view_ = view; +} + +void TracingController::UnregisterShellView(ShellView* view) { + view_ = nullptr; +} + +} // namespace shell +} // namespace sky diff --git a/sky/shell/tracing_controller.h b/sky/shell/tracing_controller.h new file mode 100644 index 000000000..0c6a8bc24 --- /dev/null +++ b/sky/shell/tracing_controller.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef __SKY_SHELL_TRACING_CONTROLLER__ +#define __SKY_SHELL_TRACING_CONTROLLER__ + +#include "base/files/file.h" +#include "base/macros.h" +#include "base/memory/ref_counted_memory.h" +#include "mojo/common/data_pipe_drainer.h" +#include "mojo/public/cpp/system/data_pipe.h" +#include "sky/shell/shell_view.h" + +#include + +namespace sky { +namespace shell { + +class TracingController : public mojo::common::DataPipeDrainer::Client { + public: + TracingController(); + ~TracingController() override; + + void RegisterShellView(ShellView* view); + void UnregisterShellView(ShellView* view); + + // Enable tracing in base as well as the dart isolates attached to the shell + // views + void StartTracing(); + + // Stop tracing in base as well as the dart isolates attached to shell views + // and dump the resulting trace to the specified path. Traces from various + // sources are separated by a NULL character in the resulting file and must + // be merged before viewing in the trace viewer + void StopTracing(const base::FilePath& path); + + private: + std::unique_ptr drainer_; + std::unique_ptr trace_file_; + // TODO: Currently, only the last shell view is traced. When the shell gains + // the ability to host multiple shell views, references to each must be stored + // instead and trace data from each serialized to the output trace. + ShellView* view_; + + void StartDartTracing(); + void StartBaseTracing(); + void StopDartTracing(); + void StopBaseTracing(); + void OnDataAvailable(const void* data, size_t num_bytes) override; + void OnDataComplete() override; + static void OnBaseTraceChunk( + const scoped_refptr& chunk, + bool has_more_events); + + DISALLOW_COPY_AND_ASSIGN(TracingController); +}; +} // namespace shell +} // namespace sky + +#endif /* defined(__SKY_SHELL_TRACING_CONTROLLER__) */ diff --git a/sky/shell/ui/engine.cc b/sky/shell/ui/engine.cc index 1fa6a6c68..ca6fddade 100644 --- a/sky/shell/ui/engine.cc +++ b/sky/shell/ui/engine.cc @@ -262,5 +262,13 @@ void Engine::RequestNavigateHistory(int32_t delta) { NOTIMPLEMENTED(); } +void Engine::StartDartTracing() { + sky_view_->StartDartTracing(); +} + +void Engine::StopDartTracing(mojo::ScopedDataPipeProducerHandle producer) { + sky_view_->StopDartTracing(producer.Pass()); +} + } // namespace shell } // namespace sky diff --git a/sky/shell/ui/engine.h b/sky/shell/ui/engine.h index 2dc832928..b4ccfb536 100644 --- a/sky/shell/ui/engine.h +++ b/sky/shell/ui/engine.h @@ -11,6 +11,7 @@ #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/interfaces/application/service_provider.mojom.h" #include "mojo/services/asset_bundle/public/interfaces/asset_bundle.mojom.h" #include "mojo/services/navigation/public/interfaces/navigation.mojom.h" @@ -56,6 +57,9 @@ class Engine : public UIDelegate, void BeginFrame(base::TimeTicks frame_time); skia::RefPtr Paint(); + void StartDartTracing(); + void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer); + private: // UIDelegate implementation: void ConnectToEngine(mojo::InterfaceRequest request) override;