tracing_service_impl: Move compression from perfetto_cmd.cc
Before this change, trace compression was implemented in
perfetto_cmd.cc. This meant that it wasn't possible to use compression
with `write_into_file`, because the service would be directly writing
the data to a file, without going through perfetto_cmd.
With this commit the code that does the compression is moved into the
tracing service. Note that compression in the tracing service is only
enabled as part of `traced`, it's not enabled in the tracing service in
the client library (the compressor is injected with a function pointer).
Note that this change might have unexpected behavior when using
mismatching versions of perfetto_cmd and tracing_service (both will try
to compress or none will). In practice I'm not aware of any use of
mismatching versions, so I think it this will not be a problem.
The `compress_from_cli` config option can be used to restore the old
behavior (both in perfetto_cmd and tracing_service).
Here's the change in binary size for various files on android before and
after this patch:
```
| Binary | Size before | Size after |
| -------------------------------- | ----------- | ---------- |
| /system/bin/surfaceflinger | 7445056 | 7445072 |
| /system/lib64/libgpumemtracer.so | 801936 | 806088 |
| /system/lib64/libperfetto.so | 1124896 | 1125184 |
| /system/bin/perfetto | 545176 | 545152 |
```
surfaceflinger and libgpumemtracer statically link the perfetto client
SDK. libperfetto.so contains the tracing service.
The last point to consider is that this makes the compression ratio a
little bit worse when write_into_file is not used. Before this patch,
perfetto_cmd was compressing as part of the same stream up to 512 Kb of
data. Now, reads from IPC are limited to 32 Kb, so that's how often we
have to reset the compression stream. In tested compressing 26 Mb of a
sample trace in both configurations and this are the results I got:
```
| Single stream size | Total size | # of compressed packets |
| -------------------------------- | ---------- | ----------------------- |
| 32 Kb (after this patch) | 9049943 | 574 |
| 64 Kb | 8708512 | 337 |
| 512 Kb (before this patch) | 8306867 | 50 |
```
Bug: 278884624
Change-Id: Ib777ba5c44930a53b3e95994e768a970822e70a3
diff --git a/Android.bp b/Android.bp
index e3a94e7..66715f8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -593,6 +593,7 @@
":perfetto_src_tracing_common",
":perfetto_src_tracing_core_core",
":perfetto_src_tracing_core_service",
+ ":perfetto_src_tracing_core_zlib_compressor",
":perfetto_src_tracing_ipc_common",
":perfetto_src_tracing_ipc_default_socket",
":perfetto_src_tracing_ipc_producer_producer",
@@ -660,10 +661,19 @@
defaults: [
"perfetto_defaults",
],
+ cflags: [
+ "-DZLIB_IMPLEMENTATION",
+ ],
target: {
android: {
shared_libs: [
"liblog",
+ "libz",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libz",
],
},
},
@@ -11299,6 +11309,15 @@
"src/tracing/core/trace_packet_unittest.cc",
"src/tracing/core/trace_writer_impl_unittest.cc",
"src/tracing/core/tracing_service_impl_unittest.cc",
+ "src/tracing/core/zlib_compressor_unittest.cc",
+ ],
+}
+
+// GN: //src/tracing/core:zlib_compressor
+filegroup {
+ name: "perfetto_src_tracing_core_zlib_compressor",
+ srcs: [
+ "src/tracing/core/zlib_compressor.cc",
],
}
@@ -12115,6 +12134,7 @@
":perfetto_src_tracing_core_service",
":perfetto_src_tracing_core_test_support",
":perfetto_src_tracing_core_unittests",
+ ":perfetto_src_tracing_core_zlib_compressor",
":perfetto_src_tracing_ipc_common",
":perfetto_src_tracing_ipc_consumer_consumer",
":perfetto_src_tracing_ipc_default_socket",
diff --git a/BUILD b/BUILD
index a8826c5..a3af5a9 100644
--- a/BUILD
+++ b/BUILD
@@ -279,6 +279,7 @@
":src_tracing_common",
":src_tracing_core_core",
":src_tracing_core_service",
+ ":src_tracing_core_zlib_compressor",
":src_tracing_ipc_common",
":src_tracing_ipc_default_socket",
":src_tracing_ipc_producer_producer",
@@ -355,7 +356,7 @@
":protozero",
":src_base_base",
":src_base_version",
- ],
+ ] + PERFETTO_CONFIG.deps.zlib,
linkstatic = True,
)
@@ -2632,6 +2633,15 @@
],
)
+# GN target: //src/tracing/core:zlib_compressor
+perfetto_filegroup(
+ name = "src_tracing_core_zlib_compressor",
+ srcs = [
+ "src/tracing/core/zlib_compressor.cc",
+ "src/tracing/core/zlib_compressor.h",
+ ],
+)
+
# GN target: //src/tracing/ipc/consumer:consumer
perfetto_filegroup(
name = "src_tracing_ipc_consumer_consumer",
diff --git a/CHANGELOG b/CHANGELOG
index 4d1ee16..107a26b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
Unreleased:
Tracing service and probes:
+ * Compression has been moved from perfetto_cmd to traced. Now compression is
+ supported even with write_into_file. The `compress_from_cli` config option
+ can be used to restore the old behavior.
+ Trace Processor:
*
UI:
*
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index b778d88..579fc0f 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -296,8 +296,9 @@
enable_perfetto_trace_processor &&
(perfetto_build_standalone || perfetto_build_with_android)
- # Enables Zlib support. This is used both by the "perfetto" cmdline client
- # (for compressing traces) and by trace processor (for compressed traces).
+ # Enables Zlib support. This is used to compress traces (by the tracing
+ # service and by the "perfetto" cmdline client) and to decompress traces (by
+ # trace_processor).
enable_perfetto_zlib =
(enable_perfetto_trace_processor && !build_with_chromium) ||
enable_perfetto_platform_services
diff --git a/include/perfetto/ext/tracing/core/tracing_service.h b/include/perfetto/ext/tracing/core/tracing_service.h
index 82e53f7..b82a96a 100644
--- a/include/perfetto/ext/tracing/core/tracing_service.h
+++ b/include/perfetto/ext/tracing/core/tracing_service.h
@@ -28,6 +28,7 @@
#include "perfetto/ext/base/sys_types.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/shared_memory.h"
+#include "perfetto/ext/tracing/core/trace_packet.h"
#include "perfetto/tracing/buffer_exhausted_policy.h"
#include "perfetto/tracing/core/forward_decls.h"
@@ -253,6 +254,14 @@
virtual void SaveTraceForBugreport(SaveTraceForBugreportCallback) = 0;
}; // class ConsumerEndpoint.
+struct PERFETTO_EXPORT_COMPONENT TracingServiceInitOpts {
+ // Function used by tracing service to compress packets. Takes a pointer to
+ // a vector of TracePackets and replaces the packets in the vector with
+ // compressed ones.
+ using CompressorFn = void (*)(std::vector<TracePacket>*);
+ CompressorFn compressor_fn = nullptr;
+};
+
// The public API of the tracing Service business logic.
//
// Exposed to:
@@ -267,6 +276,7 @@
public:
using ProducerEndpoint = perfetto::ProducerEndpoint;
using ConsumerEndpoint = perfetto::ConsumerEndpoint;
+ using InitOpts = TracingServiceInitOpts;
// Default sizes used by the service implementation and client library.
static constexpr size_t kDefaultShmPageSize = 4096ul;
@@ -286,10 +296,12 @@
kDisabled
};
- // Implemented in src/core/tracing_service_impl.cc .
+ // Implemented in src/core/tracing_service_impl.cc . CompressorFn can be
+ // nullptr, in which case TracingService will not support compression.
static std::unique_ptr<TracingService> CreateInstance(
std::unique_ptr<SharedMemory::Factory>,
- base::TaskRunner*);
+ base::TaskRunner*,
+ InitOpts init_opts = {});
virtual ~TracingService();
diff --git a/include/perfetto/ext/tracing/ipc/service_ipc_host.h b/include/perfetto/ext/tracing/ipc/service_ipc_host.h
index 5c51c4a..b24ccb5 100644
--- a/include/perfetto/ext/tracing/ipc/service_ipc_host.h
+++ b/include/perfetto/ext/tracing/ipc/service_ipc_host.h
@@ -23,6 +23,7 @@
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/unix_socket.h"
#include "perfetto/ext/tracing/core/basic_types.h"
+#include "perfetto/ext/tracing/core/tracing_service.h"
namespace perfetto {
namespace base {
@@ -33,8 +34,6 @@
class Host;
} // namespace ipc
-class TracingService;
-
// Creates an instance of the service (business logic + UNIX socket transport).
// Exposed to:
// The code in the tracing client that will host the service e.g., traced.
@@ -42,7 +41,9 @@
// src/tracing/ipc/service/service_ipc_host_impl.cc
class PERFETTO_EXPORT_COMPONENT ServiceIPCHost {
public:
- static std::unique_ptr<ServiceIPCHost> CreateInstance(base::TaskRunner*);
+ static std::unique_ptr<ServiceIPCHost> CreateInstance(
+ base::TaskRunner*,
+ TracingService::InitOpts = {});
virtual ~ServiceIPCHost();
// Start listening on the Producer & Consumer ports. Returns false in case of
diff --git a/protos/perfetto/config/perfetto_config.proto b/protos/perfetto/config/perfetto_config.proto
index 387db1b..646ae1a 100644
--- a/protos/perfetto/config/perfetto_config.proto
+++ b/protos/perfetto/config/perfetto_config.proto
@@ -2700,7 +2700,7 @@
// It contains the general config for the logging buffer(s) and the configs for
// all the data source being enabled.
//
-// Next id: 37.
+// Next id: 38.
message TraceConfig {
message BufferConfig {
optional uint32 size_kb = 1;
@@ -3089,6 +3089,11 @@
}
optional CompressionType compression_type = 24;
+ // Use the legacy codepath that compresses from perfetto_cmd.cc instead of
+ // using the new codepath that compresses from tracing_service_impl.cc. This
+ // will be removed in the future.
+ optional bool compress_from_cli = 37;
+
// Android-only. Not for general use. If set, saves the trace into an
// incident. This field is read by perfetto_cmd, rather than the tracing
// service. This field must be set when passing the --upload flag to
diff --git a/protos/perfetto/config/trace_config.proto b/protos/perfetto/config/trace_config.proto
index ef2702d..4fe3ea9 100644
--- a/protos/perfetto/config/trace_config.proto
+++ b/protos/perfetto/config/trace_config.proto
@@ -26,7 +26,7 @@
// It contains the general config for the logging buffer(s) and the configs for
// all the data source being enabled.
//
-// Next id: 37.
+// Next id: 38.
message TraceConfig {
message BufferConfig {
optional uint32 size_kb = 1;
@@ -415,6 +415,11 @@
}
optional CompressionType compression_type = 24;
+ // Use the legacy codepath that compresses from perfetto_cmd.cc instead of
+ // using the new codepath that compresses from tracing_service_impl.cc. This
+ // will be removed in the future.
+ optional bool compress_from_cli = 37;
+
// Android-only. Not for general use. If set, saves the trace into an
// incident. This field is read by perfetto_cmd, rather than the tracing
// service. This field must be set when passing the --upload flag to
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index 2cce87c..a51e385 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -2700,7 +2700,7 @@
// It contains the general config for the logging buffer(s) and the configs for
// all the data source being enabled.
//
-// Next id: 37.
+// Next id: 38.
message TraceConfig {
message BufferConfig {
optional uint32 size_kb = 1;
@@ -3089,6 +3089,11 @@
}
optional CompressionType compression_type = 24;
+ // Use the legacy codepath that compresses from perfetto_cmd.cc instead of
+ // using the new codepath that compresses from tracing_service_impl.cc. This
+ // will be removed in the future.
+ optional bool compress_from_cli = 37;
+
// Android-only. Not for general use. If set, saves the trace into an
// incident. This field is read by perfetto_cmd, rather than the tracing
// service. This field must be set when passing the --upload flag to
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index b30a8a5..b718ca2 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -799,8 +799,12 @@
packet_writer_ = CreateFilePacketWriter(trace_out_stream_.get());
}
- if (trace_config_->compression_type() ==
- TraceConfig::COMPRESSION_TYPE_DEFLATE) {
+ // TODO(b/281043457): this code path will go away after Android U. Compression
+ // has been moved to the service. This code is here only as a fallback in case
+ // of bugs in the U timeframe.
+ if (trace_config_->compress_from_cli() &&
+ trace_config_->compression_type() ==
+ TraceConfig::COMPRESSION_TYPE_DEFLATE) {
if (packet_writer_) {
#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
packet_writer_ = CreateZipPacketWriter(std::move(packet_writer_));
diff --git a/src/traced/service/BUILD.gn b/src/traced/service/BUILD.gn
index e0770db..cb142e5 100644
--- a/src/traced/service/BUILD.gn
+++ b/src/traced/service/BUILD.gn
@@ -43,6 +43,10 @@
"../../tracing/core:service",
"../../tracing/ipc/service",
]
+ if (enable_perfetto_zlib) {
+ deps += [ "../../tracing/core:zlib_compressor" ]
+ }
+
sources = [
"builtin_producer.cc",
"builtin_producer.h",
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index 72f19ac..c9d6335 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -43,6 +43,10 @@
#include <sys/system_properties.h>
#endif
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include "src/tracing/core/zlib_compressor.h"
+#endif
+
namespace perfetto {
namespace {
#if defined(PERFETTO_SET_SOCKET_PERMISSIONS)
@@ -158,7 +162,11 @@
base::UnixTaskRunner task_runner;
std::unique_ptr<ServiceIPCHost> svc;
- svc = ServiceIPCHost::CreateInstance(&task_runner);
+ TracingService::InitOpts init_opts = {};
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+ init_opts.compressor_fn = &ZlibCompressFn;
+#endif
+ svc = ServiceIPCHost::CreateInstance(&task_runner, init_opts);
// When built as part of the Android tree, the two socket are created and
// bound by init and their fd number is passed in two env variables.
diff --git a/src/tracing/core/BUILD.gn b/src/tracing/core/BUILD.gn
index ea1cb90..3fe90ea 100644
--- a/src/tracing/core/BUILD.gn
+++ b/src/tracing/core/BUILD.gn
@@ -83,6 +83,21 @@
}
}
+if (enable_perfetto_zlib) {
+ source_set("zlib_compressor") {
+ deps = [
+ ":core",
+ "../../../gn:default_deps",
+ "../../../gn:zlib",
+ "../../../include/perfetto/tracing",
+ ]
+ sources = [
+ "zlib_compressor.cc",
+ "zlib_compressor.h",
+ ]
+ }
+}
+
perfetto_unittest_source_set("unittests") {
testonly = true
deps = [
@@ -99,6 +114,14 @@
"../../base:test_support",
"../test:test_support",
]
+
+ if (enable_perfetto_zlib) {
+ deps += [
+ ":zlib_compressor",
+ "../../../gn:zlib",
+ ]
+ }
+
sources = [
"histogram_unittest.cc",
"id_allocator_unittest.cc",
@@ -110,6 +133,10 @@
"trace_packet_unittest.cc",
]
+ if (enable_perfetto_zlib) {
+ sources += [ "zlib_compressor_unittest.cc" ]
+ }
+
# These tests rely on test_task_runner.h which
# has no Windows implementation.
if (!is_win) {
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index bb29a63..f04f67f 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -16,9 +16,6 @@
#include "src/tracing/core/tracing_service_impl.h"
-#include "perfetto/base/build_config.h"
-#include "perfetto/tracing/core/forward_decls.h"
-
#include <errno.h>
#include <limits.h>
#include <string.h>
@@ -304,15 +301,18 @@
// static
std::unique_ptr<TracingService> TracingService::CreateInstance(
std::unique_ptr<SharedMemory::Factory> shm_factory,
- base::TaskRunner* task_runner) {
+ base::TaskRunner* task_runner,
+ InitOpts init_opts) {
return std::unique_ptr<TracingService>(
- new TracingServiceImpl(std::move(shm_factory), task_runner));
+ new TracingServiceImpl(std::move(shm_factory), task_runner, init_opts));
}
TracingServiceImpl::TracingServiceImpl(
std::unique_ptr<SharedMemory::Factory> shm_factory,
- base::TaskRunner* task_runner)
+ base::TaskRunner* task_runner,
+ InitOpts init_opts)
: task_runner_(task_runner),
+ init_opts_(init_opts),
shm_factory_(std::move(shm_factory)),
uid_(base::GetCurrentUserId()),
buffer_ids_(kMaxTraceBufferID),
@@ -856,6 +856,17 @@
tracing_session->bytes_written_into_file = 0;
}
+ if (!cfg.compress_from_cli() &&
+ cfg.compression_type() == TraceConfig::COMPRESSION_TYPE_DEFLATE) {
+ if (init_opts_.compressor_fn) {
+ tracing_session->compress_deflate = true;
+ } else {
+ PERFETTO_LOG(
+ "COMPRESSION_TYPE_DEFLATE is not supported in the current build "
+ "configuration. Skipping compression");
+ }
+ }
+
// Initialize the log buffers.
bool did_allocate_all_buffers = true;
bool invalid_buffer_config = false;
@@ -2327,6 +2338,8 @@
MaybeFilterPackets(tracing_session, &packets);
+ MaybeCompressPackets(tracing_session, &packets);
+
if (!*has_more) {
// We've observed some extremely high memory usage by scudo after
// MaybeFilterPackets in the past. The original bug (b/195145848) is fixed
@@ -2379,6 +2392,16 @@
}
}
+void TracingServiceImpl::MaybeCompressPackets(
+ TracingSession* tracing_session,
+ std::vector<TracePacket>* packets) {
+ if (!tracing_session->compress_deflate) {
+ return;
+ }
+
+ init_opts_.compressor_fn(packets);
+}
+
bool TracingServiceImpl::WriteIntoFile(TracingSession* tracing_session,
std::vector<TracePacket> packets) {
if (!tracing_session->write_into_file) {
diff --git a/src/tracing/core/tracing_service_impl.h b/src/tracing/core/tracing_service_impl.h
index 6ca47b9..8d067fd 100644
--- a/src/tracing/core/tracing_service_impl.h
+++ b/src/tracing/core/tracing_service_impl.h
@@ -87,8 +87,9 @@
// tracing_integration_test.cc and b/195065199
// This is a rough threshold to determine how many bytes to read from the
- // buffers on each iteration when writing into a file. Since filtering
- // allocates memory, this limits the amount of memory allocated.
+ // buffers on each iteration when writing into a file. Since filtering and
+ // compression allocate memory, this effectively limits the amount of memory
+ // allocated.
static constexpr size_t kWriteIntoFileChunkSize = 1024 * 1024ul;
// The implementation behind the service endpoint exposed to each producer.
@@ -265,7 +266,8 @@
};
explicit TracingServiceImpl(std::unique_ptr<SharedMemory::Factory>,
- base::TaskRunner*);
+ base::TaskRunner*,
+ InitOpts = {});
~TracingServiceImpl() override;
// Called by ProducerEndpointImpl.
@@ -566,6 +568,9 @@
// Whether we put the system info into the trace output yet.
bool did_emit_system_info = false;
+ // Whether we should compress TracePackets after reading them.
+ bool compress_deflate = false;
+
// The number of received triggers we've emitted into the trace output.
size_t num_triggers_emitted_into_trace = 0;
@@ -746,6 +751,10 @@
void MaybeFilterPackets(TracingSession* tracing_session,
std::vector<TracePacket>* packets);
+ // If `*tracing_session` has compression enabled, compress `*packets`.
+ void MaybeCompressPackets(TracingSession* tracing_session,
+ std::vector<TracePacket>* packets);
+
// If `*tracing_session` is configured to write into a file, writes `packets`
// into the file.
//
@@ -767,6 +776,7 @@
TracingSessionID);
base::TaskRunner* const task_runner_;
+ const InitOpts init_opts_;
std::unique_ptr<SharedMemory::Factory> shm_factory_;
ProducerID last_producer_id_ = 0;
DataSourceInstanceID last_data_source_instance_id_ = 0;
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index 808e781..c6d7384 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -49,6 +49,11 @@
#include "protos/perfetto/trace/trace_uuid.gen.h"
#include "protos/perfetto/trace/trigger.gen.h"
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#include <zlib.h>
+#include "src/tracing/core/zlib_compressor.h"
+#endif
+
using ::testing::_;
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
@@ -103,6 +108,53 @@
return HasTriggerModeInternal(arg, mode);
}
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+std::string Decompress(const std::string& data) {
+ uint8_t out[1024];
+
+ z_stream stream{};
+ stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data.data()));
+ stream.avail_in = static_cast<unsigned int>(data.size());
+
+ EXPECT_EQ(inflateInit(&stream), Z_OK);
+ std::string s;
+
+ int ret;
+ do {
+ stream.next_out = out;
+ stream.avail_out = sizeof(out);
+ ret = inflate(&stream, Z_NO_FLUSH);
+ EXPECT_NE(ret, Z_STREAM_ERROR);
+ EXPECT_NE(ret, Z_NEED_DICT);
+ EXPECT_NE(ret, Z_DATA_ERROR);
+ EXPECT_NE(ret, Z_MEM_ERROR);
+ s.append(reinterpret_cast<char*>(out), sizeof(out) - stream.avail_out);
+ } while (ret != Z_STREAM_END);
+
+ inflateEnd(&stream);
+ return s;
+}
+
+std::vector<protos::gen::TracePacket> DecompressTrace(
+ const std::vector<protos::gen::TracePacket> compressed) {
+ std::vector<protos::gen::TracePacket> decompressed;
+
+ for (const protos::gen::TracePacket& c : compressed) {
+ if (c.compressed_packets().empty()) {
+ decompressed.push_back(c);
+ continue;
+ }
+
+ std::string s = Decompress(c.compressed_packets());
+ protos::gen::Trace t;
+ EXPECT_TRUE(t.ParseFromString(s));
+ decompressed.insert(decompressed.end(), t.packet().begin(),
+ t.packet().end());
+ }
+ return decompressed;
+}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
} // namespace
class TracingServiceImplTest : public testing::Test {
@@ -110,11 +162,14 @@
using DataSourceInstanceState =
TracingServiceImpl::DataSourceInstance::DataSourceInstanceState;
- TracingServiceImplTest() {
+ TracingServiceImplTest() { InitializeSvcWithOpts({}); }
+
+ void InitializeSvcWithOpts(TracingService::InitOpts init_opts) {
auto shm_factory =
std::unique_ptr<SharedMemory::Factory>(new TestSharedMemory::Factory());
svc.reset(static_cast<TracingServiceImpl*>(
- TracingService::CreateInstance(std::move(shm_factory), &task_runner)
+ TracingService::CreateInstance(std::move(shm_factory), &task_runner,
+ init_opts)
.release()));
svc->min_write_period_ms_ = 1;
}
@@ -1631,6 +1686,244 @@
ASSERT_EQ(6u, connect_producer_and_get_id("6"));
}
+TEST_F(TracingServiceImplTest, CompressionConfiguredButUnsupported) {
+ // Initialize the service without support for compression.
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = nullptr;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ // Ask for compression in the config.
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ consumer->EnableTracing(trace_config);
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ // The packets should NOT be compressed.
+ std::vector<protos::gen::TracePacket> packets = consumer->ReadBuffers();
+ EXPECT_THAT(packets, Not(IsEmpty()));
+ EXPECT_THAT(
+ packets,
+ Each(Property(&protos::gen::TracePacket::has_compressed_packets, false)));
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-1")))));
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-2")))));
+}
+
+#if PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+TEST_F(TracingServiceImplTest, CompressionFromCli) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ // When compress_from_cli is enabled, the service shouldn't do compression
+ trace_config.set_compress_from_cli(true);
+ consumer->EnableTracing(trace_config);
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ std::vector<protos::gen::TracePacket> packets = consumer->ReadBuffers();
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-1")))));
+ EXPECT_THAT(packets, Contains(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str,
+ Eq("payload-2")))));
+}
+
+TEST_F(TracingServiceImplTest, CompressionReadIpc) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ consumer->EnableTracing(trace_config);
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ std::vector<protos::gen::TracePacket> compressed_packets =
+ consumer->ReadBuffers();
+ EXPECT_THAT(compressed_packets, Not(IsEmpty()));
+ EXPECT_THAT(compressed_packets,
+ Each(Property(&protos::gen::TracePacket::compressed_packets,
+ Not(IsEmpty()))));
+ std::vector<protos::gen::TracePacket> decompressed_packets =
+ DecompressTrace(compressed_packets);
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-1")))));
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-2")))));
+}
+
+TEST_F(TracingServiceImplTest, CompressionWriteIntoFile) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+ producer->RegisterDataSource("data_source");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(4096);
+ auto* ds_config = trace_config.add_data_sources()->mutable_config();
+ ds_config->set_name("data_source");
+ ds_config->set_target_buffer(0);
+ trace_config.set_write_into_file(true);
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+ base::TempFile tmp_file = base::TempFile::Create();
+ consumer->EnableTracing(trace_config, base::ScopedFile(dup(tmp_file.fd())));
+
+ producer->WaitForTracingSetup();
+ producer->WaitForDataSourceSetup("data_source");
+ producer->WaitForDataSourceStart("data_source");
+
+ std::unique_ptr<TraceWriter> writer =
+ producer->CreateTraceWriter("data_source");
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-1");
+ }
+ {
+ auto tp = writer->NewTracePacket();
+ tp->set_for_testing()->set_str("payload-2");
+ }
+
+ writer->Flush();
+ writer.reset();
+
+ consumer->DisableTracing();
+ producer->WaitForDataSourceStop("data_source");
+ consumer->WaitForTracingDisabled();
+
+ // Verify the contents of the file.
+ std::string trace_raw;
+ ASSERT_TRUE(base::ReadFile(tmp_file.path().c_str(), &trace_raw));
+ protos::gen::Trace trace;
+ ASSERT_TRUE(trace.ParseFromString(trace_raw));
+ EXPECT_THAT(trace.packet(), Not(IsEmpty()));
+ EXPECT_THAT(trace.packet(),
+ Each(Property(&protos::gen::TracePacket::compressed_packets,
+ Not(IsEmpty()))));
+ std::vector<protos::gen::TracePacket> decompressed_packets =
+ DecompressTrace(trace.packet());
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-1")))));
+ EXPECT_THAT(decompressed_packets,
+ Contains(Property(
+ &protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, Eq("payload-2")))));
+}
+#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+
// Note: file_write_period_ms is set to a large enough to have exactly one flush
// of the tracing buffers (and therefore at most one synchronization section),
// unless the test runs unrealistically slowly, or the implementation of the
diff --git a/src/tracing/core/zlib_compressor.cc b/src/tracing/core/zlib_compressor.cc
new file mode 100644
index 0000000..1a9689e
--- /dev/null
+++ b/src/tracing/core/zlib_compressor.cc
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/tracing/core/zlib_compressor.h"
+
+#if !PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
+#error "Zlib must be enabled to compile this file."
+#endif
+
+#include <zlib.h>
+
+#include "protos/perfetto/trace/trace.pbzero.h"
+#include "protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+namespace {
+
+struct Preamble {
+ uint32_t size;
+ std::array<uint8_t, 16> buf;
+};
+
+template <uint32_t id>
+Preamble GetPreamble(size_t sz) {
+ Preamble preamble;
+ uint8_t* ptr = preamble.buf.data();
+ constexpr uint32_t tag = protozero::proto_utils::MakeTagLengthDelimited(id);
+ ptr = protozero::proto_utils::WriteVarInt(tag, ptr);
+ ptr = protozero::proto_utils::WriteVarInt(sz, ptr);
+ preamble.size =
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr) -
+ reinterpret_cast<uintptr_t>(preamble.buf.data()));
+ PERFETTO_DCHECK(preamble.size < preamble.buf.size());
+ return preamble;
+}
+
+Slice PreambleToSlice(const Preamble& preamble) {
+ Slice slice = Slice::Allocate(preamble.size);
+ memcpy(slice.own_data(), preamble.buf.data(), preamble.size);
+ return slice;
+}
+
+// A compressor for `TracePacket`s that uses zlib. The class is exposed for
+// testing.
+class ZlibPacketCompressor {
+ public:
+ ZlibPacketCompressor();
+ ~ZlibPacketCompressor();
+
+ // Can be called multiple times, before Finish() is called.
+ void PushPacket(const TracePacket& packet);
+
+ // Returned the compressed data. Can be called at most once. After this call,
+ // the object is unusable (PushPacket should not be called) and must be
+ // destroyed.
+ TracePacket Finish();
+
+ private:
+ void PushData(const void* data, uint32_t size);
+ void NewOutputSlice();
+ void PushCurSlice();
+
+ z_stream stream_;
+ size_t total_new_slices_size_ = 0;
+ std::vector<Slice> new_slices_;
+ std::unique_ptr<uint8_t[]> cur_slice_;
+};
+
+ZlibPacketCompressor::ZlibPacketCompressor() {
+ memset(&stream_, 0, sizeof(stream_));
+ int status = deflateInit(&stream_, 6);
+ PERFETTO_CHECK(status == Z_OK);
+}
+
+ZlibPacketCompressor::~ZlibPacketCompressor() {
+ int status = deflateEnd(&stream_);
+ PERFETTO_CHECK(status == Z_OK);
+}
+
+void ZlibPacketCompressor::PushPacket(const TracePacket& packet) {
+ // We need to be able to tokenize packets in the compressed stream, so we
+ // prefix a proto preamble to each packet. The compressed stream looks like a
+ // valid Trace proto.
+ Preamble preamble =
+ GetPreamble<protos::pbzero::Trace::kPacketFieldNumber>(packet.size());
+ PushData(preamble.buf.data(), preamble.size);
+ for (const Slice& slice : packet.slices()) {
+ PushData(slice.start, static_cast<uint32_t>(slice.size));
+ }
+}
+
+void ZlibPacketCompressor::PushData(const void* data, uint32_t size) {
+ stream_.next_in = const_cast<Bytef*>(static_cast<const Bytef*>(data));
+ stream_.avail_in = static_cast<uInt>(size);
+ while (stream_.avail_in != 0) {
+ if (stream_.avail_out == 0) {
+ NewOutputSlice();
+ }
+ int status = deflate(&stream_, Z_NO_FLUSH);
+ PERFETTO_CHECK(status == Z_OK);
+ }
+}
+
+TracePacket ZlibPacketCompressor::Finish() {
+ for (;;) {
+ int status = deflate(&stream_, Z_FINISH);
+ if (status == Z_STREAM_END)
+ break;
+ PERFETTO_CHECK(status == Z_OK || status == Z_BUF_ERROR);
+ NewOutputSlice();
+ }
+
+ PushCurSlice();
+
+ TracePacket packet;
+ packet.AddSlice(PreambleToSlice(
+ GetPreamble<protos::pbzero::TracePacket::kCompressedPacketsFieldNumber>(
+ total_new_slices_size_)));
+ for (auto& slice : new_slices_) {
+ packet.AddSlice(std::move(slice));
+ }
+ return packet;
+}
+
+void ZlibPacketCompressor::NewOutputSlice() {
+ PushCurSlice();
+ cur_slice_ = std::make_unique<uint8_t[]>(kZlibCompressSliceSize);
+ stream_.next_out = reinterpret_cast<Bytef*>(cur_slice_.get());
+ stream_.avail_out = kZlibCompressSliceSize;
+}
+
+void ZlibPacketCompressor::PushCurSlice() {
+ if (cur_slice_) {
+ total_new_slices_size_ += kZlibCompressSliceSize - stream_.avail_out;
+ new_slices_.push_back(Slice::TakeOwnership(
+ std::move(cur_slice_), kZlibCompressSliceSize - stream_.avail_out));
+ }
+}
+
+} // namespace
+
+void ZlibCompressFn(std::vector<TracePacket>* packets) {
+ if (packets->empty()) {
+ return;
+ }
+
+ ZlibPacketCompressor stream;
+
+ for (const TracePacket& packet : *packets) {
+ stream.PushPacket(packet);
+ }
+
+ TracePacket packet = stream.Finish();
+
+ packets->clear();
+ packets->push_back(std::move(packet));
+}
+
+} // namespace perfetto
diff --git a/src/tracing/core/zlib_compressor.h b/src/tracing/core/zlib_compressor.h
new file mode 100644
index 0000000..1962c48
--- /dev/null
+++ b/src/tracing/core/zlib_compressor.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACING_CORE_ZLIB_COMPRESSOR_H_
+#define SRC_TRACING_CORE_ZLIB_COMPRESSOR_H_
+
+#include <vector>
+
+#include "perfetto/ext/tracing/core/trace_packet.h"
+
+namespace perfetto {
+
+// Matches TracingServiceImpl::kMaxTracePacketSliceSize. Exposed for testing.
+static constexpr size_t kZlibCompressSliceSize = 128 * 1024 - 512;
+
+void ZlibCompressFn(std::vector<TracePacket>*);
+
+} // namespace perfetto
+
+#endif // SRC_TRACING_CORE_ZLIB_COMPRESSOR_H_
diff --git a/src/tracing/core/zlib_compressor_unittest.cc b/src/tracing/core/zlib_compressor_unittest.cc
new file mode 100644
index 0000000..2471c1b
--- /dev/null
+++ b/src/tracing/core/zlib_compressor_unittest.cc
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/tracing/core/zlib_compressor.h"
+
+#include <random>
+
+#include <zlib.h>
+
+#include "protos/perfetto/trace/test_event.gen.h"
+#include "protos/perfetto/trace/trace.gen.h"
+#include "protos/perfetto/trace/trace_packet.gen.h"
+#include "src/tracing/core/tracing_service_impl.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace {
+
+using ::testing::Each;
+using ::testing::ElementsAre;
+using ::testing::Field;
+using ::testing::IsEmpty;
+using ::testing::Le;
+using ::testing::Not;
+using ::testing::Property;
+using ::testing::SizeIs;
+
+template <typename F>
+TracePacket CreateTracePacket(F fill_function) {
+ protos::gen::TracePacket msg;
+ fill_function(&msg);
+ std::vector<uint8_t> buf = msg.SerializeAsArray();
+ Slice slice = Slice::Allocate(buf.size());
+ memcpy(slice.own_data(), buf.data(), buf.size());
+ perfetto::TracePacket packet;
+ packet.AddSlice(std::move(slice));
+ return packet;
+}
+
+// Return a copy of the `old` trace packets that owns its own slices data.
+TracePacket CopyTracePacket(const TracePacket& old) {
+ TracePacket ret;
+ for (const Slice& slice : old.slices()) {
+ auto new_slice = Slice::Allocate(slice.size);
+ memcpy(new_slice.own_data(), slice.start, slice.size);
+ ret.AddSlice(std::move(new_slice));
+ }
+ return ret;
+}
+
+std::vector<TracePacket> CopyTracePackets(const std::vector<TracePacket>& old) {
+ std::vector<TracePacket> ret;
+ ret.reserve(old.size());
+ for (const TracePacket& trace_packet : old) {
+ ret.push_back(CopyTracePacket(trace_packet));
+ }
+ return ret;
+}
+std::string RandomString(size_t size) {
+ std::default_random_engine rnd(0);
+ std::uniform_int_distribution<> dist(0, 255);
+ std::string s;
+ s.resize(size);
+ for (size_t i = 0; i < s.size(); i++)
+ s[i] = static_cast<char>(dist(rnd));
+ return s;
+}
+
+std::string Decompress(const std::string& data) {
+ uint8_t out[1024];
+
+ z_stream stream{};
+ stream.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data.data()));
+ stream.avail_in = static_cast<unsigned int>(data.size());
+
+ EXPECT_EQ(inflateInit(&stream), Z_OK);
+ std::string s;
+
+ int ret;
+ do {
+ stream.next_out = out;
+ stream.avail_out = sizeof(out);
+ ret = inflate(&stream, Z_NO_FLUSH);
+ EXPECT_NE(ret, Z_STREAM_ERROR);
+ EXPECT_NE(ret, Z_NEED_DICT);
+ EXPECT_NE(ret, Z_DATA_ERROR);
+ EXPECT_NE(ret, Z_MEM_ERROR);
+ s.append(reinterpret_cast<char*>(out), sizeof(out) - stream.avail_out);
+ } while (ret != Z_STREAM_END);
+
+ inflateEnd(&stream);
+ return s;
+}
+
+static_assert(kZlibCompressSliceSize ==
+ TracingServiceImpl::kMaxTracePacketSliceSize);
+
+TEST(ZlibCompressFnTest, Empty) {
+ std::vector<TracePacket> packets;
+
+ ZlibCompressFn(&packets);
+
+ EXPECT_THAT(packets, IsEmpty());
+}
+
+TEST(ZlibCompressFnTest, End2EndCompressAndDecompress) {
+ std::vector<TracePacket> packets;
+
+ packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
+ auto* for_testing = msg->mutable_for_testing();
+ for_testing->set_str("abc");
+ }));
+ packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
+ auto* for_testing = msg->mutable_for_testing();
+ for_testing->set_str("def");
+ }));
+
+ ZlibCompressFn(&packets);
+
+ ASSERT_THAT(packets, SizeIs(1));
+ protos::gen::TracePacket compressed_packet_proto;
+ ASSERT_TRUE(compressed_packet_proto.ParseFromString(
+ packets[0].GetRawBytesForTesting()));
+ const std::string& data = compressed_packet_proto.compressed_packets();
+ EXPECT_THAT(data, Not(IsEmpty()));
+ protos::gen::Trace subtrace;
+ ASSERT_TRUE(subtrace.ParseFromString(Decompress(data)));
+ EXPECT_THAT(
+ subtrace.packet(),
+ ElementsAre(Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, "abc")),
+ Property(&protos::gen::TracePacket::for_testing,
+ Property(&protos::gen::TestEvent::str, "def"))));
+}
+
+TEST(ZlibCompressFnTest, MaxSliceSize) {
+ std::vector<TracePacket> packets;
+
+ constexpr size_t kStopOutputSize =
+ TracingServiceImpl::kMaxTracePacketSliceSize + 2000;
+
+ TracePacket compressed_packet;
+ while (compressed_packet.size() < kStopOutputSize) {
+ packets.push_back(CreateTracePacket([](protos::gen::TracePacket* msg) {
+ auto* for_testing = msg->mutable_for_testing();
+ for_testing->set_str(RandomString(65536));
+ }));
+ {
+ std::vector<TracePacket> packets_copy = CopyTracePackets(packets);
+ ZlibCompressFn(&packets_copy);
+ ASSERT_THAT(packets_copy, SizeIs(1));
+ compressed_packet = std::move(packets_copy[0]);
+ }
+ }
+
+ EXPECT_GE(compressed_packet.slices().size(), 2u);
+ ASSERT_GT(compressed_packet.size(),
+ TracingServiceImpl::kMaxTracePacketSliceSize);
+ EXPECT_THAT(compressed_packet.slices(),
+ Each(Field(&Slice::size,
+ Le(TracingServiceImpl::kMaxTracePacketSliceSize))));
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.cc b/src/tracing/ipc/service/service_ipc_host_impl.cc
index 85029a2..1df674e 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.cc
+++ b/src/tracing/ipc/service/service_ipc_host_impl.cc
@@ -40,12 +40,15 @@
// Implements the publicly exposed factory method declared in
// include/tracing/posix_ipc/posix_service_host.h.
std::unique_ptr<ServiceIPCHost> ServiceIPCHost::CreateInstance(
- base::TaskRunner* task_runner) {
- return std::unique_ptr<ServiceIPCHost>(new ServiceIPCHostImpl(task_runner));
+ base::TaskRunner* task_runner,
+ TracingService::InitOpts init_opts) {
+ return std::unique_ptr<ServiceIPCHost>(
+ new ServiceIPCHostImpl(task_runner, init_opts));
}
-ServiceIPCHostImpl::ServiceIPCHostImpl(base::TaskRunner* task_runner)
- : task_runner_(task_runner) {}
+ServiceIPCHostImpl::ServiceIPCHostImpl(base::TaskRunner* task_runner,
+ TracingService::InitOpts init_opts)
+ : task_runner_(task_runner), init_opts_(init_opts) {}
ServiceIPCHostImpl::~ServiceIPCHostImpl() {}
@@ -95,7 +98,8 @@
std::unique_ptr<SharedMemory::Factory> shm_factory(
new PosixSharedMemory::Factory());
#endif
- svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_);
+ svc_ = TracingService::CreateInstance(std::move(shm_factory), task_runner_,
+ init_opts_);
if (!producer_ipc_port_ || !consumer_ipc_port_) {
Shutdown();
diff --git a/src/tracing/ipc/service/service_ipc_host_impl.h b/src/tracing/ipc/service/service_ipc_host_impl.h
index dda7e5b..4ccfa65 100644
--- a/src/tracing/ipc/service/service_ipc_host_impl.h
+++ b/src/tracing/ipc/service/service_ipc_host_impl.h
@@ -33,7 +33,8 @@
// producer_ipc_service.cc and consumer_ipc_service.cc.
class ServiceIPCHostImpl : public ServiceIPCHost {
public:
- ServiceIPCHostImpl(base::TaskRunner*);
+ explicit ServiceIPCHostImpl(base::TaskRunner*,
+ TracingService::InitOpts init_opts = {});
~ServiceIPCHostImpl() override;
// ServiceIPCHost implementation.
@@ -51,6 +52,7 @@
void Shutdown();
base::TaskRunner* const task_runner_;
+ const TracingService::InitOpts init_opts_;
std::unique_ptr<TracingService> svc_; // The service business logic.
// The IPC host that listens on the Producer socket. It owns the
diff --git a/tools/gen_amalgamated b/tools/gen_amalgamated
index c529155..fac7f60 100755
--- a/tools/gen_amalgamated
+++ b/tools/gen_amalgamated
@@ -44,6 +44,7 @@
# line).
gn_args = ' '.join([
'enable_perfetto_ipc=true',
+ 'enable_perfetto_zlib=false',
'is_debug=false',
'is_perfetto_build_generator=true',
'is_perfetto_embedder=true',