提交 34696334 编写于 作者: C Chinmay Garde

Allow capturing unified (Dart and base) traces from observatory

* Start capturing via <obs_host>:<obs_port>/flutter_startTracing
* Stop capturing via <obs_host>:<obs_port>/flutter_stopTracing
上级 34d60a60
......@@ -163,47 +163,4 @@ void DartController::CreateIsolateFor(std::unique_ptr<DOMDartState> state) {
Dart_ExitIsolate();
}
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) {
// Trim trailing null characters.
if (buffer[buffer_length - 1] == 0)
--buffer_length;
if (buffer_length) {
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
......@@ -43,9 +43,6 @@ 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();
......
......@@ -93,12 +93,4 @@ void SkyView::Render(Scene* scene) {
layer_tree_ = scene->takeLayerTree();
}
void SkyView::StartDartTracing() {
dart_controller_->StartTracing();
}
void SkyView::StopDartTracing(mojo::ScopedDataPipeProducerHandle producer) {
dart_controller_->StopTracing(producer.Pass());
}
} // namespace blink
......@@ -54,9 +54,6 @@ class SkyView : public WindowClient {
void HandlePointerPacket(const pointer::PointerPacketPtr& packet);
void StartDartTracing();
void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer);
private:
explicit SkyView(SkyViewClient* client);
......
......@@ -51,7 +51,7 @@ void InitializeTracing() {
DCHECK(result);
sky::shell::Shell::Shared()
.tracing_controller()
.set_picture_tracing_base_path(path);
.set_traces_base_path(path);
}
} // namespace
......
......@@ -93,7 +93,7 @@ class TouchMapper {
TouchMapper _touch_mapper;
}
static std::string SkPictureTracingPath() {
static std::string TracesBasePath() {
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
return [paths.firstObject UTF8String];
......@@ -102,11 +102,11 @@ static std::string SkPictureTracingPath() {
- (instancetype)initWithShellView:(sky::shell::ShellView*)shellView {
self = [super init];
if (self) {
base::FilePath pictureTracingPath =
base::FilePath::FromUTF8Unsafe(SkPictureTracingPath());
base::FilePath tracesPath =
base::FilePath::FromUTF8Unsafe(TracesBasePath());
sky::shell::Shell::Shared()
.tracing_controller()
.set_picture_tracing_base_path(pictureTracingPath);
.set_traces_base_path(tracesPath);
_shell_view.reset(shellView);
self.multipleTouchEnabled = YES;
......
......@@ -22,14 +22,12 @@ void Drop(scoped_ptr<T> ptr) { }
ShellView::ShellView(Shell& shell)
: shell_(shell) {
shell_.tracing_controller().RegisterShellView(this);
rasterizer_ = Rasterizer::Create();
CreateEngine();
CreatePlatformView();
}
ShellView::~ShellView() {
shell_.tracing_controller().UnregisterShellView(this);
view_ = nullptr;
shell_.gpu_task_runner()->PostTask(FROM_HERE,
base::Bind(&Drop<Rasterizer>, base::Passed(&rasterizer_)));
......@@ -52,17 +50,5 @@ 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
......@@ -24,9 +24,6 @@ class ShellView {
PlatformView* view() const { return view_.get(); }
void StartDartTracing();
void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer);
private:
void CreateEngine();
void CreatePlatformView();
......
......@@ -9,6 +9,7 @@
#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 <string>
#include <sstream>
......@@ -19,11 +20,89 @@ namespace shell {
const char kBaseTraceStart[] = "{\"traceEvents\":[";
const char kBaseTraceEnd[] = "]}";
const char kObservatoryMethodStartTracing[] = "flutter_startTracing";
const char kObservatoryMethodStopTracing[] = "flutter_stopTracing";
const char kObservatoryResultOk[] = "{\"success\" : true}";
const char kObservatoryResultFail[] = "{\"success\" : false}";
static const char* ObservatoryInvoke(const char* method,
const char** param_keys,
const char** param_values,
intptr_t num_params,
void* user_data) {
if (user_data == nullptr) {
// During the desctruction on the tracing controller, the user data is
// cleared. Make sure that observatory requests to service calls are not
// attempted after tracing controller destruction.
return strdup(kObservatoryResultFail);
}
auto tracing_controller = reinterpret_cast<TracingController*>(user_data);
if (strncmp(method, kObservatoryMethodStartTracing,
sizeof(kObservatoryMethodStartTracing)) == 0) {
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;
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);
tracing_controller->StopTracing(path, true);
// 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();
if (length == 0) {
base::DeleteFile(path, false);
return strdup(kObservatoryResultFail);
}
char* data = reinterpret_cast<char*>(malloc(length));
int length_read = file.Read(0, data, length);
DCHECK(length == length_read);
base::DeleteFile(path, false);
return data;
}
return strdup(kObservatoryResultFail);
}
TracingController::TracingController()
: view_(nullptr), picture_tracing_enabled_(false), weak_factory_(this) {
: picture_tracing_enabled_(false),
terminate_loop_on_write_(false),
weak_factory_(this) {
ManageObservatoryCallbacks(true);
}
TracingController::~TracingController() {
ManageObservatoryCallbacks(false);
}
void TracingController::ManageObservatoryCallbacks(bool add) {
void* baton = add ? this : nullptr;
Dart_RegisterRootServiceRequestCallback(kObservatoryMethodStartTracing,
&ObservatoryInvoke, baton);
Dart_RegisterRootServiceRequestCallback(kObservatoryMethodStopTracing,
&ObservatoryInvoke, baton);
}
void TracingController::StartTracing() {
......@@ -33,7 +112,23 @@ void TracingController::StartTracing() {
StartBaseTracing();
}
void TracingController::StopTracing(const base::FilePath& path) {
void TracingController::StopTracing(const base::FilePath& path,
bool terminate_loop_when_done) {
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&TracingController::StopTracingAsync,
weak_factory_.GetWeakPtr(), path, terminate_loop_when_done));
}
void TracingController::StopTracingAsync(const base::FilePath& path,
bool terminate_loop_when_done) {
if (terminate_loop_on_write_) {
DLOG(INFO) << "Observatory is attempting to capture a trace.";
return;
}
terminate_loop_on_write_ = terminate_loop_when_done;
LOG(INFO) << "Saving trace to " << path.LossyDisplayName();
trace_file_ = std::unique_ptr<base::File>(new base::File(
......@@ -42,34 +137,41 @@ void TracingController::StopTracing(const base::FilePath& path) {
StopBaseTracing();
}
void TracingController::OnDataAvailable(const void* data, size_t size) {
if (trace_file_)
trace_file_->WriteAtCurrentPos(reinterpret_cast<const char*>(data), size);
}
void TracingController::OnDataComplete() {
drainer_ = nullptr;
FinalizeTraceFile();
LOG(INFO) << "Trace complete";
void TracingController::StartDartTracing() {
Dart_GlobalTimelineSetRecordedStreams(~0);
}
void TracingController::StartDartTracing() {
if (view_)
view_->StartDartTracing();
static void TracingController_DartStreamConsumer(
Dart_StreamConsumer_State state,
const char* stream_name,
uint8_t* buffer,
intptr_t buffer_length,
base::File* traceFile) {
if (state == Dart_StreamConsumer_kData) {
// Trim trailing null characters.
if (buffer[buffer_length - 1] == 0)
--buffer_length;
if (buffer_length) {
if (traceFile != nullptr) {
traceFile->WriteAtCurrentPos(reinterpret_cast<char*>(buffer),
buffer_length);
}
}
}
}
void TracingController::StopDartTracing() {
if (view_) {
if (trace_file_)
trace_file_->WriteAtCurrentPos(",", 1);
mojo::DataPipe pipe;
drainer_ = std::unique_ptr<mojo::common::DataPipeDrainer>(
new mojo::common::DataPipeDrainer(this, pipe.consumer_handle.Pass()));
view_->StopDartTracing(pipe.producer_handle.Pass());
} else {
FinalizeTraceFile();
if (trace_file_){
trace_file_->WriteAtCurrentPos(",", 1);
}
Dart_GlobalTimelineSetRecordedStreams(DART_TIMELINE_STREAM_DISABLE);
auto callback = reinterpret_cast<Dart_StreamConsumer>(
&TracingController_DartStreamConsumer);
Dart_GlobalTimelineGetTrace(callback, trace_file_.get());
FinalizeTraceFile();
}
void TracingController::StartBaseTracing() {
......@@ -86,8 +188,9 @@ void TracingController::StopBaseTracing() {
trace_file_->WriteAtCurrentPos(kBaseTraceStart,
sizeof(kBaseTraceStart) - 1);
}
log->Flush(base::Bind(
&TracingController::OnBaseTraceChunk, weak_factory_.GetWeakPtr()));
log->Flush(base::Bind(&TracingController::OnBaseTraceChunk,
weak_factory_.GetWeakPtr()));
}
void TracingController::FinalizeTraceFile() {
......@@ -95,6 +198,11 @@ void TracingController::FinalizeTraceFile() {
trace_file_->WriteAtCurrentPos(kBaseTraceEnd, sizeof(kBaseTraceEnd) - 1);
trace_file_ = nullptr;
}
if (terminate_loop_on_write_) {
base::MessageLoop::current()->Quit();
terminate_loop_on_write_ = false;
}
}
void TracingController::OnBaseTraceChunk(
......@@ -107,31 +215,40 @@ void TracingController::OnBaseTraceChunk(
trace_file_->WriteAtCurrentPos(",", 1);
}
if (!has_more_events)
if (!has_more_events) {
StopDartTracing();
}
}
void TracingController::RegisterShellView(ShellView* view) {
view_ = view;
}
void TracingController::UnregisterShellView(ShellView* view) {
view_ = nullptr;
}
base::FilePath TracingController::PictureTracingPathForCurrentTime() const {
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_.skp
// 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 << ".skp";
return picture_tracing_base_path_.Append(stream.str());
<< 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");
}
base::FilePath TracingController::TracePathForCurrentTime(
base::FilePath dir) const {
return TracePathWithExtension(dir, "json");
}
} // namespace shell
......
......@@ -10,7 +10,6 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "mojo/data_pipe_utils/data_pipe_drainer.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "sky/shell/shell_view.h"
......@@ -19,28 +18,24 @@
namespace sky {
namespace shell {
class TracingController : public mojo::common::DataPipeDrainer::Client {
class TracingController {
public:
TracingController();
~TracingController() override;
~TracingController();
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);
void StopTracing(const base::FilePath& path,
bool terminateLoopWhenDone = false);
base::FilePath PictureTracingPathForCurrentTime() const;
base::FilePath PictureTracingPathForCurrentTime(base::FilePath dir) const;
base::FilePath TracePathForCurrentTime(base::FilePath dir) const;
void set_picture_tracing_base_path(const base::FilePath& base_path) {
picture_tracing_base_path_ = base_path;
void set_traces_base_path(const base::FilePath& base_path) {
traces_base_path_ = base_path;
}
void set_picture_tracing_enabled(bool enabled) {
......@@ -50,25 +45,24 @@ class TracingController : public mojo::common::DataPipeDrainer::Client {
bool picture_tracing_enabled() const { return picture_tracing_enabled_; }
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_;
base::FilePath picture_tracing_base_path_;
base::FilePath traces_base_path_;
bool picture_tracing_enabled_;
bool terminate_loop_on_write_;
void StartDartTracing();
void StartBaseTracing();
void StopDartTracing();
void StopBaseTracing();
void OnDataAvailable(const void* data, size_t num_bytes) override;
void OnDataComplete() override;
void FinalizeTraceFile();
void StopTracingAsync(const base::FilePath& path, bool terminateLoopWhenDone);
void OnBaseTraceChunk(const scoped_refptr<base::RefCountedString>& chunk,
bool has_more_events);
void ManageObservatoryCallbacks(bool addOrRemove);
base::FilePath TracePathWithExtension(base::FilePath dir,
std::string extension) const;
base::WeakPtrFactory<TracingController> weak_factory_;
......
......@@ -261,13 +261,5 @@ void Engine::ScheduleFrame() {
void Engine::Render(std::unique_ptr<compositor::LayerTree> layer_tree) {
}
void Engine::StartDartTracing() {
sky_view_->StartDartTracing();
}
void Engine::StopDartTracing(mojo::ScopedDataPipeProducerHandle producer) {
sky_view_->StopDartTracing(producer.Pass());
}
} // namespace shell
} // namespace sky
......@@ -49,9 +49,6 @@ class Engine : public UIDelegate,
std::unique_ptr<compositor::LayerTree> BeginFrame(base::TimeTicks frame_time);
void StartDartTracing();
void StopDartTracing(mojo::ScopedDataPipeProducerHandle producer);
private:
// UIDelegate implementation:
void ConnectToEngine(mojo::InterfaceRequest<SkyEngine> request) override;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册