blob: 57f9cae98291c7030d41cc8ebc577a912a0f42f1 [file] [log] [blame]
// Copyright (C) 2018 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 <gtest/gtest.h>
#include <random>
#include "benchmark/benchmark.h"
#include "perfetto/base/time.h"
#include "perfetto/trace/trace_packet.pb.h"
#include "perfetto/trace/trace_packet.pbzero.h"
#include "perfetto/traced/traced.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
#include "src/base/test/test_task_runner.h"
#include "test/fake_consumer.h"
#include "test/task_runner_thread.h"
#include "test/task_runner_thread_delegates.h"
namespace perfetto {
// If we're building on Android and starting the daemons ourselves,
// create the sockets in a world-writable location.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
#define TEST_PRODUCER_SOCK_NAME "/data/local/tmp/traced_producer"
#define TEST_CONSUMER_SOCK_NAME "/data/local/tmp/traced_consumer"
#else
#define TEST_PRODUCER_SOCK_NAME PERFETTO_PRODUCER_SOCK_NAME
#define TEST_CONSUMER_SOCK_NAME PERFETTO_CONSUMER_SOCK_NAME
#endif
static void BM_EndToEnd(benchmark::State& state) {
base::TestTaskRunner task_runner;
#if PERFETTO_BUILDFLAG(PERFETTO_START_DAEMONS)
TaskRunnerThread service_thread("perfetto.svc");
service_thread.Start(std::unique_ptr<ServiceDelegate>(
new ServiceDelegate(TEST_PRODUCER_SOCK_NAME, TEST_CONSUMER_SOCK_NAME)));
#endif
TaskRunnerThread producer_thread("perfetto.prd");
auto on_producer_enabled = task_runner.CreateCheckpoint("producer.enabled");
auto posted_on_producer_enabled = [&task_runner, &on_producer_enabled] {
task_runner.PostTask(on_producer_enabled);
};
std::unique_ptr<FakeProducerDelegate> producer_delegate(
new FakeProducerDelegate(TEST_PRODUCER_SOCK_NAME,
posted_on_producer_enabled));
FakeProducerDelegate* producer_delegate_cached = producer_delegate.get();
producer_thread.Start(std::move(producer_delegate));
// Setup the TraceConfig for the consumer.
TraceConfig trace_config;
trace_config.add_buffers()->set_size_kb(512);
// Create the buffer for ftrace.
auto* ds_config = trace_config.add_data_sources()->mutable_config();
ds_config->set_name("android.perfetto.FakeProducer");
ds_config->set_target_buffer(0);
// The parameters for the producer.
static constexpr uint32_t kRandomSeed = 42;
uint32_t message_count = state.range(0);
uint32_t message_size = state.range(1);
// Setup the test to use a random number generator.
ds_config->mutable_for_testing()->set_seed(kRandomSeed);
ds_config->mutable_for_testing()->set_message_count(message_count);
ds_config->mutable_for_testing()->set_message_size(message_size);
bool is_first_packet = true;
auto on_readback_complete = task_runner.CreateCheckpoint("readback.complete");
std::minstd_rand0 rnd_engine(kRandomSeed);
auto on_consumer_data = [&is_first_packet, &on_readback_complete,
&rnd_engine](std::vector<TracePacket> packets,
bool has_more) {
for (auto& packet : packets) {
ASSERT_TRUE(packet.Decode());
ASSERT_TRUE(packet->has_for_testing() || packet->has_clock_snapshot());
if (packet->has_clock_snapshot()) {
continue;
}
ASSERT_EQ(protos::TracePacket::kTrustedUid,
packet->optional_trusted_uid_case());
if (is_first_packet) {
rnd_engine = std::minstd_rand0(packet->for_testing().seq_value());
is_first_packet = false;
} else {
ASSERT_EQ(packet->for_testing().seq_value(), rnd_engine());
}
}
if (!has_more) {
is_first_packet = true;
on_readback_complete();
}
};
// Finally, make the consumer connect to the service.
auto on_connect = task_runner.CreateCheckpoint("consumer.connected");
FakeConsumer consumer(trace_config, std::move(on_connect),
std::move(on_consumer_data), &task_runner);
consumer.Connect(TEST_CONSUMER_SOCK_NAME);
task_runner.RunUntilCheckpoint("consumer.connected");
consumer.EnableTracing();
task_runner.RunUntilCheckpoint("producer.enabled");
uint64_t wall_start_ns = base::GetWallTimeNs().count();
uint64_t thread_start_ns = service_thread.GetThreadCPUTimeNs();
uint64_t iterations = 0;
for (auto _ : state) {
auto cname = "produced.and.committed." + std::to_string(iterations++);
auto on_produced_and_committed = task_runner.CreateCheckpoint(cname);
auto posted_on_produced_and_committed = [&task_runner,
&on_produced_and_committed] {
task_runner.PostTask(on_produced_and_committed);
};
FakeProducer* producer = producer_delegate_cached->producer();
producer->ProduceEventBatch(posted_on_produced_and_committed);
task_runner.RunUntilCheckpoint(cname);
}
uint64_t thread_ns = service_thread.GetThreadCPUTimeNs() - thread_start_ns;
uint64_t wall_ns = base::GetWallTimeNs().count() - wall_start_ns;
state.counters["Ser CPU"] = benchmark::Counter(100.0 * thread_ns / wall_ns);
state.counters["Ser ns/m"] =
benchmark::Counter(1.0 * thread_ns / message_count);
// Read back the buffer just to check correctness.
consumer.ReadTraceData();
task_runner.RunUntilCheckpoint("readback.complete");
state.SetBytesProcessed(int64_t(state.iterations()) * message_size *
message_count);
consumer.Disconnect();
}
BENCHMARK(BM_EndToEnd)
->Unit(benchmark::kMicrosecond)
->UseRealTime()
->RangeMultiplier(2)
->Ranges({{16, 1024 * 1024}, {8, 2048}});
}