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:
Chinmay Garde
2015-08-11 14:00:37 -07:00
parent d87a1cc6ea
commit cfec10d80d
15 changed files with 276 additions and 141 deletions
+41
View File
@@ -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
+3
View File
@@ -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();
+8
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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)
-19
View File
@@ -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__) */
-120
View File
@@ -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
+4
View File
@@ -85,5 +85,9 @@ Shell& Shell::Shared() {
return *g_shell;
}
TracingController& Shell::tracing_controller() {
return tracing_controller_;
}
} // namespace shell
} // namespace sky
+4
View File
@@ -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);
};
+14
View File
@@ -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
+4
View File
@@ -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();
+120
View File
@@ -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
+61
View File
@@ -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__) */
+8
View File
@@ -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
+4
View File
@@ -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;