1 /* 2 * Copyright (C) 2017 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 <inttypes.h> 18 #include <unistd.h> 19 20 #include "gmock/gmock.h" 21 #include "gtest/gtest.h" 22 #include "perfetto/base/temp_file.h" 23 #include "perfetto/tracing/core/consumer.h" 24 #include "perfetto/tracing/core/data_source_config.h" 25 #include "perfetto/tracing/core/data_source_descriptor.h" 26 #include "perfetto/tracing/core/producer.h" 27 #include "perfetto/tracing/core/trace_config.h" 28 #include "perfetto/tracing/core/trace_packet.h" 29 #include "perfetto/tracing/core/trace_writer.h" 30 #include "perfetto/tracing/ipc/consumer_ipc_client.h" 31 #include "perfetto/tracing/ipc/producer_ipc_client.h" 32 #include "perfetto/tracing/ipc/service_ipc_host.h" 33 #include "src/base/test/test_task_runner.h" 34 #include "src/ipc/test/test_socket.h" 35 36 #include "perfetto/config/trace_config.pb.h" 37 #include "perfetto/trace/test_event.pbzero.h" 38 #include "perfetto/trace/trace.pb.h" 39 #include "perfetto/trace/trace_packet.pb.h" 40 #include "perfetto/trace/trace_packet.pbzero.h" 41 42 namespace perfetto { 43 namespace { 44 45 using testing::Invoke; 46 using testing::InvokeWithoutArgs; 47 using testing::_; 48 49 constexpr char kProducerSockName[] = TEST_SOCK_NAME("tracing_test-producer"); 50 constexpr char kConsumerSockName[] = TEST_SOCK_NAME("tracing_test-consumer"); 51 52 class MockProducer : public Producer { 53 public: 54 ~MockProducer() override {} 55 56 // Producer implementation. 57 MOCK_METHOD0(OnConnect, void()); 58 MOCK_METHOD0(OnDisconnect, void()); 59 MOCK_METHOD2(CreateDataSourceInstance, 60 void(DataSourceInstanceID, const DataSourceConfig&)); 61 MOCK_METHOD1(TearDownDataSourceInstance, void(DataSourceInstanceID)); 62 MOCK_METHOD0(uid, uid_t()); 63 MOCK_METHOD0(OnTracingSetup, void()); 64 MOCK_METHOD3(Flush, 65 void(FlushRequestID, const DataSourceInstanceID*, size_t)); 66 }; 67 68 class MockConsumer : public Consumer { 69 public: 70 ~MockConsumer() override {} 71 72 // Producer implementation. 73 MOCK_METHOD0(OnConnect, void()); 74 MOCK_METHOD0(OnDisconnect, void()); 75 MOCK_METHOD0(OnTracingDisabled, void()); 76 MOCK_METHOD2(OnTracePackets, void(std::vector<TracePacket>*, bool)); 77 78 // Workaround, gmock doesn't support yet move-only types, passing a pointer. 79 void OnTraceData(std::vector<TracePacket> packets, bool has_more) { 80 OnTracePackets(&packets, has_more); 81 } 82 }; 83 84 void CheckTraceStats(const protos::TracePacket& packet) { 85 EXPECT_TRUE(packet.has_trace_stats()); 86 EXPECT_GE(packet.trace_stats().producers_seen(), 1); 87 EXPECT_EQ(1, packet.trace_stats().producers_connected()); 88 EXPECT_EQ(1, packet.trace_stats().data_sources_registered()); 89 EXPECT_EQ(1, packet.trace_stats().tracing_sessions()); 90 EXPECT_EQ(1, packet.trace_stats().total_buffers()); 91 EXPECT_EQ(1, packet.trace_stats().buffer_stats_size()); 92 93 const auto& buf_stats = packet.trace_stats().buffer_stats(0); 94 EXPECT_GT(buf_stats.bytes_written(), 0); 95 EXPECT_GT(buf_stats.chunks_written(), 0); 96 EXPECT_EQ(0, buf_stats.chunks_overwritten()); 97 EXPECT_EQ(0, buf_stats.write_wrap_count()); 98 EXPECT_EQ(0, buf_stats.patches_failed()); 99 EXPECT_EQ(0, buf_stats.readaheads_failed()); 100 EXPECT_EQ(0, buf_stats.abi_violations()); 101 } 102 103 class TracingIntegrationTest : public ::testing::Test { 104 public: 105 void SetUp() override { 106 DESTROY_TEST_SOCK(kProducerSockName); 107 DESTROY_TEST_SOCK(kConsumerSockName); 108 task_runner_.reset(new base::TestTaskRunner()); 109 110 // Create the service host. 111 svc_ = ServiceIPCHost::CreateInstance(task_runner_.get()); 112 svc_->Start(kProducerSockName, kConsumerSockName); 113 114 // Create and connect a Producer. 115 producer_endpoint_ = ProducerIPCClient::Connect( 116 kProducerSockName, &producer_, "perfetto.mock_producer", 117 task_runner_.get()); 118 auto on_producer_connect = 119 task_runner_->CreateCheckpoint("on_producer_connect"); 120 EXPECT_CALL(producer_, OnConnect()).WillOnce(Invoke(on_producer_connect)); 121 task_runner_->RunUntilCheckpoint("on_producer_connect"); 122 123 // Register a data source. 124 DataSourceDescriptor ds_desc; 125 ds_desc.set_name("perfetto.test"); 126 producer_endpoint_->RegisterDataSource(ds_desc); 127 128 // Create and connect a Consumer. 129 consumer_endpoint_ = ConsumerIPCClient::Connect( 130 kConsumerSockName, &consumer_, task_runner_.get()); 131 auto on_consumer_connect = 132 task_runner_->CreateCheckpoint("on_consumer_connect"); 133 EXPECT_CALL(consumer_, OnConnect()).WillOnce(Invoke(on_consumer_connect)); 134 task_runner_->RunUntilCheckpoint("on_consumer_connect"); 135 136 ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&producer_)); 137 ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&consumer_)); 138 } 139 140 void TearDown() override { 141 // Destroy the service and check that both Producer and Consumer see an 142 // OnDisconnect() call. 143 144 auto on_producer_disconnect = 145 task_runner_->CreateCheckpoint("on_producer_disconnect"); 146 EXPECT_CALL(producer_, OnDisconnect()) 147 .WillOnce(Invoke(on_producer_disconnect)); 148 149 auto on_consumer_disconnect = 150 task_runner_->CreateCheckpoint("on_consumer_disconnect"); 151 EXPECT_CALL(consumer_, OnDisconnect()) 152 .WillOnce(Invoke(on_consumer_disconnect)); 153 154 svc_.reset(); 155 task_runner_->RunUntilCheckpoint("on_producer_disconnect"); 156 task_runner_->RunUntilCheckpoint("on_consumer_disconnect"); 157 158 ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&producer_)); 159 ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(&consumer_)); 160 161 task_runner_.reset(); 162 DESTROY_TEST_SOCK(kProducerSockName); 163 DESTROY_TEST_SOCK(kConsumerSockName); 164 } 165 166 std::unique_ptr<base::TestTaskRunner> task_runner_; 167 std::unique_ptr<ServiceIPCHost> svc_; 168 std::unique_ptr<Service::ProducerEndpoint> producer_endpoint_; 169 MockProducer producer_; 170 std::unique_ptr<Service::ConsumerEndpoint> consumer_endpoint_; 171 MockConsumer consumer_; 172 }; 173 174 TEST_F(TracingIntegrationTest, WithIPCTransport) { 175 // Start tracing. 176 TraceConfig trace_config; 177 trace_config.add_buffers()->set_size_kb(4096 * 10); 178 auto* ds_config = trace_config.add_data_sources()->mutable_config(); 179 ds_config->set_name("perfetto.test"); 180 ds_config->set_target_buffer(0); 181 consumer_endpoint_->EnableTracing(trace_config); 182 183 // At this point, the Producer should be asked to turn its data source on. 184 DataSourceInstanceID ds_iid = 0; 185 186 BufferID global_buf_id = 0; 187 auto on_create_ds_instance = 188 task_runner_->CreateCheckpoint("on_create_ds_instance"); 189 EXPECT_CALL(producer_, OnTracingSetup()); 190 EXPECT_CALL(producer_, CreateDataSourceInstance(_, _)) 191 .WillOnce( 192 Invoke([on_create_ds_instance, &ds_iid, &global_buf_id]( 193 DataSourceInstanceID id, const DataSourceConfig& cfg) { 194 ASSERT_NE(0u, id); 195 ds_iid = id; 196 ASSERT_EQ("perfetto.test", cfg.name()); 197 global_buf_id = static_cast<BufferID>(cfg.target_buffer()); 198 ASSERT_NE(0u, global_buf_id); 199 ASSERT_LE(global_buf_id, std::numeric_limits<BufferID>::max()); 200 on_create_ds_instance(); 201 })); 202 task_runner_->RunUntilCheckpoint("on_create_ds_instance"); 203 204 // Now let the data source fill some pages within the same task. 205 // Doing so should accumulate a bunch of chunks that will be notified by the 206 // a future task in one batch. 207 std::unique_ptr<TraceWriter> writer = 208 producer_endpoint_->CreateTraceWriter(global_buf_id); 209 ASSERT_TRUE(writer); 210 211 const size_t kNumPackets = 10; 212 for (size_t i = 0; i < kNumPackets; i++) { 213 char buf[16]; 214 sprintf(buf, "evt_%zu", i); 215 writer->NewTracePacket()->set_for_testing()->set_str(buf, strlen(buf)); 216 } 217 218 // Allow the service to see the CommitData() before reading back. 219 auto on_data_committed = task_runner_->CreateCheckpoint("on_data_committed"); 220 writer->Flush(on_data_committed); 221 task_runner_->RunUntilCheckpoint("on_data_committed"); 222 223 // Read the log buffer. 224 consumer_endpoint_->ReadBuffers(); 225 size_t num_pack_rx = 0; 226 bool saw_clock_snapshot = false; 227 bool saw_trace_config = false; 228 bool saw_trace_stats = false; 229 auto all_packets_rx = task_runner_->CreateCheckpoint("all_packets_rx"); 230 EXPECT_CALL(consumer_, OnTracePackets(_, _)) 231 .WillRepeatedly( 232 Invoke([&num_pack_rx, all_packets_rx, &trace_config, 233 &saw_clock_snapshot, &saw_trace_config, &saw_trace_stats]( 234 std::vector<TracePacket>* packets, bool has_more) { 235 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX) 236 const int kExpectedMinNumberOfClocks = 1; 237 #else 238 const int kExpectedMinNumberOfClocks = 6; 239 #endif 240 241 for (auto& encoded_packet : *packets) { 242 protos::TracePacket packet; 243 ASSERT_TRUE(encoded_packet.Decode(&packet)); 244 if (packet.has_for_testing()) { 245 char buf[8]; 246 sprintf(buf, "evt_%zu", num_pack_rx++); 247 EXPECT_EQ(std::string(buf), packet.for_testing().str()); 248 } else if (packet.has_clock_snapshot()) { 249 EXPECT_GE(packet.clock_snapshot().clocks_size(), 250 kExpectedMinNumberOfClocks); 251 saw_clock_snapshot = true; 252 } else if (packet.has_trace_config()) { 253 protos::TraceConfig config_proto; 254 trace_config.ToProto(&config_proto); 255 Slice expected_slice = Slice::Allocate( 256 static_cast<size_t>(config_proto.ByteSize())); 257 config_proto.SerializeWithCachedSizesToArray( 258 expected_slice.own_data()); 259 Slice actual_slice = Slice::Allocate( 260 static_cast<size_t>(packet.trace_config().ByteSize())); 261 packet.trace_config().SerializeWithCachedSizesToArray( 262 actual_slice.own_data()); 263 EXPECT_EQ(std::string(reinterpret_cast<const char*>( 264 expected_slice.own_data()), 265 expected_slice.size), 266 std::string(reinterpret_cast<const char*>( 267 actual_slice.own_data()), 268 actual_slice.size)); 269 saw_trace_config = true; 270 } else if (packet.has_trace_stats()) { 271 saw_trace_stats = true; 272 CheckTraceStats(packet); 273 } 274 } 275 if (!has_more) 276 all_packets_rx(); 277 })); 278 task_runner_->RunUntilCheckpoint("all_packets_rx"); 279 ASSERT_EQ(kNumPackets, num_pack_rx); 280 EXPECT_TRUE(saw_clock_snapshot); 281 EXPECT_TRUE(saw_trace_config); 282 EXPECT_TRUE(saw_trace_stats); 283 284 // Disable tracing. 285 consumer_endpoint_->DisableTracing(); 286 287 auto on_tracing_disabled = 288 task_runner_->CreateCheckpoint("on_tracing_disabled"); 289 EXPECT_CALL(producer_, TearDownDataSourceInstance(_)); 290 EXPECT_CALL(consumer_, OnTracingDisabled()) 291 .WillOnce(Invoke(on_tracing_disabled)); 292 task_runner_->RunUntilCheckpoint("on_tracing_disabled"); 293 } 294 295 TEST_F(TracingIntegrationTest, WriteIntoFile) { 296 // Start tracing. 297 TraceConfig trace_config; 298 trace_config.add_buffers()->set_size_kb(4096 * 10); 299 auto* ds_config = trace_config.add_data_sources()->mutable_config(); 300 ds_config->set_name("perfetto.test"); 301 ds_config->set_target_buffer(0); 302 trace_config.set_write_into_file(true); 303 base::TempFile tmp_file = base::TempFile::CreateUnlinked(); 304 consumer_endpoint_->EnableTracing(trace_config, 305 base::ScopedFile(dup(tmp_file.fd()))); 306 307 // At this point, the producer_ should be asked to turn its data source on. 308 BufferID global_buf_id = 0; 309 auto on_create_ds_instance = 310 task_runner_->CreateCheckpoint("on_create_ds_instance"); 311 EXPECT_CALL(producer_, OnTracingSetup()); 312 EXPECT_CALL(producer_, CreateDataSourceInstance(_, _)) 313 .WillOnce(Invoke([on_create_ds_instance, &global_buf_id]( 314 DataSourceInstanceID, const DataSourceConfig& cfg) { 315 global_buf_id = static_cast<BufferID>(cfg.target_buffer()); 316 on_create_ds_instance(); 317 })); 318 task_runner_->RunUntilCheckpoint("on_create_ds_instance"); 319 320 std::unique_ptr<TraceWriter> writer = 321 producer_endpoint_->CreateTraceWriter(global_buf_id); 322 ASSERT_TRUE(writer); 323 324 const size_t kNumPackets = 10; 325 for (size_t i = 0; i < kNumPackets; i++) { 326 char buf[16]; 327 sprintf(buf, "evt_%zu", i); 328 writer->NewTracePacket()->set_for_testing()->set_str(buf, strlen(buf)); 329 } 330 auto on_data_committed = task_runner_->CreateCheckpoint("on_data_committed"); 331 writer->Flush(on_data_committed); 332 task_runner_->RunUntilCheckpoint("on_data_committed"); 333 334 // Will disable tracing and will force the buffers to be written into the 335 // file before destroying them. 336 consumer_endpoint_->FreeBuffers(); 337 338 auto on_tracing_disabled = 339 task_runner_->CreateCheckpoint("on_tracing_disabled"); 340 EXPECT_CALL(producer_, TearDownDataSourceInstance(_)); 341 EXPECT_CALL(consumer_, OnTracingDisabled()) 342 .WillOnce(Invoke(on_tracing_disabled)); 343 task_runner_->RunUntilCheckpoint("on_tracing_disabled"); 344 345 // Check that |tmp_file| contains a valid trace.proto message. 346 ASSERT_EQ(0, lseek(tmp_file.fd(), 0, SEEK_SET)); 347 char tmp_buf[1024]; 348 ssize_t rsize = read(tmp_file.fd(), tmp_buf, sizeof(tmp_buf)); 349 ASSERT_GT(rsize, 0); 350 protos::Trace tmp_trace; 351 ASSERT_TRUE(tmp_trace.ParseFromArray(tmp_buf, static_cast<int>(rsize))); 352 size_t num_test_packet = 0; 353 bool saw_trace_stats = false; 354 for (int i = 0; i < tmp_trace.packet_size(); i++) { 355 const protos::TracePacket& packet = tmp_trace.packet(i); 356 if (packet.has_for_testing()) { 357 ASSERT_EQ("evt_" + std::to_string(num_test_packet++), 358 packet.for_testing().str()); 359 } else if (packet.has_trace_stats()) { 360 saw_trace_stats = true; 361 CheckTraceStats(packet); 362 } 363 } 364 ASSERT_TRUE(saw_trace_stats); 365 } 366 367 // TODO(primiano): add tests to cover: 368 // - unknown fields preserved end-to-end. 369 // - >1 data source. 370 // - >1 data consumer sharing the same data source, with different TraceBuffers. 371 // - >1 consumer with > 1 buffer each. 372 // - Consumer disconnecting in the middle of a ReadBuffers() call. 373 // - Multiple calls to DisableTracing. 374 // - Out of order Enable/Disable/FreeBuffers calls. 375 // - DisableTracing does actually freeze the buffers. 376 377 } // namespace 378 } // namespace perfetto 379