Commit 27807d9a authored by Sami Kyostila's avatar Sami Kyostila Committed by Commit Bot

services/tracing: Implement a Perfetto producer backend

This patch implements a producer backend for Perfetto's client library
using the mojo-based PerfettoService. This makes it possible to use
Perfetto's client library to emit trace events. Since the perfetto
service only supports one producer for each process, we introduce a
feature flag (EnablePerfettoClientApiProducer) to enable the client
library producer instead of the TraceLog implementation. Note that since
no producers are actually ported to the client library yet, no trace
events currently are generated when using this flag.

Bug: b/158460810, 839071
Change-Id: Ief61793cba9fe6d5fb8e2a9330f9c06cccd0942a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2283307
Commit-Queue: François Doray <fdoray@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarStephen Nusko <nuskos@chromium.org>
Reviewed-by: default avatarEric Seckler <eseckler@chromium.org>
Auto-Submit: Sami Kyöstilä <skyostil@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790558}
parent d804aafe
...@@ -2291,7 +2291,10 @@ buildflag_header("sanitizer_buildflags") { ...@@ -2291,7 +2291,10 @@ buildflag_header("sanitizer_buildflags") {
buildflag_header("tracing_buildflags") { buildflag_header("tracing_buildflags") {
header = "tracing_buildflags.h" header = "tracing_buildflags.h"
flags = [ "ENABLE_BASE_TRACING=$enable_base_tracing" ] flags = [
"ENABLE_BASE_TRACING=$enable_base_tracing",
"USE_PERFETTO_CLIENT_LIBRARY=$use_perfetto_client_library",
]
} }
# This is the subset of files from base that should not be used with a dynamic # This is the subset of files from base that should not be used with a dynamic
......
...@@ -71,7 +71,9 @@ bool ProducerHost::Initialize( ...@@ -71,7 +71,9 @@ bool ProducerHost::Initialize(
base::ProcessId pid; base::ProcessId pid;
if (PerfettoService::ParsePidFromProducerName(name, &pid)) { if (PerfettoService::ParsePidFromProducerName(name, &pid)) {
bool in_process = (pid == base::Process::Current().Pid()); bool in_process = (pid == base::Process::Current().Pid());
if (in_process) { // TODO(skyostil): Implement arbiter binding for the client API.
if (in_process && !base::FeatureList::IsEnabled(
features::kEnablePerfettoClientApiProducer)) {
PerfettoTracedProcess::Get() PerfettoTracedProcess::Get()
->producer_client() ->producer_client()
->BindInProcessSharedMemoryArbiter(producer_endpoint_.get(), ->BindInProcessSharedMemoryArbiter(producer_endpoint_.get(),
......
...@@ -110,7 +110,7 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoProducer { ...@@ -110,7 +110,7 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoProducer {
bool IsStartupTracingActive(); bool IsStartupTracingActive();
// TODO(oysteine): Find a good compromise between performance and // TODO(crbug.com/839071): Find a good compromise between performance and
// data granularity (mainly relevant to running with small buffer sizes // data granularity (mainly relevant to running with small buffer sizes
// when we use background tracing) on Android. // when we use background tracing) on Android.
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -119,7 +119,7 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoProducer { ...@@ -119,7 +119,7 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoProducer {
static constexpr size_t kSMBPageSizeBytes = 32 * 1024; static constexpr size_t kSMBPageSizeBytes = 32 * 1024;
#endif #endif
// TODO(oysteine): Figure out a good buffer size. // TODO(crbug.com/839071): Figure out a good buffer size.
static constexpr size_t kSMBSizeBytes = 4 * 1024 * 1024; static constexpr size_t kSMBSizeBytes = 4 * 1024 * 1024;
PerfettoTaskRunner* task_runner(); PerfettoTaskRunner* task_runner();
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "services/tracing/public/cpp/perfetto/trace_event_data_source.h" #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h" #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
#include "services/tracing/public/cpp/trace_startup.h" #include "services/tracing/public/cpp/trace_startup.h"
#include "services/tracing/public/cpp/tracing_features.h"
#include "services/tracing/public/mojom/tracing_service.mojom.h" #include "services/tracing/public/mojom/tracing_service.mojom.h"
#include "third_party/perfetto/include/perfetto/tracing/tracing.h" #include "third_party/perfetto/include/perfetto/tracing/tracing.h"
...@@ -95,6 +96,17 @@ void PerfettoTracedProcess::SetConsumerConnectionFactory( ...@@ -95,6 +96,17 @@ void PerfettoTracedProcess::SetConsumerConnectionFactory(
consumer_connection_task_runner_ = task_runner; consumer_connection_task_runner_ = task_runner;
} }
void PerfettoTracedProcess::ConnectProducer(
mojo::PendingRemote<mojom::PerfettoService> perfetto_service) {
if (base::FeatureList::IsEnabled(
features::kEnablePerfettoClientApiProducer)) {
DCHECK(pending_producer_callback_);
std::move(pending_producer_callback_).Run(std::move(perfetto_service));
} else {
producer_client_->Connect(std::move(perfetto_service));
}
}
void PerfettoTracedProcess::ClearDataSourcesForTesting() { void PerfettoTracedProcess::ClearDataSourcesForTesting() {
base::AutoLock lock(data_sources_lock_); base::AutoLock lock(data_sources_lock_);
data_sources_.clear(); data_sources_.clear();
...@@ -125,6 +137,18 @@ void PerfettoTracedProcess::DeleteSoonForTesting( ...@@ -125,6 +137,18 @@ void PerfettoTracedProcess::DeleteSoonForTesting(
FROM_HERE, std::move(perfetto_traced_process)); FROM_HERE, std::move(perfetto_traced_process));
} }
void PerfettoTracedProcess::CreateProducerConnection(
base::OnceCallback<void(mojo::PendingRemote<mojom::PerfettoService>)>
callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Perfetto will attempt to create the producer connection as soon as the
// client library is initialized, which is before we have a a connection to
// the tracing service. Store the connection callback until ConnectProducer()
// is called.
DCHECK(!pending_producer_callback_);
pending_producer_callback_ = std::move(callback);
}
void PerfettoTracedProcess::CreateConsumerConnection( void PerfettoTracedProcess::CreateConsumerConnection(
base::OnceCallback<void(mojo::PendingRemote<mojom::ConsumerHost>)> base::OnceCallback<void(mojo::PendingRemote<mojom::ConsumerHost>)>
callback) { callback) {
......
...@@ -106,6 +106,11 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final ...@@ -106,6 +106,11 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
void SetConsumerConnectionFactory(ConsumerConnectionFactory, void SetConsumerConnectionFactory(ConsumerConnectionFactory,
scoped_refptr<base::SequencedTaskRunner>); scoped_refptr<base::SequencedTaskRunner>);
// Connect the current process to the mojo trace producer API. Depending on
// the configuration, this will either set up the Perfetto Client API or the
// legacy TraceLog to become the trace producer for this process.
void ConnectProducer(mojo::PendingRemote<mojom::PerfettoService>);
ProducerClient* producer_client() const; ProducerClient* producer_client() const;
SystemProducer* system_producer() const; // May be null. SystemProducer* system_producer() const; // May be null.
...@@ -178,6 +183,9 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final ...@@ -178,6 +183,9 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
} }
// PerfettoTracingBackend::Delegate implementation. // PerfettoTracingBackend::Delegate implementation.
void CreateProducerConnection(
base::OnceCallback<void(mojo::PendingRemote<mojom::PerfettoService>)>)
override;
void CreateConsumerConnection( void CreateConsumerConnection(
base::OnceCallback<void(mojo::PendingRemote<mojom::ConsumerHost>)>) base::OnceCallback<void(mojo::PendingRemote<mojom::ConsumerHost>)>)
override; override;
...@@ -209,6 +217,9 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final ...@@ -209,6 +217,9 @@ class COMPONENT_EXPORT(TRACING_CPP) PerfettoTracedProcess final
scoped_refptr<base::SequencedTaskRunner> consumer_connection_task_runner_; scoped_refptr<base::SequencedTaskRunner> consumer_connection_task_runner_;
ConsumerConnectionFactory consumer_connection_factory_; ConsumerConnectionFactory consumer_connection_factory_;
base::OnceCallback<void(mojo::PendingRemote<mojom::PerfettoService>)>
pending_producer_callback_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(PerfettoTracedProcess); DISALLOW_COPY_AND_ASSIGN(PerfettoTracedProcess);
}; };
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
namespace tracing { namespace tracing {
namespace mojom { namespace mojom {
class ConsumerHost; class ConsumerHost;
class PerfettoService;
} // namespace mojom } // namespace mojom
// The Perfetto tracing backend mediates between the Perfetto client library and // The Perfetto tracing backend mediates between the Perfetto client library and
...@@ -26,7 +27,9 @@ class ConsumerHost; ...@@ -26,7 +27,9 @@ class ConsumerHost;
// .---------->| ConsumerEndpoint |<--->| ConsumerHost | // .---------->| ConsumerEndpoint |<--->| ConsumerHost |
// .--------------. : `------------------' : `--------------' // .--------------. : `------------------' : `--------------'
// | TracingMuxer | : : // | TracingMuxer | : :
// `--------------' : : // `--------------' : .------------------. : .--------------.
// `---------->| ProducerEndpoint |<--->| ProducerHost |
// : `------------------' : `--------------'
// : : // : :
class PerfettoTracingBackend : public perfetto::TracingBackend { class PerfettoTracingBackend : public perfetto::TracingBackend {
public: public:
...@@ -38,6 +41,12 @@ class PerfettoTracingBackend : public perfetto::TracingBackend { ...@@ -38,6 +41,12 @@ class PerfettoTracingBackend : public perfetto::TracingBackend {
// callback may be called on an arbitrary sequence. // callback may be called on an arbitrary sequence.
virtual void CreateConsumerConnection( virtual void CreateConsumerConnection(
base::OnceCallback<void(mojo::PendingRemote<mojom::ConsumerHost>)>) = 0; base::OnceCallback<void(mojo::PendingRemote<mojom::ConsumerHost>)>) = 0;
// Called to establish a producer connection to the tracing service. The
// callback may be called on an arbitrary sequence.
virtual void CreateProducerConnection(
base::OnceCallback<
void(mojo::PendingRemote<mojom::PerfettoService>)>) = 0;
}; };
explicit PerfettoTracingBackend(Delegate&); explicit PerfettoTracingBackend(Delegate&);
......
...@@ -95,7 +95,7 @@ void TracedProcessImpl::ConnectToTracingService( ...@@ -95,7 +95,7 @@ void TracedProcessImpl::ConnectToTracingService(
// Ensure the TraceEventAgent has been created. // Ensure the TraceEventAgent has been created.
TraceEventAgent::GetInstance(); TraceEventAgent::GetInstance();
PerfettoTracedProcess::Get()->producer_client()->Connect( PerfettoTracedProcess::Get()->ConnectProducer(
std::move(request->perfetto_service)); std::move(request->perfetto_service));
} }
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/tracing_buildflags.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "build/chromecast_buildflags.h" #include "build/chromecast_buildflags.h"
#include "components/tracing/common/tracing_switches.h" #include "components/tracing/common/tracing_switches.h"
...@@ -37,6 +38,17 @@ const base::Feature kTracingServiceInProcess { ...@@ -37,6 +38,17 @@ const base::Feature kTracingServiceInProcess {
const base::Feature kEnablePerfettoSystemTracing{ const base::Feature kEnablePerfettoSystemTracing{
"EnablePerfettoSystemTracing", base::FEATURE_DISABLED_BY_DEFAULT}; "EnablePerfettoSystemTracing", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether trace points are implemented using Perfetto's client library
// (enabled) or legacy TraceLog (disabled).
const base::Feature kEnablePerfettoClientApiProducer {
"EnablePerfettoClientApiProducer",
#if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
#endif
};
} // namespace features } // namespace features
namespace tracing { namespace tracing {
......
...@@ -24,6 +24,9 @@ extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature ...@@ -24,6 +24,9 @@ extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
kEnablePerfettoSystemTracing; kEnablePerfettoSystemTracing;
extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature
kEnablePerfettoClientApiProducer;
} // namespace features } // namespace features
namespace tracing { namespace tracing {
......
...@@ -9,8 +9,11 @@ ...@@ -9,8 +9,11 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h" #include "base/test/test_simple_task_runner.h"
#include "base/threading/thread.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
#include "services/tracing/perfetto/test_utils.h" #include "services/tracing/perfetto/test_utils.h"
...@@ -109,6 +112,22 @@ class TracingServiceTest : public testing::Test { ...@@ -109,6 +112,22 @@ class TracingServiceTest : public testing::Test {
factory, base::SequencedTaskRunnerHandle::Get()); factory, base::SequencedTaskRunnerHandle::Get());
} }
void EnableClientApiProducer() {
// Connect the producer part of the client API. AddClient() will end up
// calling TracedProcessImpl::ConnectToTracingService(), which will in turn
// route the PerfettoService interface to the client API backend.
mojo::PendingRemote<tracing::mojom::TracedProcess> traced_process_remote;
traced_process_receiver_ =
std::make_unique<mojo::Receiver<tracing::mojom::TracedProcess>>(
tracing::TracedProcessImpl::GetInstance());
traced_process_receiver_->Bind(
traced_process_remote.InitWithNewPipeAndPassReceiver());
auto client_info = mojom::ClientInfo::New(base::GetCurrentProcId(),
std::move(traced_process_remote));
service()->AddClient(std::move(client_info));
perfetto_service()->SetActiveServicePidsInitialized();
}
size_t ReadAndCountTestPackets(perfetto::TracingSession& session) { size_t ReadAndCountTestPackets(perfetto::TracingSession& session) {
size_t test_packet_count = 0; size_t test_packet_count = 0;
base::RunLoop wait_for_data_loop; base::RunLoop wait_for_data_loop;
...@@ -137,6 +156,9 @@ class TracingServiceTest : public testing::Test { ...@@ -137,6 +156,9 @@ class TracingServiceTest : public testing::Test {
PerfettoService perfetto_service_; PerfettoService perfetto_service_;
TracingService service_; TracingService service_;
std::unique_ptr<mojo::Receiver<tracing::mojom::TracedProcess>>
traced_process_receiver_;
DISALLOW_COPY_AND_ASSIGN(TracingServiceTest); DISALLOW_COPY_AND_ASSIGN(TracingServiceTest);
}; };
...@@ -247,4 +269,97 @@ TEST_F(TracingServiceTest, PerfettoClientConsumer) { ...@@ -247,4 +269,97 @@ TEST_F(TracingServiceTest, PerfettoClientConsumer) {
EXPECT_EQ(kNumPackets, ReadAndCountTestPackets(*session)); EXPECT_EQ(kNumPackets, ReadAndCountTestPackets(*session));
} }
class CustomDataSource : public perfetto::DataSource<CustomDataSource> {
public:
struct Events {
base::RunLoop wait_for_setup_loop;
base::RunLoop wait_for_start_loop;
base::RunLoop wait_for_stop_loop;
};
static void set_events(Events* events) { events_ = events; }
void OnSetup(const SetupArgs&) override {
events_->wait_for_setup_loop.Quit();
}
void OnStart(const StartArgs&) override {
events_->wait_for_start_loop.Quit();
}
void OnStop(const StopArgs&) override { events_->wait_for_stop_loop.Quit(); }
private:
static Events* events_;
};
CustomDataSource::Events* CustomDataSource::events_;
TEST_F(TracingServiceTest, PerfettoClientProducer) {
// Use the client API as the producer for this process instead of
// ProducerClient.
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitAndEnableFeature(
features::kEnablePerfettoClientApiProducer);
// Set up API bindings.
EnableClientApiConsumer();
EnableClientApiProducer();
perfetto::DataSourceDescriptor dsd;
dsd.set_name("com.example.custom_data_source");
CustomDataSource::Events ds_events;
CustomDataSource::set_events(&ds_events);
CustomDataSource::Register(dsd);
// Start a tracing session using the client API.
auto session = perfetto::Tracing::NewTrace();
perfetto::TraceConfig perfetto_config;
perfetto_config.add_buffers()->set_size_kb(1024);
auto* ds_cfg = perfetto_config.add_data_sources()->mutable_config();
ds_cfg->set_name("com.example.custom_data_source");
session->Setup(perfetto_config);
session->Start();
ds_events.wait_for_setup_loop.Run();
ds_events.wait_for_start_loop.Run();
// Write more data to check the commit flow works too.
size_t kNumPackets = 1000;
CustomDataSource::Trace([kNumPackets](CustomDataSource::TraceContext ctx) {
for (size_t i = 0; i < kNumPackets / 2; i++) {
ctx.NewTracePacket()->set_for_testing()->set_str(
tracing::kPerfettoTestString);
}
ctx.Flush();
});
// Write half of the data from another thread to check TLS is hooked up
// properly.
base::Thread thread("TestThread");
thread.Start();
thread.task_runner()->PostTask(
FROM_HERE, base::BindLambdaForTesting([kNumPackets] {
CustomDataSource::Trace(
[kNumPackets](CustomDataSource::TraceContext ctx) {
for (size_t i = 0; i < kNumPackets / 2; i++) {
ctx.NewTracePacket()->set_for_testing()->set_str(
tracing::kPerfettoTestString);
}
ctx.Flush();
});
}));
thread.Stop();
// Stop the session and wait for it to stop. Note that we can't use the
// blocking variants here because the service runs on the current sequence.
base::RunLoop wait_for_stop_loop;
session->SetOnStopCallback(
[&wait_for_stop_loop] { wait_for_stop_loop.Quit(); });
session->Stop();
ds_events.wait_for_stop_loop.Run();
wait_for_stop_loop.Run();
// Read and verify the data.
EXPECT_EQ(kNumPackets, ReadAndCountTestPackets(*session));
}
} // namespace tracing } // namespace tracing
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