tracing: Add init option to avoid linking system consumer
Today when using perfetto::Tracing::Initialize() with the system
backend, both the producer and the consumer side of the ipcs are linked
in, even though most perfetto users will not likely use the consumer
side.
The consumer side implementation is responsible for a large portion of
the statically linked binary size (~100Kbytes out of ~700kBytes, thanks
rzuklie@google.com for finding that out!).
This commit adds an option to perfetto::Tracing::Initialize to avoid
initializing the consumer side of the system backend.
Change-Id: I17a72f4864c6c300a6a734f93b349e6d020f1967
diff --git a/CHANGELOG b/CHANGELOG
index 36e88af..ef4b9fc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,8 @@
been deprecated in favor of this new functionality.
* Deprecated the PERFETTO_COMPONENT_EXPORT macro in favor of
PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE_WITH_ATTRS.
+ * Added TracingInitArgs::enable_system_consumer configuration option, that
+ allows the linker to discard the consumer IPC, if not required.
v31.0 - 2022-11-10:
diff --git a/include/perfetto/tracing/internal/system_tracing_backend.h b/include/perfetto/tracing/internal/system_tracing_backend.h
index e1b0ff3..ded54c5 100644
--- a/include/perfetto/tracing/internal/system_tracing_backend.h
+++ b/include/perfetto/tracing/internal/system_tracing_backend.h
@@ -35,6 +35,8 @@
// together with system traces, useful to correlate on the timeline system
// events (e.g. scheduling slices from the kernel) with in-app events.
namespace internal {
+
+// Full backend (with producer and consumer)
class PERFETTO_EXPORT_COMPONENT SystemTracingBackend : public TracingBackend {
public:
static TracingBackend* GetInstance();
@@ -49,6 +51,22 @@
SystemTracingBackend();
};
+// Producer only backend.
+class PERFETTO_EXPORT_COMPONENT SystemTracingProducerOnlyBackend
+ : public TracingBackend {
+ public:
+ static TracingBackend* GetInstance();
+
+ // TracingBackend implementation.
+ std::unique_ptr<ProducerEndpoint> ConnectProducer(
+ const ConnectProducerArgs&) override;
+ std::unique_ptr<ConsumerEndpoint> ConnectConsumer(
+ const ConnectConsumerArgs&) override;
+
+ private:
+ SystemTracingProducerOnlyBackend();
+};
+
} // namespace internal
} // namespace perfetto
diff --git a/include/perfetto/tracing/tracing.h b/include/perfetto/tracing/tracing.h
index f289f49..73496d4 100644
--- a/include/perfetto/tracing/tracing.h
+++ b/include/perfetto/tracing/tracing.h
@@ -127,6 +127,13 @@
// with CLOCK_MONOTONIC_RAW on platforms that support it.
bool use_monotonic_raw_clock = false;
+ // This flag can be set to false in order to avoid enabling the system
+ // consumer in Tracing::Initialize(), so that the linker can remove the unused
+ // consumer IPC implementation to reduce binary size. When this option is
+ // false, calling Tracing::NewTrace() on the system backend will fail. This
+ // setting only has an effect if kSystemBackend is specified in |backends|.
+ bool enable_system_consumer = true;
+
protected:
friend class Tracing;
friend class internal::TracingMuxerImpl;
@@ -136,11 +143,13 @@
bool operator==(const TracingInitArgs& other) const {
return std::tie(backends, custom_backend, platform, shmem_size_hint_kb,
shmem_page_size_hint_kb, in_process_backend_factory_,
- system_backend_factory_, dcheck_is_on_) ==
+ system_backend_factory_, dcheck_is_on_,
+ enable_system_consumer) ==
std::tie(other.backends, other.custom_backend, other.platform,
other.shmem_size_hint_kb, other.shmem_page_size_hint_kb,
other.in_process_backend_factory_,
- other.system_backend_factory_, other.dcheck_is_on_);
+ other.system_backend_factory_, other.dcheck_is_on_,
+ other.enable_system_consumer);
}
using BackendFactoryFunction = TracingBackend* (*)();
@@ -173,8 +182,13 @@
&internal::InProcessTracingBackend::GetInstance;
}
if (args.backends & kSystemBackend) {
- args_copy.system_backend_factory_ =
- &internal::SystemTracingBackend::GetInstance;
+ if (args.enable_system_consumer) {
+ args_copy.system_backend_factory_ =
+ &internal::SystemTracingBackend::GetInstance;
+ } else {
+ args_copy.system_backend_factory_ =
+ &internal::SystemTracingProducerOnlyBackend::GetInstance;
+ }
}
InitializeInternal(args_copy);
}
@@ -184,8 +198,6 @@
// Start a new tracing session using the given tracing backend. Use
// |kUnspecifiedBackend| to select an available backend automatically.
- // For the moment this can be used only when initializing tracing in
- // kInProcess mode. For the system mode use the 'bin/perfetto' cmdline client.
static std::unique_ptr<TracingSession> NewTrace(
BackendType = kUnspecifiedBackend);
diff --git a/src/tracing/internal/system_tracing_backend.cc b/src/tracing/internal/system_tracing_backend.cc
index 8aacd8d..824311d 100644
--- a/src/tracing/internal/system_tracing_backend.cc
+++ b/src/tracing/internal/system_tracing_backend.cc
@@ -34,17 +34,10 @@
namespace perfetto {
namespace internal {
+namespace {
-// static
-TracingBackend* SystemTracingBackend::GetInstance() {
- static auto* instance = new SystemTracingBackend();
- return instance;
-}
-
-SystemTracingBackend::SystemTracingBackend() {}
-
-std::unique_ptr<ProducerEndpoint> SystemTracingBackend::ConnectProducer(
- const ConnectProducerArgs& args) {
+std::unique_ptr<ProducerEndpoint> CreateProducerEndpoint(
+ const TracingBackend::ConnectProducerArgs& args) {
PERFETTO_DCHECK(args.task_runner->RunsTasksOnCurrentThread());
std::unique_ptr<SharedMemory> shm;
@@ -74,6 +67,21 @@
return endpoint;
}
+} // namespace
+
+// static
+TracingBackend* SystemTracingBackend::GetInstance() {
+ static auto* instance = new SystemTracingBackend();
+ return instance;
+}
+
+SystemTracingBackend::SystemTracingBackend() {}
+
+std::unique_ptr<ProducerEndpoint> SystemTracingBackend::ConnectProducer(
+ const ConnectProducerArgs& args) {
+ return CreateProducerEndpoint(args);
+}
+
std::unique_ptr<ConsumerEndpoint> SystemTracingBackend::ConnectConsumer(
const ConnectConsumerArgs& args) {
#if PERFETTO_BUILDFLAG(PERFETTO_SYSTEM_CONSUMER)
@@ -88,5 +96,29 @@
#endif
}
+// static
+TracingBackend* SystemTracingProducerOnlyBackend::GetInstance() {
+ static auto* instance = new SystemTracingProducerOnlyBackend();
+ return instance;
+}
+
+SystemTracingProducerOnlyBackend::SystemTracingProducerOnlyBackend() {}
+
+std::unique_ptr<ProducerEndpoint>
+SystemTracingProducerOnlyBackend::ConnectProducer(
+ const ConnectProducerArgs& args) {
+ return CreateProducerEndpoint(args);
+}
+
+std::unique_ptr<ConsumerEndpoint>
+SystemTracingProducerOnlyBackend::ConnectConsumer(
+ const ConnectConsumerArgs& args) {
+ base::ignore_result(args);
+ PERFETTO_FATAL(
+ "System backend consumer support disabled. "
+ "TracingInitArgs::enable_system_consumer was false");
+ return nullptr;
+}
+
} // namespace internal
} // namespace perfetto
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index e363f8c..463d0d4 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -875,6 +875,7 @@
rb.backend = backend;
rb.id = backend_id;
rb.type = type;
+ rb.consumer_enabled = type != kSystemBackend || args.enable_system_consumer;
rb.producer.reset(new ProducerImpl(this, backend_id,
args.shmem_batch_commits_duration_ms));
rb.producer_conn_args.producer = rb.producer.get();
@@ -2051,6 +2052,10 @@
continue;
}
+ if (!backend.consumer_enabled) {
+ continue;
+ }
+
TracingBackendId backend_id = backend.id;
// Create the consumer now, even if we have to ask the embedder below, so
diff --git a/src/tracing/internal/tracing_muxer_impl.h b/src/tracing/internal/tracing_muxer_impl.h
index 2cb3441..4d83ab9 100644
--- a/src/tracing/internal/tracing_muxer_impl.h
+++ b/src/tracing/internal/tracing_muxer_impl.h
@@ -439,6 +439,8 @@
std::vector<std::unique_ptr<ConsumerImpl>> consumers;
std::vector<RegisteredStartupSession> startup_sessions;
+
+ bool consumer_enabled = true;
};
void UpdateDataSourceOnAllBackends(RegisteredDataSource& rds,
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index f52a075..0e131dd 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -6005,6 +6005,46 @@
EXPECT_THAT(slices3, ElementsAre("B:test.DrawGame3"));
}
+TEST(PerfettoApiInitTest, DisableSystemConsumer) {
+ g_test_tracing_policy->should_allow_consumer_connection = true;
+
+ auto system_service = perfetto::test::SystemService::Start();
+ // If the system backend isn't supported, skip
+ if (!system_service.valid()) {
+ GTEST_SKIP();
+ }
+
+ EXPECT_FALSE(perfetto::Tracing::IsInitialized());
+ TracingInitArgs args;
+ args.backends = perfetto::kSystemBackend;
+ args.tracing_policy = g_test_tracing_policy;
+ args.enable_system_consumer = false;
+ perfetto::Tracing::Initialize(args);
+
+ // If this wasn't the first test to run in this process, any producers
+ // connected to the old system service will have been disconnected by the
+ // service restarting above. Wait for all producers to connect again before
+ // proceeding with the test.
+ perfetto::test::SyncProducers();
+
+ perfetto::test::DisableReconnectLimit();
+
+ std::unique_ptr<perfetto::TracingSession> ts =
+ perfetto::Tracing::NewTrace(perfetto::kSystemBackend);
+
+ // Creating the consumer should cause an asynchronous disconnect error.
+ WaitableTestEvent got_error;
+ ts->SetOnErrorCallback([&](perfetto::TracingError error) {
+ EXPECT_EQ(perfetto::TracingError::kDisconnected, error.code);
+ EXPECT_FALSE(error.message.empty());
+ got_error.Notify();
+ });
+ got_error.Wait();
+ ts.reset();
+
+ perfetto::Tracing::ResetForTesting();
+}
+
struct BackendTypeAsString {
std::string operator()(
const ::testing::TestParamInfo<perfetto::BackendType>& info) const {