blob: e5652ab94619dbe91b08c0b1d532ce6464084ec4 [file] [log] [blame]
Eric Secklerc65693d2019-01-11 15:12:48 +00001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/tracing/core/startup_trace_writer.h"
18
19#include "gtest/gtest.h"
Eric Seckler42777e52019-01-23 10:13:22 +000020#include "perfetto/tracing/core/startup_trace_writer_registry.h"
21#include "perfetto/tracing/core/trace_packet.h"
Eric Secklerc65693d2019-01-11 15:12:48 +000022#include "perfetto/tracing/core/tracing_service.h"
23#include "src/base/test/test_task_runner.h"
24#include "src/tracing/core/shared_memory_arbiter_impl.h"
Eric Seckler42777e52019-01-23 10:13:22 +000025#include "src/tracing/core/sliced_protobuf_input_stream.h"
26#include "src/tracing/core/trace_buffer.h"
Eric Secklerc65693d2019-01-11 15:12:48 +000027#include "src/tracing/test/aligned_buffer_test.h"
28#include "src/tracing/test/fake_producer_endpoint.h"
29
30#include "perfetto/trace/test_event.pbzero.h"
Eric Seckler42777e52019-01-23 10:13:22 +000031#include "perfetto/trace/trace_packet.pb.h"
Eric Secklerc65693d2019-01-11 15:12:48 +000032#include "perfetto/trace/trace_packet.pbzero.h"
33
34namespace perfetto {
Eric Secklerc65693d2019-01-11 15:12:48 +000035
36class StartupTraceWriterTest : public AlignedBufferTest {
37 public:
38 void SetUp() override {
39 SharedMemoryArbiterImpl::set_default_layout_for_testing(
40 SharedMemoryABI::PageLayout::kPageDiv4);
41 AlignedBufferTest::SetUp();
42 task_runner_.reset(new base::TestTaskRunner());
43 arbiter_.reset(new SharedMemoryArbiterImpl(buf(), buf_size(), page_size(),
44 &fake_producer_endpoint_,
45 task_runner_.get()));
46 }
47
48 void TearDown() override {
49 arbiter_.reset();
50 task_runner_.reset();
51 }
52
Eric Seckler42777e52019-01-23 10:13:22 +000053 std::unique_ptr<StartupTraceWriter> CreateUnboundWriter() {
54 std::shared_ptr<StartupTraceWriterRegistryHandle> registry;
55 return std::unique_ptr<StartupTraceWriter>(
56 new StartupTraceWriter(registry));
57 }
58
59 bool BindWriter(StartupTraceWriter* writer) {
60 const BufferID kBufId = 42;
61 return writer->BindToArbiter(arbiter_.get(), kBufId);
62 }
63
Eric Secklerc65693d2019-01-11 15:12:48 +000064 void WritePackets(StartupTraceWriter* writer, size_t packet_count) {
65 for (size_t i = 0; i < packet_count; i++) {
66 auto packet = writer->NewTracePacket();
Eric Seckler42777e52019-01-23 10:13:22 +000067 packet->set_for_testing()->set_str(kPacketPayload);
Eric Secklerc65693d2019-01-11 15:12:48 +000068 }
69 }
70
Eric Seckler42777e52019-01-23 10:13:22 +000071 void VerifyPackets(size_t expected_count) {
Eric Secklerc65693d2019-01-11 15:12:48 +000072 SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
Eric Seckler42777e52019-01-23 10:13:22 +000073 auto buffer = TraceBuffer::Create(abi->size());
74
75 size_t total_packets_count = 0;
Eric Secklerc65693d2019-01-11 15:12:48 +000076 ChunkID current_max_chunk_id = 0;
77 for (size_t page_idx = 0; page_idx < kNumPages; page_idx++) {
78 uint32_t page_layout = abi->GetPageLayout(page_idx);
79 size_t num_chunks = SharedMemoryABI::GetNumChunksForLayout(page_layout);
80 for (size_t chunk_idx = 0; chunk_idx < num_chunks; chunk_idx++) {
81 auto chunk_state = abi->GetChunkState(page_idx, chunk_idx);
82 ASSERT_TRUE(chunk_state == SharedMemoryABI::kChunkFree ||
83 chunk_state == SharedMemoryABI::kChunkComplete);
84 auto chunk = abi->TryAcquireChunkForReading(page_idx, chunk_idx);
85 if (!chunk.is_valid())
86 continue;
87
88 // Should only see new chunks with IDs larger than the previous read
89 // since our reads and writes are serialized.
90 ChunkID chunk_id = chunk.header()->chunk_id.load();
Eric Seckler4a0ee4e2019-01-15 08:37:46 +000091 if (last_read_max_chunk_id_ != 0) {
Eric Secklerc65693d2019-01-11 15:12:48 +000092 EXPECT_LT(last_read_max_chunk_id_, chunk_id);
Eric Seckler4a0ee4e2019-01-15 08:37:46 +000093 }
Eric Secklerc65693d2019-01-11 15:12:48 +000094 current_max_chunk_id = std::max(current_max_chunk_id, chunk_id);
95
96 auto packets_header = chunk.header()->packets.load();
Eric Seckler42777e52019-01-23 10:13:22 +000097 total_packets_count += packets_header.count;
Eric Secklerc65693d2019-01-11 15:12:48 +000098 if (packets_header.flags &
99 SharedMemoryABI::ChunkHeader::kFirstPacketContinuesFromPrevChunk) {
100 // Don't count fragmented packets twice.
Eric Seckler42777e52019-01-23 10:13:22 +0000101 total_packets_count--;
Eric Secklerc65693d2019-01-11 15:12:48 +0000102 }
Eric Seckler42777e52019-01-23 10:13:22 +0000103
104 buffer->CopyChunkUntrusted(
105 /*producer_id_trusted=*/1, /*producer_uid_trusted=*/1,
106 chunk.header()->writer_id.load(), chunk_id, packets_header.count,
107 packets_header.flags, /*chunk_complete=*/true,
108 chunk.payload_begin(), chunk.payload_size());
Eric Secklerc65693d2019-01-11 15:12:48 +0000109 abi->ReleaseChunkAsFree(std::move(chunk));
110 }
111 }
112 last_read_max_chunk_id_ = current_max_chunk_id;
Eric Seckler42777e52019-01-23 10:13:22 +0000113 EXPECT_EQ(expected_count, total_packets_count);
114
115 // Now verify chunk and packet contents.
116 buffer->BeginRead();
117 size_t num_packets_read = 0;
118 while (true) {
119 TracePacket packet;
Eric Secklerd0ac7ca2019-02-06 09:13:45 +0000120 TraceBuffer::PacketSequenceProperties sequence_properties{};
121 if (!buffer->ReadNextTracePacket(&packet, &sequence_properties))
Eric Seckler42777e52019-01-23 10:13:22 +0000122 break;
Eric Secklerd0ac7ca2019-02-06 09:13:45 +0000123 EXPECT_EQ(static_cast<uid_t>(1),
124 sequence_properties.producer_uid_trusted);
Eric Seckler42777e52019-01-23 10:13:22 +0000125
126 SlicedProtobufInputStream stream(&packet.slices());
127 size_t size = 0;
128 for (const Slice& slice : packet.slices())
129 size += slice.size;
130 protos::TracePacket parsed_packet;
131 bool success = parsed_packet.ParseFromBoundedZeroCopyStream(
132 &stream, static_cast<int>(size));
133 EXPECT_TRUE(success);
134 if (!success)
135 break;
136 EXPECT_TRUE(parsed_packet.has_for_testing());
137 EXPECT_EQ(kPacketPayload, parsed_packet.for_testing().str());
138 num_packets_read++;
139 }
140 EXPECT_EQ(expected_count, num_packets_read);
Eric Secklerc65693d2019-01-11 15:12:48 +0000141 }
142
Eric Seckler42777e52019-01-23 10:13:22 +0000143 size_t GetUnboundWriterCount(
144 const StartupTraceWriterRegistry& registry) const {
145 return registry.unbound_writers_.size() +
146 registry.unbound_owned_writers_.size();
147 }
148
149 size_t GetBindingRegistriesCount(
150 const SharedMemoryArbiterImpl& arbiter) const {
151 return arbiter.startup_trace_writer_registries_.size();
152 }
153
154 size_t GetUnboundWriterCount(const SharedMemoryArbiterImpl& arbiter) const {
155 size_t count = 0u;
156 for (const auto& reg : arbiter.startup_trace_writer_registries_) {
157 count += reg->unbound_writers_.size();
158 count += reg->unbound_owned_writers_.size();
159 }
160 return count;
161 }
162
163 protected:
164 static constexpr char kPacketPayload[] = "foo";
165
Eric Secklerc65693d2019-01-11 15:12:48 +0000166 FakeProducerEndpoint fake_producer_endpoint_;
167 std::unique_ptr<base::TestTaskRunner> task_runner_;
168 std::unique_ptr<SharedMemoryArbiterImpl> arbiter_;
169 std::function<void(const std::vector<uint32_t>&)> on_pages_complete_;
170
171 ChunkID last_read_max_chunk_id_ = 0;
172};
173
Eric Seckler42777e52019-01-23 10:13:22 +0000174constexpr char StartupTraceWriterTest::kPacketPayload[];
175
176namespace {
177
Eric Secklerc65693d2019-01-11 15:12:48 +0000178size_t const kPageSizes[] = {4096, 65536};
179INSTANTIATE_TEST_CASE_P(PageSize,
180 StartupTraceWriterTest,
181 ::testing::ValuesIn(kPageSizes));
182
183TEST_P(StartupTraceWriterTest, CreateUnboundAndBind) {
Eric Seckler42777e52019-01-23 10:13:22 +0000184 auto writer = CreateUnboundWriter();
Eric Secklerc65693d2019-01-11 15:12:48 +0000185
Eric Seckler42777e52019-01-23 10:13:22 +0000186 // Bind writer right away without having written any data before.
187 EXPECT_TRUE(BindWriter(writer.get()));
Eric Secklerc65693d2019-01-11 15:12:48 +0000188
189 const size_t kNumPackets = 32;
190 WritePackets(writer.get(), kNumPackets);
191 // Finalizes the last packet and returns the chunk.
192 writer.reset();
193
Eric Seckler42777e52019-01-23 10:13:22 +0000194 VerifyPackets(kNumPackets);
Eric Secklerc65693d2019-01-11 15:12:48 +0000195}
196
197TEST_P(StartupTraceWriterTest, CreateBound) {
198 // Create a bound writer immediately.
199 const BufferID kBufId = 42;
200 std::unique_ptr<StartupTraceWriter> writer(
201 new StartupTraceWriter(arbiter_->CreateTraceWriter(kBufId)));
202
203 const size_t kNumPackets = 32;
204 WritePackets(writer.get(), kNumPackets);
205 // Finalizes the last packet and returns the chunk.
206 writer.reset();
207
Eric Seckler42777e52019-01-23 10:13:22 +0000208 VerifyPackets(kNumPackets);
Eric Secklerc65693d2019-01-11 15:12:48 +0000209}
210
211TEST_P(StartupTraceWriterTest, WriteWhileUnboundAndDiscard) {
Eric Seckler42777e52019-01-23 10:13:22 +0000212 auto writer = CreateUnboundWriter();
Eric Secklerc65693d2019-01-11 15:12:48 +0000213
214 const size_t kNumPackets = 32;
215 WritePackets(writer.get(), kNumPackets);
216
217 // Should discard the written data.
218 writer.reset();
219
Eric Seckler42777e52019-01-23 10:13:22 +0000220 VerifyPackets(0);
Eric Secklerc65693d2019-01-11 15:12:48 +0000221}
222
223TEST_P(StartupTraceWriterTest, WriteWhileUnboundAndBind) {
Eric Seckler42777e52019-01-23 10:13:22 +0000224 auto writer = CreateUnboundWriter();
Eric Secklerc65693d2019-01-11 15:12:48 +0000225
226 const size_t kNumPackets = 32;
227 WritePackets(writer.get(), kNumPackets);
228
229 // Binding the writer should cause the previously written packets to be
230 // written to the SMB and committed.
Eric Seckler42777e52019-01-23 10:13:22 +0000231 EXPECT_TRUE(BindWriter(writer.get()));
Eric Secklerc65693d2019-01-11 15:12:48 +0000232
Eric Seckler42777e52019-01-23 10:13:22 +0000233 VerifyPackets(kNumPackets);
Eric Secklerc65693d2019-01-11 15:12:48 +0000234
235 // Any further packets should be written to the SMB directly.
236 const size_t kNumAdditionalPackets = 16;
237 WritePackets(writer.get(), kNumAdditionalPackets);
238 // Finalizes the last packet and returns the chunk.
239 writer.reset();
240
Eric Seckler42777e52019-01-23 10:13:22 +0000241 VerifyPackets(kNumAdditionalPackets);
Eric Secklerc65693d2019-01-11 15:12:48 +0000242}
243
244TEST_P(StartupTraceWriterTest, WriteMultipleChunksWhileUnboundAndBind) {
Eric Seckler42777e52019-01-23 10:13:22 +0000245 auto writer = CreateUnboundWriter();
Eric Secklerc65693d2019-01-11 15:12:48 +0000246
247 // Write a single packet to determine its size in the buffer.
248 WritePackets(writer.get(), 1);
249 size_t packet_size = writer->used_buffer_size();
250
251 // Write at least 3 pages worth of packets.
252 const size_t kNumPackets = (page_size() * 3 + packet_size - 1) / packet_size;
253 WritePackets(writer.get(), kNumPackets);
254
255 // Binding the writer should cause the previously written packets to be
256 // written to the SMB and committed.
Eric Seckler42777e52019-01-23 10:13:22 +0000257 EXPECT_TRUE(BindWriter(writer.get()));
Eric Secklerc65693d2019-01-11 15:12:48 +0000258
Eric Seckler42777e52019-01-23 10:13:22 +0000259 VerifyPackets(kNumPackets + 1);
Eric Secklerc65693d2019-01-11 15:12:48 +0000260
261 // Any further packets should be written to the SMB directly.
262 const size_t kNumAdditionalPackets = 16;
263 WritePackets(writer.get(), kNumAdditionalPackets);
264 // Finalizes the last packet and returns the chunk.
265 writer.reset();
266
Eric Seckler42777e52019-01-23 10:13:22 +0000267 VerifyPackets(kNumAdditionalPackets);
Eric Secklerc65693d2019-01-11 15:12:48 +0000268}
269
270TEST_P(StartupTraceWriterTest, BindingWhileWritingFails) {
Eric Seckler42777e52019-01-23 10:13:22 +0000271 auto writer = CreateUnboundWriter();
Eric Secklerc65693d2019-01-11 15:12:48 +0000272
Eric Secklerc65693d2019-01-11 15:12:48 +0000273 {
Eric Seckler42777e52019-01-23 10:13:22 +0000274 // Begin a write by opening a TracePacket.
Eric Secklerc65693d2019-01-11 15:12:48 +0000275 auto packet = writer->NewTracePacket();
Eric Seckler42777e52019-01-23 10:13:22 +0000276 packet->set_for_testing()->set_str(kPacketPayload);
Eric Secklerc65693d2019-01-11 15:12:48 +0000277
278 // Binding while writing should fail.
Eric Seckler42777e52019-01-23 10:13:22 +0000279 EXPECT_FALSE(BindWriter(writer.get()));
Eric Secklerc65693d2019-01-11 15:12:48 +0000280 }
281
282 // Packet was completed, so binding should work now and emit the packet.
Eric Seckler42777e52019-01-23 10:13:22 +0000283 EXPECT_TRUE(BindWriter(writer.get()));
284 VerifyPackets(1);
285}
286
287TEST_P(StartupTraceWriterTest, CreateAndBindViaRegistry) {
288 std::unique_ptr<StartupTraceWriterRegistry> registry(
289 new StartupTraceWriterRegistry());
290
291 // Create unbound writers.
292 auto writer1 = registry->CreateUnboundTraceWriter();
293 auto writer2 = registry->CreateUnboundTraceWriter();
294
295 EXPECT_EQ(2u, GetUnboundWriterCount(*registry));
296
297 // Return |writer2|. It should be kept alive until the registry is bound.
298 registry->ReturnUnboundTraceWriter(std::move(writer2));
299
300 {
301 // Begin a write by opening a TracePacket on |writer1|.
302 auto packet = writer1->NewTracePacket();
303
304 // Binding |writer1| writing should fail, but |writer2| should be bound.
305 const BufferID kBufId = 42;
306 arbiter_->BindStartupTraceWriterRegistry(std::move(registry), kBufId);
307 EXPECT_EQ(1u, GetUnboundWriterCount(*arbiter_));
308 }
309
310 // Wait for |writer1| to be bound and the registry to be deleted.
311 auto checkpoint_name = "all_bound";
312 auto all_bound = task_runner_->CreateCheckpoint(checkpoint_name);
313 std::function<void()> task;
314 task = [&task, &all_bound, this]() {
315 if (!GetBindingRegistriesCount(*arbiter_)) {
316 all_bound();
317 return;
318 }
319 task_runner_->PostDelayedTask(task, 1);
320 };
321 task_runner_->PostDelayedTask(task, 1);
322 task_runner_->RunUntilCheckpoint(checkpoint_name);
Eric Secklerc65693d2019-01-11 15:12:48 +0000323}
324
325} // namespace
326} // namespace perfetto