123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- // 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/test_utils.h"
- #include <utility>
- #include "base/bind.h"
- #include "base/run_loop.h"
- #include "base/tracing/perfetto_platform.h"
- #include "services/tracing/public/cpp/perfetto/shared_memory.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/perfetto/include/perfetto/ext/tracing/core/commit_data_request.h"
- #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
- #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_writer.h"
- #include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
- #include "third_party/perfetto/protos/perfetto/trace/test_event.pbzero.h"
- #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
- #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
- namespace tracing {
- namespace {
- perfetto::TraceConfig GetDefaultTraceConfig(
- const std::vector<std::string>& data_sources) {
- perfetto::TraceConfig trace_config;
- trace_config.add_buffers()->set_size_kb(1024 * 32);
- for (const auto& data_source : data_sources) {
- auto* ds_config = trace_config.add_data_sources()->mutable_config();
- ds_config->set_name(data_source);
- ds_config->set_target_buffer(0);
- }
- return trace_config;
- }
- } // namespace
- // static
- std::unique_ptr<TestDataSource> TestDataSource::CreateAndRegisterDataSource(
- const std::string& data_source_name,
- size_t send_packet_count) {
- auto data_source = std::unique_ptr<TestDataSource>(
- new TestDataSource(data_source_name, send_packet_count));
- PerfettoTracedProcess::Get()->AddDataSource(data_source.get());
- return data_source;
- }
- TestDataSource::TestDataSource(const std::string& data_source_name,
- size_t send_packet_count)
- : DataSourceBase(data_source_name), send_packet_count_(send_packet_count) {
- }
- TestDataSource::~TestDataSource() = default;
- void TestDataSource::WritePacketBigly() {
- std::unique_ptr<char[]> payload(new char[kLargeMessageSize]);
- memset(payload.get(), '.', kLargeMessageSize);
- payload.get()[kLargeMessageSize - 1] = 0;
- std::unique_ptr<perfetto::TraceWriter> writer =
- producer_->CreateTraceWriter(config_.target_buffer());
- CHECK(writer);
- writer->NewTracePacket()->set_for_testing()->set_str(payload.get(),
- kLargeMessageSize);
- }
- void TestDataSource::StartTracingImpl(
- PerfettoProducer* producer,
- const perfetto::DataSourceConfig& data_source_config) {
- producer_ = producer;
- config_ = data_source_config;
- if (send_packet_count_ > 0) {
- std::unique_ptr<perfetto::TraceWriter> writer =
- producer_->CreateTraceWriter(config_.target_buffer());
- CHECK(writer);
- for (size_t i = 0; i < send_packet_count_; i++) {
- writer->NewTracePacket()->set_for_testing()->set_str(kPerfettoTestString);
- }
- }
- if (!start_tracing_callback_.is_null()) {
- std::move(start_tracing_callback_).Run();
- }
- }
- void TestDataSource::StopTracingImpl(base::OnceClosure stop_complete_callback) {
- CHECK(producer_);
- producer_ = nullptr;
- std::move(stop_complete_callback).Run();
- }
- void TestDataSource::Flush(base::RepeatingClosure flush_complete_callback) {
- if (flush_complete_callback) {
- flush_complete_callback.Run();
- }
- }
- void TestDataSource::set_start_tracing_callback(
- base::OnceClosure start_tracing_callback) {
- start_tracing_callback_ = std::move(start_tracing_callback);
- }
- MockProducerClient::MockProducerClient(
- uint32_t num_data_sources,
- base::OnceClosure client_enabled_callback,
- base::OnceClosure client_disabled_callback)
- : ProducerClient(PerfettoTracedProcess::Get()->GetTaskRunner()),
- num_data_sources_expected_(num_data_sources),
- client_enabled_callback_(std::move(client_enabled_callback)),
- client_disabled_callback_(std::move(client_disabled_callback)) {
- // Create SMB immediately since we never call ProducerClient's Connect().
- CHECK(InitSharedMemoryIfNeeded());
- }
- MockProducerClient::~MockProducerClient() = default;
- // static
- std::unique_ptr<MockProducerClient::Handle> MockProducerClient::Create(
- uint32_t num_data_sources,
- base::OnceClosure client_enabled_callback,
- base::OnceClosure client_disabled_callback) {
- std::unique_ptr<MockProducerClient> client(new MockProducerClient(
- num_data_sources, std::move(client_enabled_callback),
- std::move(client_disabled_callback)));
- auto handle = std::make_unique<Handle>(client.get());
- // Transfer ownership of the client to PerfettoTracedProcess.
- PerfettoTracedProcess::Get()
- ->GetTaskRunner()
- ->GetOrCreateTaskRunner()
- ->PostTask(
- FROM_HERE,
- base::BindOnce(
- [](std::unique_ptr<MockProducerClient> client) {
- auto* raw_client = client.get();
- raw_client->old_producer_ =
- PerfettoTracedProcess::Get()->SetProducerClientForTesting(
- std::move(client));
- },
- std::move(client)));
- return handle;
- }
- MockProducerClient::Handle::~Handle() {
- // Replace the previous client in PerfettoTracedProcess, deleting the mock
- // as a side-effect.
- PerfettoTracedProcess::Get()
- ->GetTaskRunner()
- ->GetOrCreateTaskRunner()
- ->PostTask(
- FROM_HERE,
- base::BindOnce(
- [](std::unique_ptr<ProducerClient> old_producer) {
- PerfettoTracedProcess::Get()->SetProducerClientForTesting(
- std::move(old_producer));
- },
- std::move(client_->old_producer_)));
- }
- void MockProducerClient::SetupDataSource(const std::string& data_source_name) {}
- void MockProducerClient::StartDataSource(
- uint64_t id,
- const perfetto::DataSourceConfig& data_source_config,
- StartDataSourceCallback callback) {
- ProducerClient::StartDataSource(id, std::move(data_source_config),
- std::move(callback));
- CHECK_LT(num_data_sources_active_, num_data_sources_expected_);
- if (++num_data_sources_active_ == num_data_sources_expected_ &&
- client_enabled_callback_) {
- std::move(client_enabled_callback_).Run();
- }
- }
- void MockProducerClient::StopDataSource(uint64_t id,
- StopDataSourceCallback callback) {
- ProducerClient::StopDataSource(id, std::move(callback));
- CHECK_GT(num_data_sources_active_, 0u);
- if (--num_data_sources_active_ == 0 && client_disabled_callback_) {
- std::move(client_disabled_callback_).Run();
- }
- }
- void MockProducerClient::CommitData(const perfetto::CommitDataRequest& commit,
- CommitDataCallback callback) {
- // Only write out commits that have actual data in it; Perfetto
- // might send two commits from different threads (one always empty),
- // which causes TSan to complain.
- if (commit.chunks_to_patch_size() || commit.chunks_to_move_size()) {
- all_client_commit_data_requests_.push_back(commit.SerializeAsString());
- }
- ProducerClient::CommitData(commit, callback);
- }
- void MockProducerClient::SetAgentEnabledCallback(
- base::OnceClosure client_enabled_callback) {
- client_enabled_callback_ = std::move(client_enabled_callback);
- }
- void MockProducerClient::SetAgentDisabledCallback(
- base::OnceClosure client_disabled_callback) {
- client_disabled_callback_ = std::move(client_disabled_callback);
- }
- MockConsumer::MockConsumer(std::vector<std::string> data_source_names,
- perfetto::TracingService* service,
- PacketReceivedCallback packet_received_callback)
- : MockConsumer(data_source_names,
- service,
- std::move(packet_received_callback),
- GetDefaultTraceConfig(data_source_names)) {}
- MockConsumer::MockConsumer(std::vector<std::string> data_source_names,
- perfetto::TracingService* service,
- PacketReceivedCallback packet_received_callback,
- const perfetto::TraceConfig& config)
- : packet_received_callback_(packet_received_callback),
- trace_config_(config) {
- for (const auto& source : data_source_names) {
- data_sources_.emplace_back(DataSourceStatus{
- source,
- perfetto::ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED});
- }
- CHECK(!data_sources_.empty());
- consumer_endpoint_ = service->ConnectConsumer(this, /*uid=*/0);
- CHECK(consumer_endpoint_);
- }
- MockConsumer::~MockConsumer() = default;
- void MockConsumer::ReadBuffers() {
- CHECK(consumer_endpoint_);
- consumer_endpoint_->ReadBuffers();
- }
- void MockConsumer::StopTracing() {
- ReadBuffers();
- CHECK(consumer_endpoint_);
- consumer_endpoint_->DisableTracing();
- }
- void MockConsumer::StartTracing() {
- CHECK(consumer_endpoint_);
- consumer_endpoint_->EnableTracing(trace_config_);
- }
- void MockConsumer::FreeBuffers() {
- CHECK(consumer_endpoint_);
- consumer_endpoint_->FreeBuffers();
- }
- void MockConsumer::OnConnect() {
- consumer_endpoint_->ObserveEvents(
- perfetto::ObservableEvents::TYPE_DATA_SOURCES_INSTANCES);
- StartTracing();
- }
- void MockConsumer::OnDisconnect() {}
- void MockConsumer::OnTracingDisabled(const std::string& error) {}
- void MockConsumer::OnTraceData(std::vector<perfetto::TracePacket> packets,
- bool has_more) {
- for (auto& encoded_packet : packets) {
- perfetto::protos::TracePacket packet;
- EXPECT_TRUE(packet.ParseFromString(encoded_packet.GetRawBytesForTesting()));
- ++received_packets_;
- if (packet.for_testing().str() == kPerfettoTestString) {
- ++received_test_packets_;
- }
- }
- packet_received_callback_(has_more);
- }
- void MockConsumer::OnDetach(bool /*success*/) {}
- void MockConsumer::OnAttach(bool /*success*/, const perfetto::TraceConfig&) {}
- void MockConsumer::OnTraceStats(bool /*success*/, const perfetto::TraceStats&) {
- }
- void MockConsumer::OnObservableEvents(
- const perfetto::ObservableEvents& events) {
- for (const auto& change : events.instance_state_changes()) {
- for (auto& data_source_status : data_sources_) {
- if (change.data_source_name() != data_source_status.name) {
- continue;
- }
- data_source_status.state = change.state();
- }
- CheckForAllDataSourcesStarted();
- CheckForAllDataSourcesStopped();
- }
- }
- void MockConsumer::WaitForAllDataSourcesStarted() {
- base::RunLoop on_started;
- on_started_runloop_ = &on_started;
- CheckForAllDataSourcesStarted();
- if (on_started_runloop_) {
- on_started_runloop_->Run();
- }
- }
- void MockConsumer::WaitForAllDataSourcesStopped() {
- base::RunLoop on_stopped;
- on_stopped_runloop_ = &on_stopped;
- CheckForAllDataSourcesStopped();
- if (on_stopped_runloop_) {
- on_stopped_runloop_->Run();
- }
- }
- void MockConsumer::CheckForAllDataSourcesStarted() {
- for (auto& data_source_status : data_sources_) {
- if (data_source_status.state !=
- perfetto::ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STARTED) {
- return;
- }
- }
- if (on_started_runloop_) {
- on_started_runloop_->Quit();
- on_started_runloop_ = nullptr;
- }
- }
- void MockConsumer::CheckForAllDataSourcesStopped() {
- for (auto& data_source_status : data_sources_) {
- if (data_source_status.state !=
- perfetto::ObservableEvents::DATA_SOURCE_INSTANCE_STATE_STOPPED) {
- return;
- }
- }
- if (on_stopped_runloop_) {
- on_stopped_runloop_->Quit();
- on_stopped_runloop_ = nullptr;
- }
- }
- MockProducerHost::MockProducerHost(
- const std::string& producer_name,
- const std::string& data_source_name,
- PerfettoService* service,
- MockProducerClient* producer_client,
- base::OnceClosure datasource_registered_callback)
- : ProducerHost(service->perfetto_task_runner()),
- producer_name_(producer_name),
- datasource_registered_callback_(
- std::move(datasource_registered_callback)) {
- mojo::PendingRemote<mojom::ProducerClient> client;
- mojo::PendingRemote<mojom::ProducerHost> host_remote;
- auto client_receiver = client.InitWithNewPipeAndPassReceiver();
- Initialize(std::move(client), service->GetService(), producer_name_,
- static_cast<ChromeBaseSharedMemory*>(
- producer_client->shared_memory_for_testing())
- ->CloneRegion(),
- PerfettoProducer::kSMBPageSizeBytes);
- receiver_.Bind(host_remote.InitWithNewPipeAndPassReceiver());
- producer_client->BindClientAndHostPipesForTesting(std::move(client_receiver),
- std::move(host_remote));
- producer_client->SetupDataSource(data_source_name);
- }
- MockProducerHost::~MockProducerHost() = default;
- void MockProducerHost::RegisterDataSource(
- const perfetto::DataSourceDescriptor& registration_info) {
- ProducerHost::RegisterDataSource(registration_info);
- on_commit_callback_for_testing_ =
- base::BindRepeating(&MockProducerHost::OnCommit, base::Unretained(this));
- if (datasource_registered_callback_) {
- std::move(datasource_registered_callback_).Run();
- }
- }
- void MockProducerHost::OnConnect() {}
- void MockProducerHost::OnCommit(
- const perfetto::CommitDataRequest& commit_data_request) {
- if (!commit_data_request.chunks_to_patch_size() &&
- !commit_data_request.chunks_to_move_size()) {
- return;
- }
- all_host_commit_data_requests_.push_back(
- commit_data_request.SerializeAsString());
- }
- MockProducer::MockProducer(const std::string& producer_name,
- const std::string& data_source_name,
- PerfettoService* service,
- base::OnceClosure on_datasource_registered,
- base::OnceClosure on_tracing_started,
- size_t num_packets) {
- // Construct MockProducerClient before TestDataSource to avoid a race.
- //
- // TestDataSource calls AddDataSource on the global PerfettoTracedProcess,
- // which PostTasks to the threadpool in the task it will access the
- // |producer_client_| pointer that the PerfettoTracedProcess owns. However in
- // the constructor for MockProducerClient we will set the |producer_client_|
- // from the real client to the mock, however this is done on a different
- // sequence and thus we have a race. By setting the pointer before we
- // construct the data source the TestDataSource can not race.
- producer_client_ = MockProducerClient::Create(
- /* num_data_sources = */ 1, std::move(on_tracing_started));
- data_source_ = TestDataSource::CreateAndRegisterDataSource(data_source_name,
- num_packets);
- producer_host_ = std::make_unique<MockProducerHost>(
- producer_name, data_source_name, service, **producer_client_,
- std::move(on_datasource_registered));
- }
- MockProducer::~MockProducer() = default;
- void MockProducer::WritePacketBigly(base::OnceClosure on_write_complete) {
- PerfettoTracedProcess::Get()
- ->GetTaskRunner()
- ->GetOrCreateTaskRunner()
- ->PostTaskAndReply(FROM_HERE,
- base::BindOnce(&TestDataSource::WritePacketBigly,
- base::Unretained(data_source())),
- std::move(on_write_complete));
- }
- TracingUnitTest::TracingUnitTest()
- : task_environment_(std::make_unique<base::test::TaskEnvironment>(
- base::test::TaskEnvironment::MainThreadType::IO)),
- tracing_environment_(std::make_unique<base::test::TracingEnvironment>(
- *task_environment_,
- base::ThreadTaskRunnerHandle::Get(),
- PerfettoTracedProcess::Get()->perfetto_platform_for_testing())) {}
- TracingUnitTest::~TracingUnitTest() {
- CHECK(setup_called_ && teardown_called_);
- }
- void TracingUnitTest::SetUp() {
- setup_called_ = true;
- // Also tell PerfettoTracedProcess to use the current task environment.
- test_handle_ = PerfettoTracedProcess::SetupForTesting(
- base::ThreadTaskRunnerHandle::Get());
- PerfettoTracedProcess::Get()->OnThreadPoolAvailable(
- /* enable_consumer */ true);
- // Wait for any posted construction tasks to execute.
- RunUntilIdle();
- }
- void TracingUnitTest::TearDown() {
- teardown_called_ = true;
- tracing_environment_.reset();
- // Wait for any posted destruction tasks to execute.
- RunUntilIdle();
- // From here on, no more tasks should be posted.
- task_environment_.reset();
- // Clear task runner and data sources.
- PerfettoTracedProcess::Get()->GetTaskRunner()->ResetTaskRunnerForTesting(
- nullptr);
- PerfettoTracedProcess::Get()->ClearDataSourcesForTesting();
- test_handle_.reset();
- }
- } // namespace tracing
|