Commit 62436735 authored by Oystein Eftevaag's avatar Oystein Eftevaag Committed by Commit Bot

Reland "Add a Mojo-based transportation layer for Perfetto"

This is a reland of 4df8a2dd

Original change's description:
> Add a Mojo-based transportation layer for Perfetto
>
> This adds a base layer that individual logging protocols (like tracing)
> can use to send their data to Perfetto, using Mojo messaging and
> shared memory.
>
> First CL of several, after this comes the Chrome tracing layer: https://chromium-review.googlesource.com/c/chromium/src/+/981270
>
> A preview of the full integration can be seen here: https://chromium-review.googlesource.com/c/chromium/src/+/852808
>
> The design doc for the integration: https://docs.google.com/document/d/1a8lvN3zYWEyAsBjtuRRsy0fWOWdUdbw6bGnKLBscGdw/edit
>
> R=primiano@chromium.org,skyostil@chromium.org
>
> Change-Id: Ie1db5745ebffdcf1e2d74e2f6b12395f447c8552
> Reviewed-on: https://chromium-review.googlesource.com/980578
> Reviewed-by: oysteine <oysteine@google.com>
> Reviewed-by: Daniel Cheng <dcheng@chromium.org>
> Reviewed-by: Primiano Tucci <primiano@chromium.org>
> Commit-Queue: oysteine <oysteine@google.com>
> Cr-Commit-Position: refs/heads/master@{#551019}

Change-Id: Ic47afdb6c2e09924a5f540fa56552ceb6e29e6d7

TBR=dcheng@chromium.org,primiano@chromium.org,oysteine@google.com,skyostil@chromium.org

Change-Id: Ic47afdb6c2e09924a5f540fa56552ceb6e29e6d7
Reviewed-on: https://chromium-review.googlesource.com/1015189Reviewed-by: default avataroysteine <oysteine@chromium.org>
Commit-Queue: oysteine <oysteine@chromium.org>
Cr-Commit-Position: refs/heads/master@{#551526}
parent 2f3fbbeb
......@@ -842,7 +842,7 @@ deps = {
},
'src/third_party/perfetto':
Var('android_git') + '/platform/external/perfetto.git' + '@' + '135841c8077f13f14c6b80e32d391da84d2ee131',
Var('android_git') + '/platform/external/perfetto.git' + '@' + '197785b48b41ff490cb1682a2216109b98fc7722',
'src/third_party/perl': {
'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
......
......@@ -28,6 +28,24 @@ source_set("lib") {
"//mojo/public/cpp/bindings",
"//services/tracing/public/cpp",
]
if (is_mac || is_linux || is_android) {
sources += [
"perfetto/perfetto_service.cc",
"perfetto/perfetto_service.h",
"perfetto/producer_host.cc",
"perfetto/producer_host.h",
]
deps = [
"//third_party/perfetto/protos/perfetto/trace:lite",
"//third_party/perfetto/protos/perfetto/trace:zero",
"//third_party/perfetto/protos/perfetto/trace/chrome:lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:zero",
]
public_deps += [ "//third_party/perfetto:libperfetto" ]
}
}
service_manifest("manifest") {
......@@ -75,6 +93,18 @@ source_set("tests") {
"//testing/gtest",
]
if (is_mac || is_linux || is_android) {
sources += [ "perfetto/perfetto_integration_unittest.cc" ]
deps += [
"//third_party/perfetto/protos/perfetto/common",
"//third_party/perfetto/protos/perfetto/trace:lite",
"//third_party/perfetto/protos/perfetto/trace:zero",
"//third_party/perfetto/protos/perfetto/trace/chrome:lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:zero",
]
}
data_deps = [
":tracing",
]
......
include_rules = [
"+services/service_manager/public"
"+services/service_manager/public",
"+third_party/perfetto/include",
"+third_party/perfetto/protos/perfetto",
]
......@@ -5,7 +5,8 @@
"service_manager:connector": {
"provides": {
"app": [
"tracing::mojom::AgentRegistry"
"tracing::mojom::AgentRegistry",
"tracing::mojom::PerfettoService"
],
"tracing": [ "tracing::mojom::Coordinator" ],
"tests": [ "*" ]
......
This diff is collapsed.
// Copyright 2018 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 "services/tracing/perfetto/perfetto_service.h"
#include <utility>
#include "base/task_scheduler/post_task.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
#include "services/tracing/perfetto/producer_host.h"
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
#include "third_party/perfetto/include/perfetto/tracing/core/service.h"
namespace tracing {
namespace {
const char kPerfettoProducerName[] = "org.chromium.perfetto_producer";
PerfettoService* g_perfetto_service;
// Just used to destroy disconnected clients.
template <typename T>
void OnClientDisconnect(std::unique_ptr<T>) {}
} // namespace
// TODO(oysteine): Figure out if this is the correct TaskRunner to use.
PerfettoService::PerfettoService()
: perfetto_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
service_ = perfetto::Service::CreateInstance(
std::make_unique<MojoSharedMemory::Factory>(), &perfetto_task_runner_);
DCHECK(service_);
DCHECK(!g_perfetto_service);
g_perfetto_service = this;
}
PerfettoService::~PerfettoService() {
DCHECK_EQ(g_perfetto_service, this);
g_perfetto_service = nullptr;
}
// static
PerfettoService* PerfettoService::GetInstance() {
return g_perfetto_service;
}
void PerfettoService::BindRequest(
mojom::PerfettoServiceRequest request,
const service_manager::BindSourceInfo& source_info) {
bindings_.AddBinding(this, std::move(request), source_info.identity);
}
void PerfettoService::ConnectToProducerHost(
mojom::ProducerClientPtr producer_client,
mojom::ProducerHostRequest producer_host) {
auto new_producer = std::make_unique<ProducerHost>();
new_producer->Initialize(std::move(producer_client), std::move(producer_host),
service_.get(), kPerfettoProducerName);
new_producer->set_connection_error_handler(base::BindOnce(
&OnClientDisconnect<ProducerHost>, std::move(new_producer)));
}
} // namespace tracing
// Copyright 2018 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 SERVICES_TRACING_PERFETTO_PERFETTO_SERVICE_H_
#define SERVICES_TRACING_PERFETTO_PERFETTO_SERVICE_H_
#include <memory>
#include <set>
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/service_manager/public/cpp/identity.h"
#include "services/tracing/public/cpp/perfetto/task_runner.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
namespace service_manager {
struct BindSourceInfo;
} // namespace service_manager
namespace perfetto {
class Service;
} // namespace perfetto
namespace tracing {
// This class serves two purposes: It wraps the use of the system-wide
// perfetto::Service instance, and serves as the main Mojo interface for
// connecting per-process ProducerClient with corresponding service-side
// ProducerHost.
class PerfettoService : public mojom::PerfettoService {
public:
PerfettoService();
~PerfettoService() override;
static PerfettoService* GetInstance();
void BindRequest(mojom::PerfettoServiceRequest request,
const service_manager::BindSourceInfo& source_info);
// mojom::PerfettoService implementation.
void ConnectToProducerHost(mojom::ProducerClientPtr producer_client,
mojom::ProducerHostRequest producer_host) override;
perfetto::Service* service() const { return service_.get(); }
private:
PerfettoTaskRunner perfetto_task_runner_;
std::unique_ptr<perfetto::Service> service_;
mojo::BindingSet<mojom::PerfettoService, service_manager::Identity> bindings_;
DISALLOW_COPY_AND_ASSIGN(PerfettoService);
};
} // namespace tracing
#endif // SERVICES_TRACING_PERFETTO_PERFETTO_SERVICE_H_
// Copyright 2018 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 "services/tracing/perfetto/producer_host.h"
#include <utility>
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
namespace tracing {
ProducerHost::ProducerHost() = default;
ProducerHost::~ProducerHost() = default;
void ProducerHost::Initialize(mojom::ProducerClientPtr producer_client,
mojom::ProducerHostRequest producer_host,
perfetto::Service* service,
const std::string& name) {
DCHECK(service);
DCHECK(!producer_endpoint_);
producer_client_ = std::move(producer_client);
producer_client_.set_connection_error_handler(
base::BindOnce(&ProducerHost::OnConnectionError, base::Unretained(this)));
binding_ = std::make_unique<mojo::Binding<mojom::ProducerHost>>(
this, std::move(producer_host));
binding_->set_connection_error_handler(
base::BindOnce(&ProducerHost::OnConnectionError, base::Unretained(this)));
// TODO(oysteine): Figure out an uid once we need it.
producer_endpoint_ = service->ConnectProducer(this, 0 /* uid */, name);
DCHECK(producer_endpoint_);
}
void ProducerHost::OnConnectionError() {
// Manually reset to prevent any callbacks from the ProducerEndpoint
// when we're in a half-destructed state.
producer_endpoint_.reset();
std::move(connection_error_handler_).Run();
// This object is destroyed at this point.
}
void ProducerHost::OnConnect() {
// Register data sources with Perfetto here.
}
void ProducerHost::OnDisconnect() {
// Deliberately empty, this is invoked by the |service_| business logic after
// we destroy the |producer_endpoint|.
}
void ProducerHost::OnTracingSetup() {
MojoSharedMemory* shared_memory =
static_cast<MojoSharedMemory*>(producer_endpoint_->shared_memory());
DCHECK(shared_memory);
DCHECK(producer_client_);
mojo::ScopedSharedBufferHandle shm = shared_memory->Clone();
DCHECK(shm.is_valid());
producer_client_->OnTracingStart(std::move(shm));
}
void ProducerHost::CreateDataSourceInstance(
perfetto::DataSourceInstanceID id,
const perfetto::DataSourceConfig& config) {
// TODO(oysteine): Send full DataSourceConfig, not just the name/target_buffer
// and Chrome Tracing string.
auto data_source_config = mojom::DataSourceConfig::New();
data_source_config->name = config.name();
data_source_config->target_buffer = config.target_buffer();
data_source_config->trace_config = config.chrome_config().trace_config();
producer_client_->CreateDataSourceInstance(id, std::move(data_source_config));
}
void ProducerHost::TearDownDataSourceInstance(
perfetto::DataSourceInstanceID id) {
if (producer_client_) {
producer_client_->TearDownDataSourceInstance(id);
}
}
void ProducerHost::Flush(
perfetto::FlushRequestID id,
const perfetto::DataSourceInstanceID* raw_data_source_ids,
size_t num_data_sources) {
DCHECK(producer_client_);
std::vector<uint64_t> data_source_ids(raw_data_source_ids,
raw_data_source_ids + num_data_sources);
DCHECK_EQ(data_source_ids.size(), num_data_sources);
producer_client_->Flush(id, data_source_ids);
}
// This data can come from a malicious child process. We don't do any
// sanitization here because ProducerEndpoint::CommitData() (And any other
// ProducerEndpoint methods) are designed to deal with malformed / malicious
// inputs.
void ProducerHost::CommitData(mojom::CommitDataRequestPtr data_request) {
perfetto::CommitDataRequest native_data_request;
// TODO(oysteine): Set up a TypeTrait for this instead of manual conversion.
for (auto& chunk : data_request->chunks_to_move) {
auto* new_chunk = native_data_request.add_chunks_to_move();
new_chunk->set_page(chunk->page);
new_chunk->set_chunk(chunk->chunk);
new_chunk->set_target_buffer(chunk->target_buffer);
}
for (auto& chunk_patch : data_request->chunks_to_patch) {
auto* new_chunk_patch = native_data_request.add_chunks_to_patch();
new_chunk_patch->set_target_buffer(chunk_patch->target_buffer);
new_chunk_patch->set_writer_id(chunk_patch->writer_id);
new_chunk_patch->set_chunk_id(chunk_patch->chunk_id);
for (auto& patch : chunk_patch->patches) {
auto* new_patch = new_chunk_patch->add_patches();
new_patch->set_offset(patch->offset);
new_patch->set_data(patch->data);
}
new_chunk_patch->set_has_more_patches(chunk_patch->has_more_patches);
}
if (on_commit_callback_for_testing_) {
on_commit_callback_for_testing_.Run(native_data_request);
}
// TODO(oysteine): Pass through an optional callback for
// tests to know when a commit is completed.
producer_endpoint_->CommitData(native_data_request);
}
} // namespace tracing
// Copyright 2018 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 SERVICES_TRACING_PERFETTO_PRODUCER_HOST_H_
#define SERVICES_TRACING_PERFETTO_PRODUCER_HOST_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "services/tracing/perfetto/producer_host.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/perfetto/include/perfetto/tracing/core/producer.h"
#include "third_party/perfetto/include/perfetto/tracing/core/service.h"
namespace perfetto {
class CommitDataRequest;
} // namespace perfetto
namespace tracing {
// This class is the service-side part of the Perfetto Producer pair
// and is responsible for registering any available DataSources
// with Perfetto (like ChromeTracing) in OnConnect(). It will forward
// control messages from Perfetto to its per-process ProducerClient
// counterpart, like starting tracing with a specific shared memory buffer,
// create/teardown instances of specific data sources, etc.
// It's managed by PerfettoService which is responsible for
// creating a ProducerHost when a ProducerClient registers itself
// and connects them together.
class ProducerHost : public tracing::mojom::ProducerHost,
public perfetto::Producer {
public:
ProducerHost();
~ProducerHost() override;
void set_connection_error_handler(
base::OnceClosure connection_error_handler) {
connection_error_handler_ = std::move(connection_error_handler);
}
// Called by the ProducerService to register the
// Producer with Perfetto and connect to the
// corresponding remote ProducerClient.
void Initialize(mojom::ProducerClientPtr producer_client,
mojom::ProducerHostRequest producer_host,
perfetto::Service* service,
const std::string& name);
// perfetto::Producer implementation.
// Gets called by perfetto::Service to toggle specific data sources
// when requested by a Perfetto Consumer.
void OnConnect() override;
void OnDisconnect() override;
void CreateDataSourceInstance(
perfetto::DataSourceInstanceID id,
const perfetto::DataSourceConfig& config) override;
void TearDownDataSourceInstance(perfetto::DataSourceInstanceID) override;
void OnTracingSetup() override;
void Flush(perfetto::FlushRequestID,
const perfetto::DataSourceInstanceID* raw_data_source_ids,
size_t num_data_sources) override;
// mojom::ProducerHost implementation.
// This interface gets called by the per-process ProducerClients
// to signal that there's changes to be committed to the
// Shared Memory buffer (like finished chunks).
void CommitData(mojom::CommitDataRequestPtr data_request) override;
protected:
void OnConnectionError();
base::RepeatingCallback<void(const perfetto::CommitDataRequest&)>
on_commit_callback_for_testing_;
private:
mojom::ProducerClientPtr producer_client_;
std::unique_ptr<mojo::Binding<mojom::ProducerHost>> binding_;
base::OnceClosure connection_error_handler_;
protected:
// Perfetto guarantees that no OnXX callbacks are invoked on |this|
// immediately after |producer_endpoint_| is destroyed.
std::unique_ptr<perfetto::Service::ProducerEndpoint> producer_endpoint_;
DISALLOW_COPY_AND_ASSIGN(ProducerHost);
};
} // namespace tracing
#endif // SERVICES_TRACING_PERFETTO_PRODUCER_HOST_H_
......@@ -8,6 +8,8 @@ component("cpp") {
"base_agent.h",
"chrome_trace_event_agent.cc",
"chrome_trace_event_agent.h",
"tracing_features.cc",
"tracing_features.h",
]
defines = [ "IS_TRACING_CPP_IMPL" ]
......@@ -19,4 +21,25 @@ component("cpp") {
"//services/service_manager/public/cpp",
"//services/tracing/public/mojom",
]
if (is_mac || is_linux || is_android) {
sources += [
"perfetto/producer_client.cc",
"perfetto/producer_client.h",
"perfetto/shared_memory.cc",
"perfetto/shared_memory.h",
"perfetto/task_runner.cc",
"perfetto/task_runner.h",
]
deps = [
# TODO(oysteine): Add a Perfetto build target which contains
# only the top-level proto to avoid pulling in unused messages.
"//third_party/perfetto/protos/perfetto/trace:zero",
"//third_party/perfetto/protos/perfetto/trace/chrome:lite",
"//third_party/perfetto/protos/perfetto/trace/chrome:zero",
]
public_deps += [ "//third_party/perfetto:libperfetto" ]
}
}
// Copyright 2018 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 "services/tracing/public/cpp/perfetto/producer_client.h"
#include <utility>
#include "base/task_scheduler/post_task.h"
#include "services/tracing/public/cpp/perfetto/shared_memory.h"
#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
#include "third_party/perfetto/include/perfetto/tracing/core/shared_memory_arbiter.h"
#include "third_party/perfetto/include/perfetto/tracing/core/trace_writer.h"
namespace tracing {
// TODO(oysteine): Use a new sequence here once Perfetto handles multi-threading
// properly.
ProducerClient::ProducerClient()
: perfetto_task_runner_(base::SequencedTaskRunnerHandle::Get()) {
DETACH_FROM_SEQUENCE(sequence_checker_);
}
ProducerClient::~ProducerClient() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
// static
void ProducerClient::DeleteSoon(
std::unique_ptr<ProducerClient> producer_client) {
producer_client->GetTaskRunner()->DeleteSoon(FROM_HERE,
std::move(producer_client));
}
base::SequencedTaskRunner* ProducerClient::GetTaskRunner() {
return perfetto_task_runner_.task_runner();
}
// The Mojo binding should run on the same sequence as the one we get
// callbacks from Perfetto on, to avoid additional PostTasks.
mojom::ProducerClientPtr ProducerClient::CreateAndBindProducerClient() {
DCHECK(!binding_);
mojom::ProducerClientPtr producer_client;
GetTaskRunner()->PostTask(
FROM_HERE,
base::BindOnce(&ProducerClient::BindOnSequence, base::Unretained(this),
mojo::MakeRequest(&producer_client)));
return producer_client;
}
mojom::ProducerHostRequest ProducerClient::CreateProducerHostRequest() {
return mojo::MakeRequest(&producer_host_);
}
void ProducerClient::BindOnSequence(mojom::ProducerClientRequest request) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
binding_ = std::make_unique<mojo::Binding<mojom::ProducerClient>>(
this, std::move(request));
}
void ProducerClient::OnTracingStart(
mojo::ScopedSharedBufferHandle shared_memory) {
// TODO(oysteine): In next CLs plumb this through the service.
const size_t kShmemBufferPageSize = 4096;
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(producer_host_);
if (!shared_memory_) {
shared_memory_ =
std::make_unique<MojoSharedMemory>(std::move(shared_memory));
shared_memory_arbiter_ = perfetto::SharedMemoryArbiter::CreateInstance(
shared_memory_.get(), kShmemBufferPageSize, this,
&perfetto_task_runner_);
} else {
// TODO(oysteine): This is assuming the SMB is the same, currently. Swapping
// out SharedMemoryBuffers would require more thread synchronization.
DCHECK_EQ(shared_memory_->shared_buffer()->value(), shared_memory->value());
}
}
void ProducerClient::CreateDataSourceInstance(
uint64_t id,
mojom::DataSourceConfigPtr data_source_config) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(oysteine): Create the relevant data source instance here.
}
void ProducerClient::TearDownDataSourceInstance(uint64_t id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
enabled_data_source_instance_.reset();
// TODO(oysteine): Yak shave: Can only destroy these once the TraceWriters
// are all cleaned up; have to figure out the TLS bits.
// shared_memory_arbiter_ = nullptr;
// shared_memory_ = nullptr;
}
void ProducerClient::Flush(uint64_t flush_request_id,
const std::vector<uint64_t>& data_source_ids) {
NOTREACHED();
}
void ProducerClient::RegisterDataSource(const perfetto::DataSourceDescriptor&) {
NOTREACHED();
}
void ProducerClient::UnregisterDataSource(const std::string& name) {
NOTREACHED();
}
void ProducerClient::CommitData(const perfetto::CommitDataRequest& commit,
CommitDataCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// The CommitDataRequest which the SharedMemoryArbiter uses to
// signal Perfetto that individual chunks have finished being
// written and is ready for consumption, needs to be serialized
// into the corresponding Mojo class and sent over to the
// service-side.
auto new_data_request = mojom::CommitDataRequest::New();
for (auto& chunk : commit.chunks_to_move()) {
auto new_chunk = mojom::ChunksToMove::New();
new_chunk->page = chunk.page();
new_chunk->chunk = chunk.chunk();
new_chunk->target_buffer = chunk.target_buffer();
new_data_request->chunks_to_move.push_back(std::move(new_chunk));
}
for (auto& chunk_patch : commit.chunks_to_patch()) {
auto new_chunk_patch = mojom::ChunksToPatch::New();
new_chunk_patch->target_buffer = chunk_patch.target_buffer();
new_chunk_patch->writer_id = chunk_patch.writer_id();
new_chunk_patch->chunk_id = chunk_patch.chunk_id();
for (auto& patch : chunk_patch.patches()) {
auto new_patch = mojom::ChunkPatch::New();
new_patch->offset = patch.offset();
new_patch->data = patch.data();
new_chunk_patch->patches.push_back(std::move(new_patch));
}
new_chunk_patch->has_more_patches = chunk_patch.has_more_patches();
new_data_request->chunks_to_patch.push_back(std::move(new_chunk_patch));
}
producer_host_->CommitData(std::move(new_data_request));
}
perfetto::SharedMemory* ProducerClient::shared_memory() const {
return shared_memory_.get();
}
size_t ProducerClient::shared_buffer_page_size_kb() const {
NOTREACHED();
return 0;
}
void ProducerClient::NotifyFlushComplete(perfetto::FlushRequestID) {
NOTREACHED();
}
std::unique_ptr<perfetto::TraceWriter> ProducerClient::CreateTraceWriter(
perfetto::BufferID target_buffer) {
DCHECK(shared_memory_arbiter_);
return shared_memory_arbiter_->CreateTraceWriter(target_buffer);
}
} // namespace tracing
// Copyright 2018 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 SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PRODUCER_CLIENT_H_
#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PRODUCER_CLIENT_H_
#include <memory>
#include <string>
#include <vector>
#include "base/atomicops.h"
#include "base/component_export.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/tracing/public/cpp/perfetto/task_runner.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
#include "third_party/perfetto/include/perfetto/tracing/core/service.h"
namespace perfetto {
class SharedMemoryArbiter;
} // namespace perfetto
namespace tracing {
class MojoSharedMemory;
// This class is the per-process client side of the Perfetto
// producer, and is responsible for creating specific kinds
// of DataSources (like ChromeTracing) on demand, and provide
// them with TraceWriters and a configuration to start logging.
// Implementations of new DataSources should:
// * Implement ProducerClient::DataSourceBase.
// * Add a new data source name in perfetto_service.mojom.
// * Register the data source with Perfetto in ProducerHost::OnConnect.
// * Construct the new implementation when requested to
// in ProducerClient::CreateDataSourceInstance.
class COMPONENT_EXPORT(TRACING_CPP) ProducerClient
: public mojom::ProducerClient,
public perfetto::Service::ProducerEndpoint {
public:
// Base class for different DataSource implementations,
// i.e. something which is able to provide data in the
// form of protos of a given type to Perfetto (like trace events).
class DataSourceBase {
public:
virtual ~DataSourceBase() = default;
};
ProducerClient();
~ProducerClient() override;
static void DeleteSoon(std::unique_ptr<ProducerClient>);
// Connect to the service-side ProducerHost which will
// let Perfetto know we're ready to start logging
// our data.
mojom::ProducerClientPtr CreateAndBindProducerClient();
mojom::ProducerHostRequest CreateProducerHostRequest();
bool has_connected_producer_host_for_testing() const {
return !!producer_host_;
}
// mojom::ProducerClient implementation.
// Called through Mojo by the ProducerHost on the service-side to control
// tracing and toggle specific DataSources.
void OnTracingStart(mojo::ScopedSharedBufferHandle shared_memory) override;
void CreateDataSourceInstance(
uint64_t id,
mojom::DataSourceConfigPtr data_source_config) override;
void TearDownDataSourceInstance(uint64_t id) override;
void Flush(uint64_t flush_request_id,
const std::vector<uint64_t>& data_source_ids) override;
// perfetto::Service::ProducerEndpoint implementation.
// Used by the TraceWriters
// to signal Perfetto that shared memory chunks are ready
// for consumption.
void CommitData(const perfetto::CommitDataRequest& commit,
CommitDataCallback callback) override;
// Used by the DataSource implementations to create TraceWriters
// for writing their protobufs
std::unique_ptr<perfetto::TraceWriter> CreateTraceWriter(
perfetto::BufferID target_buffer) override;
perfetto::SharedMemory* shared_memory() const override;
// These ProducerEndpoint functions are only used on the service
// side and should not be called on the clients.
void RegisterDataSource(const perfetto::DataSourceDescriptor&) override;
void UnregisterDataSource(const std::string& name) override;
size_t shared_buffer_page_size_kb() const override;
void NotifyFlushComplete(perfetto::FlushRequestID) override;
protected:
base::SequencedTaskRunner* GetTaskRunner();
// TODO(oysteine): Allow multiple enabled data source instances.
std::unique_ptr<DataSourceBase> enabled_data_source_instance_;
private:
void BindOnSequence(mojom::ProducerClientRequest request);
// Keep the TaskRunner first in the member list so it outlives
// everything else and no dependent classes will try to use
// an invalid taskrunner.
PerfettoTaskRunner perfetto_task_runner_;
std::unique_ptr<mojo::Binding<mojom::ProducerClient>> binding_;
std::unique_ptr<perfetto::SharedMemoryArbiter> shared_memory_arbiter_;
mojom::ProducerHostPtr producer_host_;
std::unique_ptr<MojoSharedMemory> shared_memory_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(ProducerClient);
};
} // namespace tracing
#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_PRODUCER_CLIENT_H_
// Copyright 2018 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 "services/tracing/public/cpp/perfetto/shared_memory.h"
#include <utility>
#include "third_party/perfetto/include/perfetto/tracing/core/shared_memory.h"
namespace tracing {
std::unique_ptr<perfetto::SharedMemory>
MojoSharedMemory::Factory::CreateSharedMemory(size_t size) {
return std::make_unique<MojoSharedMemory>(size);
}
MojoSharedMemory::MojoSharedMemory(size_t size) {
shared_buffer_ = mojo::SharedBufferHandle::Create(size);
mapping_ = shared_buffer_->Map(size);
DCHECK(mapping_);
}
MojoSharedMemory::MojoSharedMemory(mojo::ScopedSharedBufferHandle shared_memory)
: shared_buffer_(std::move(shared_memory)) {
mapping_ = shared_buffer_->Map(shared_buffer_->GetSize());
DCHECK(mapping_);
}
MojoSharedMemory::~MojoSharedMemory() = default;
mojo::ScopedSharedBufferHandle MojoSharedMemory::Clone() {
return shared_buffer_->Clone(
mojo::SharedBufferHandle::AccessMode::READ_WRITE);
}
void* MojoSharedMemory::start() const {
return mapping_.get();
}
size_t MojoSharedMemory::size() const {
return shared_buffer_->GetSize();
}
} // namespace tracing
// Copyright 2018 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 SERVICES_TRACING_PUBLIC_CPP_PERFETTO_SHARED_MEMORY_H_
#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_SHARED_MEMORY_H_
#include <memory>
#include "base/component_export.h"
#include "base/macros.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "third_party/perfetto/include/perfetto/tracing/core/shared_memory.h"
namespace tracing {
// This wraps a Mojo SharedBuffer implementation to be
// able to provide it to Perfetto.
class COMPONENT_EXPORT(TRACING_CPP) MojoSharedMemory
: public perfetto::SharedMemory {
public:
class Factory : public perfetto::SharedMemory::Factory {
public:
std::unique_ptr<perfetto::SharedMemory> CreateSharedMemory(
size_t size) override;
};
explicit MojoSharedMemory(size_t size);
explicit MojoSharedMemory(mojo::ScopedSharedBufferHandle shared_memory);
~MojoSharedMemory() override;
// Create another wrapping instance of the same SharedMemory buffer,
// for sending to other processes.
mojo::ScopedSharedBufferHandle Clone();
const mojo::ScopedSharedBufferHandle& shared_buffer() const {
return shared_buffer_;
}
// perfetto::SharedMemory implementation. Called internally by Perfetto
// classes.
void* start() const override;
size_t size() const override;
private:
mojo::ScopedSharedBufferHandle shared_buffer_;
mojo::ScopedSharedBufferMapping mapping_;
DISALLOW_COPY_AND_ASSIGN(MojoSharedMemory);
};
} // namespace tracing
#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_SHARED_MEMORY_H_
// Copyright 2018 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 "services/tracing/public/cpp/perfetto/task_runner.h"
#include <memory>
#include "base/threading/sequenced_task_runner_handle.h"
namespace tracing {
PerfettoTaskRunner::PerfettoTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner)
: task_runner_(std::move(task_runner)) {}
PerfettoTaskRunner::~PerfettoTaskRunner() = default;
void PerfettoTaskRunner::PostTask(std::function<void()> task) {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce([](std::function<void()> task) { task(); }, task));
}
void PerfettoTaskRunner::PostDelayedTask(std::function<void()> task,
uint32_t delay_ms) {
task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce([](std::function<void()> task) { task(); }, task),
base::TimeDelta::FromMilliseconds(delay_ms));
}
void PerfettoTaskRunner::AddFileDescriptorWatch(int fd, std::function<void()>) {
NOTREACHED();
}
void PerfettoTaskRunner::RemoveFileDescriptorWatch(int fd) {
NOTREACHED();
}
} // namespace tracing
// Copyright 2018 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 SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TASK_RUNNER_H_
#define SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TASK_RUNNER_H_
#include "base/component_export.h"
#include "base/macros.h"
#include "services/tracing/public/mojom/perfetto_service.mojom.h"
#include "third_party/perfetto/include/perfetto/base/task_runner.h"
namespace tracing {
// This wraps a base::TaskRunner implementation to be able
// to provide it to Perfetto.
class COMPONENT_EXPORT(TRACING_CPP) PerfettoTaskRunner
: public perfetto::base::TaskRunner {
public:
explicit PerfettoTaskRunner(
scoped_refptr<base::SequencedTaskRunner> task_runner);
~PerfettoTaskRunner() override;
// perfetto::base::TaskRunner implementation. Only called by
// the Perfetto implementation itself.
void PostTask(std::function<void()> task) override;
void PostDelayedTask(std::function<void()> task, uint32_t delay_ms) override;
// Not used in Chrome.
void AddFileDescriptorWatch(int fd, std::function<void()>) override;
void RemoveFileDescriptorWatch(int fd) override;
base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
private:
scoped_refptr<base::SequencedTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(PerfettoTaskRunner);
};
} // namespace tracing
#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_TASK_RUNNER_H_
// Copyright 2018 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 "services/tracing/public/cpp/tracing_features.h"
#include <string>
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h"
namespace features {
const base::Feature kTracingPerfettoBackend{"TracingPerfettoBackend",
base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
namespace tracing {
bool TracingUsesPerfettoBackend() {
return base::FeatureList::IsEnabled(features::kTracingPerfettoBackend);
}
} // namespace tracing
// Copyright 2018 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.
// This file defines all the public base::FeatureList features for the
// services/tracing module.
#ifndef SERVICES_TRACING_PUBLIC_CPP_TRACING_FEATURES_H_
#define SERVICES_TRACING_PUBLIC_CPP_TRACING_FEATURES_H_
#include "base/component_export.h"
#include "base/feature_list.h"
namespace features {
// The features should be documented alongside the definition of their values
// in the .cc file.
extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
kTracingPerfettoBackend;
} // namespace features
namespace tracing {
bool COMPONENT_EXPORT(TRACING_CPP) TracingUsesPerfettoBackend();
} // namespace tracing
#endif // SERVICES_TRACING_PUBLIC_CPP_TRACING_FEATURES_H_
......@@ -10,6 +10,7 @@ mojom_component("mojom") {
sources = [
"constants.mojom",
"perfetto_service.mojom",
"tracing.mojom",
]
......
// Copyright 2018 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.
module tracing.mojom;
const string kTraceEventDataSourceName = "org.chromium.trace_event";
// Brief description of the flow: There's a per-process ProducerClient
// which connects to the central PerfettoService and establishes a two-way
// connection with a ProducerHost. The latter will then pass a
// SharedMemoryBuffer to the ProducerClient and tell it to start logging
// events of a given type into it. As chunks of the buffer gets filled
// up, the client will communicate this to the ProducerHost which will
// tell Perfetto to copy the finished chunks into its central storage
// and pass to any consumers.
// For a more complete explanation of a Perfetto tracing session, see
// https://android.googlesource.com/platform/external/perfetto/+/master/docs/life-of-a-tracing-session.md
// See https://android.googlesource.com/platform/external/perfetto/
// for the full documentation of Perfetto concepts and its shared memory ABI.
// Used by the CommitDataRequest() method (client process->service) to signal when
// a chunk is (segment/page of the shared memory buffer which is
// owned by a per-thread TraceWriter) the central Perfetto service that it's
// ready for consumption (flushed or fully written).
struct ChunksToMove {
// The page index within the producer:service shared memory buffer.
uint32 page;
// The chunk index within the given page.
uint32 chunk;
// The target ring-buffer in the service where the chunk should be copied into.
uint32 target_buffer;
};
// Used by the CommitDataRequest method (client process -> service) to
// patch previously written chunks (to fill in size fields when protos
// span multiple chunks, for example).
struct ChunkPatch {
// Offset relative to the chunk defined in ChunksToPatch.
uint32 offset;
string data;
};
struct ChunksToPatch {
// The triplet {target_buffer, writer_id, chunk_id} uniquely identified a chunk that has
// been copied over into the main, non-shared, trace buffer owned by the service.
uint32 target_buffer;
uint32 writer_id;
uint32 chunk_id;
array<ChunkPatch> patches;
// If false the chunk should be considered finalized and available to be read.
bool has_more_patches;
};
struct CommitDataRequest {
array<ChunksToMove> chunks_to_move;
array<ChunksToPatch> chunks_to_patch;
};
struct DataSourceConfig {
string name;
string trace_config;
uint32 target_buffer;
};
interface ProducerHost {
// Called by a ProducerClient to asks the service to:
// 1) Move data from the shared memory buffer into the final tracing buffer owned by the service
// (through the |chunks_to_move|).
// 2) Patch data (i.e. apply diff) that has been previously copied into the tracing buffer
// (if it's not been overwritten).
// The service is robust in terms of tolerating malformed or malicious requests.
CommitData(CommitDataRequest data_request);
};
interface ProducerClient {
OnTracingStart(handle<shared_buffer> shared_memory);
// TODO(oysteine): Make a TypeTrait for sending the full DataSourceConfig.
// Called by Perfetto (via ProducerHost) to request a data source to start logging.
CreateDataSourceInstance(uint64 id, DataSourceConfig data_source_config);
// Requesting a data source to stop logging again, with the id previously sent
// in the CreateDataSourceInstance call.
TearDownDataSourceInstance(uint64 id);
Flush(uint64 flush_request_id, array<uint64> data_source_ids);
};
interface PerfettoService {
ConnectToProducerHost(ProducerClient producer_client, ProducerHost& producer_host);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment