mirror of
https://github.com/encounter/engine.git
synced 2026-03-30 11:09:55 -07:00
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
This commit is contained in:
@@ -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<const char*>(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<Dart_StreamConsumer>(&DartController_DartStreamConsumer);
|
||||
Dart_TimelineGetTrace(callback, &producer);
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,6 +44,9 @@ class SkyView {
|
||||
skia::RefPtr<SkPicture> Paint();
|
||||
void HandleInputEvent(const WebInputEvent& event);
|
||||
|
||||
void StartDartTracing();
|
||||
void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer);
|
||||
|
||||
private:
|
||||
explicit SkyView(SkyViewClient* client);
|
||||
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
|
||||
@@ -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 <Foundation/Foundation.h>
|
||||
|
||||
@interface TracingController : NSObject
|
||||
|
||||
+ (instancetype)sharedController;
|
||||
|
||||
- (void)startTracing;
|
||||
- (void)stopTracing;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* defined(__SKY_SHELL_MAC_TRACINGCONTROLLER__) */
|
||||
@@ -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 <string>
|
||||
#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<base::RefCountedString>& 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
|
||||
@@ -85,5 +85,9 @@ Shell& Shell::Shared() {
|
||||
return *g_shell;
|
||||
}
|
||||
|
||||
TracingController& Shell::tracing_controller() {
|
||||
return tracing_controller_;
|
||||
}
|
||||
|
||||
} // namespace shell
|
||||
} // namespace sky
|
||||
|
||||
@@ -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<ServiceProviderContext> service_provider_context);
|
||||
|
||||
@@ -45,6 +48,7 @@ class Shell {
|
||||
scoped_ptr<base::Thread> gpu_thread_;
|
||||
scoped_ptr<base::Thread> ui_thread_;
|
||||
scoped_ptr<ServiceProviderContext> service_provider_context_;
|
||||
TracingController tracing_controller_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Shell);
|
||||
};
|
||||
|
||||
@@ -22,12 +22,14 @@ void Drop(scoped_ptr<T> 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<Rasterizer>, 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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 <string>
|
||||
|
||||
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<base::File>(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<const char*>(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<mojo::common::DataPipeDrainer>(
|
||||
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<base::RefCountedString>& 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
|
||||
@@ -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 <memory>
|
||||
|
||||
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<mojo::common::DataPipeDrainer> drainer_;
|
||||
std::unique_ptr<base::File> 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<base::RefCountedString>& chunk,
|
||||
bool has_more_events);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TracingController);
|
||||
};
|
||||
} // namespace shell
|
||||
} // namespace sky
|
||||
|
||||
#endif /* defined(__SKY_SHELL_TRACING_CONTROLLER__) */
|
||||
@@ -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
|
||||
|
||||
@@ -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<SkPicture> Paint();
|
||||
|
||||
void StartDartTracing();
|
||||
void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer);
|
||||
|
||||
private:
|
||||
// UIDelegate implementation:
|
||||
void ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) override;
|
||||
|
||||
Reference in New Issue
Block a user