tracing_service_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <memory>
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/files/file_util.h"
  8. #include "base/json/json_reader.h"
  9. #include "base/run_loop.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/test/bind.h"
  12. #include "base/test/test_simple_task_runner.h"
  13. #include "base/threading/thread.h"
  14. #include "base/threading/thread_restrictions.h"
  15. #include "base/trace_event/trace_config.h"
  16. #include "build/build_config.h"
  17. #include "mojo/public/cpp/bindings/receiver.h"
  18. #include "mojo/public/cpp/bindings/remote.h"
  19. #include "services/tracing/perfetto/test_utils.h"
  20. #include "services/tracing/public/cpp/perfetto/perfetto_config.h"
  21. #include "services/tracing/public/cpp/perfetto/perfetto_traced_process.h"
  22. #include "services/tracing/public/cpp/perfetto/trace_packet_tokenizer.h"
  23. #include "services/tracing/public/cpp/traced_process_impl.h"
  24. #include "services/tracing/public/mojom/perfetto_service.mojom.h"
  25. #include "services/tracing/public/mojom/traced_process.mojom.h"
  26. #include "services/tracing/public/mojom/tracing_service.mojom.h"
  27. #include "services/tracing/tracing_service.h"
  28. #include "testing/gtest/include/gtest/gtest.h"
  29. #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h"
  30. #include "third_party/perfetto/include/perfetto/tracing/data_source.h"
  31. #include "third_party/perfetto/include/perfetto/tracing/tracing.h"
  32. #include "third_party/perfetto/protos/perfetto/common/trace_stats.pb.h"
  33. #include "third_party/perfetto/protos/perfetto/trace/test_event.pbzero.h"
  34. #include "third_party/perfetto/protos/perfetto/trace/trace.pb.h"
  35. #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
  36. #include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
  37. namespace tracing {
  38. class TracingServiceTest : public TracingUnitTest {
  39. public:
  40. TracingServiceTest() : service_(&perfetto_service_) {}
  41. TracingServiceTest(const TracingServiceTest&) = delete;
  42. TracingServiceTest& operator=(const TracingServiceTest&) = delete;
  43. void SetUp() override {
  44. TracingUnitTest::SetUp();
  45. perfetto_service()->SetActiveServicePidsInitialized();
  46. }
  47. void TearDown() override { TracingUnitTest::TearDown(); }
  48. protected:
  49. PerfettoService* perfetto_service() { return &perfetto_service_; }
  50. mojom::TracingService* service() { return &service_; }
  51. void EnableClientApiConsumer() {
  52. // Tell PerfettoTracedProcess how to connect to the service. This enables
  53. // the consumer part of the client API.
  54. static mojom::TracingService* s_service;
  55. s_service = service();
  56. auto factory = []() -> mojom::TracingService& { return *s_service; };
  57. PerfettoTracedProcess::Get()->SetConsumerConnectionFactory(
  58. factory, base::SequencedTaskRunnerHandle::Get());
  59. }
  60. void EnableClientApiProducer() {
  61. // Connect the producer part of the client API. AddClient() will end up
  62. // calling TracedProcessImpl::ConnectToTracingService(), which will in turn
  63. // route the PerfettoService interface to the client API backend.
  64. mojo::PendingRemote<tracing::mojom::TracedProcess> traced_process_remote;
  65. traced_process_receiver_ =
  66. std::make_unique<mojo::Receiver<tracing::mojom::TracedProcess>>(
  67. tracing::TracedProcessImpl::GetInstance());
  68. traced_process_receiver_->Bind(
  69. traced_process_remote.InitWithNewPipeAndPassReceiver());
  70. auto client_info = mojom::ClientInfo::New(base::GetCurrentProcId(),
  71. std::move(traced_process_remote));
  72. service()->AddClient(std::move(client_info));
  73. perfetto_service()->SetActiveServicePidsInitialized();
  74. }
  75. static size_t CountTestPackets(const char* data, size_t length) {
  76. if (!length)
  77. return 0;
  78. size_t test_packet_count = 0;
  79. perfetto::protos::Trace trace;
  80. EXPECT_TRUE(trace.ParseFromArray(data, length));
  81. for (const auto& packet : trace.packet()) {
  82. if (packet.has_for_testing()) {
  83. EXPECT_EQ(kPerfettoTestString, packet.for_testing().str());
  84. test_packet_count++;
  85. }
  86. }
  87. return test_packet_count;
  88. }
  89. size_t ReadAndCountTestPackets(perfetto::TracingSession& session) {
  90. size_t test_packet_count = 0;
  91. base::RunLoop wait_for_data_loop;
  92. session.ReadTrace(
  93. [&wait_for_data_loop, &test_packet_count](
  94. perfetto::TracingSession::ReadTraceCallbackArgs args) {
  95. test_packet_count += CountTestPackets(args.data, args.size);
  96. if (!args.has_more)
  97. wait_for_data_loop.Quit();
  98. });
  99. wait_for_data_loop.Run();
  100. return test_packet_count;
  101. }
  102. private:
  103. PerfettoService perfetto_service_;
  104. TracingService service_;
  105. std::unique_ptr<mojo::Receiver<tracing::mojom::TracedProcess>>
  106. traced_process_receiver_;
  107. };
  108. class TestTracingClient : public mojom::TracingSessionClient {
  109. public:
  110. void StartTracing(mojom::TracingService* service,
  111. base::OnceClosure on_tracing_enabled) {
  112. service->BindConsumerHost(consumer_host_.BindNewPipeAndPassReceiver());
  113. perfetto::TraceConfig perfetto_config =
  114. tracing::GetDefaultPerfettoConfig(base::trace_event::TraceConfig(""),
  115. /*privacy_filtering_enabled=*/false);
  116. consumer_host_->EnableTracing(
  117. tracing_session_host_.BindNewPipeAndPassReceiver(),
  118. receiver_.BindNewPipeAndPassRemote(), std::move(perfetto_config),
  119. base::File());
  120. tracing_session_host_->RequestBufferUsage(
  121. base::BindOnce([](base::OnceClosure on_response, bool, float,
  122. bool) { std::move(on_response).Run(); },
  123. std::move(on_tracing_enabled)));
  124. }
  125. void StopTracing(base::OnceClosure on_tracing_stopped) {
  126. tracing_disabled_callback_ = std::move(on_tracing_stopped);
  127. tracing_session_host_->DisableTracing();
  128. }
  129. // tracing::mojom::TracingSessionClient implementation:
  130. void OnTracingEnabled() override {}
  131. void OnTracingDisabled(bool) override {
  132. std::move(tracing_disabled_callback_).Run();
  133. }
  134. private:
  135. base::OnceClosure tracing_disabled_callback_;
  136. mojo::Remote<mojom::ConsumerHost> consumer_host_;
  137. mojo::Remote<mojom::TracingSessionHost> tracing_session_host_;
  138. mojo::Receiver<mojom::TracingSessionClient> receiver_{this};
  139. };
  140. TEST_F(TracingServiceTest, TracingServiceInstantiate) {
  141. TestTracingClient tracing_client;
  142. base::RunLoop tracing_started;
  143. tracing_client.StartTracing(service(), tracing_started.QuitClosure());
  144. tracing_started.Run();
  145. base::RunLoop tracing_stopped;
  146. tracing_client.StopTracing(tracing_stopped.QuitClosure());
  147. tracing_stopped.Run();
  148. }
  149. TEST_F(TracingServiceTest, PerfettoClientConsumer) {
  150. // Set up API bindings.
  151. EnableClientApiConsumer();
  152. // Register a mock producer with an in-process Perfetto service.
  153. auto pid = 123;
  154. size_t kNumPackets = 10;
  155. base::RunLoop wait_for_start;
  156. base::RunLoop wait_for_registration;
  157. std::unique_ptr<MockProducer> producer = std::make_unique<MockProducer>(
  158. std::string("org.chromium-") + base::NumberToString(pid),
  159. "com.example.mock_data_source", perfetto_service(),
  160. wait_for_registration.QuitClosure(), wait_for_start.QuitClosure(),
  161. kNumPackets);
  162. wait_for_registration.Run();
  163. // Start a tracing session using the client API.
  164. auto session =
  165. perfetto::Tracing::NewTrace(perfetto::BackendType::kCustomBackend);
  166. perfetto::TraceConfig perfetto_config;
  167. perfetto_config.add_buffers()->set_size_kb(1024);
  168. auto* ds_cfg = perfetto_config.add_data_sources()->mutable_config();
  169. ds_cfg->set_name("com.example.mock_data_source");
  170. session->Setup(perfetto_config);
  171. session->Start();
  172. wait_for_start.Run();
  173. // Stop the session and wait for it to stop. Note that we can't use the
  174. // blocking API here because the service runs on the current sequence.
  175. base::RunLoop wait_for_stop_loop;
  176. session->SetOnStopCallback(
  177. [&wait_for_stop_loop] { wait_for_stop_loop.Quit(); });
  178. session->Stop();
  179. wait_for_stop_loop.Run();
  180. // Verify tracing session statistics.
  181. base::RunLoop wait_for_stats_loop;
  182. perfetto::protos::TraceStats stats;
  183. auto stats_callback =
  184. [&wait_for_stats_loop,
  185. &stats](perfetto::TracingSession::GetTraceStatsCallbackArgs args) {
  186. EXPECT_TRUE(args.success);
  187. EXPECT_TRUE(stats.ParseFromArray(args.trace_stats_data.data(),
  188. args.trace_stats_data.size()));
  189. wait_for_stats_loop.Quit();
  190. };
  191. session->GetTraceStats(std::move(stats_callback));
  192. wait_for_stats_loop.Run();
  193. EXPECT_EQ(1024u * 1024u, stats.buffer_stats(0).buffer_size());
  194. EXPECT_GT(stats.buffer_stats(0).bytes_written(), 0u);
  195. EXPECT_EQ(0u, stats.buffer_stats(0).trace_writer_packet_loss());
  196. // Read and verify the data.
  197. EXPECT_EQ(kNumPackets, ReadAndCountTestPackets(*session));
  198. }
  199. TEST_F(TracingServiceTest, PerfettoClientConsumerLegacyJson) {
  200. // Set up API bindings.
  201. EnableClientApiConsumer();
  202. // Start a tracing session with legacy JSON exporting.
  203. auto session =
  204. perfetto::Tracing::NewTrace(perfetto::BackendType::kCustomBackend);
  205. perfetto::TraceConfig perfetto_config = GetDefaultPerfettoConfig(
  206. base::trace_event::TraceConfig(), /*privacy_filtering_enabled=*/false,
  207. /*convert_to_legacy_json=*/true);
  208. session->Setup(perfetto_config);
  209. session->Start();
  210. // Stop the session and wait for it to stop. Note that we can't use the
  211. // blocking API here because the service runs on the current sequence.
  212. base::RunLoop wait_for_stop_loop;
  213. session->SetOnStopCallback(
  214. [&wait_for_stop_loop] { wait_for_stop_loop.Quit(); });
  215. session->Stop();
  216. wait_for_stop_loop.Run();
  217. // Read and verify the JSON data.
  218. base::RunLoop wait_for_data_loop;
  219. TracePacketTokenizer tokenizer;
  220. std::string json;
  221. session->ReadTrace([&wait_for_data_loop, &tokenizer, &json](
  222. perfetto::TracingSession::ReadTraceCallbackArgs args) {
  223. if (args.size) {
  224. auto packets = tokenizer.Parse(
  225. reinterpret_cast<const uint8_t*>(args.data), args.size);
  226. for (const auto& packet : packets) {
  227. for (const auto& slice : packet.slices()) {
  228. json += std::string(reinterpret_cast<const char*>(slice.start),
  229. slice.size);
  230. }
  231. }
  232. }
  233. if (!args.has_more)
  234. wait_for_data_loop.Quit();
  235. });
  236. wait_for_data_loop.Run();
  237. DCHECK(!tokenizer.has_more());
  238. absl::optional<base::Value> result = base::JSONReader::Read(json);
  239. ASSERT_TRUE(result.has_value());
  240. EXPECT_TRUE(result->FindKey("traceEvents"));
  241. }
  242. #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
  243. class CustomDataSource : public perfetto::DataSource<CustomDataSource> {
  244. public:
  245. struct Events {
  246. base::RunLoop wait_for_setup_loop;
  247. base::RunLoop wait_for_start_loop;
  248. base::RunLoop wait_for_stop_loop;
  249. };
  250. static void set_events(Events* events) { events_ = events; }
  251. void OnSetup(const SetupArgs&) override {
  252. events_->wait_for_setup_loop.Quit();
  253. }
  254. void OnStart(const StartArgs&) override {
  255. events_->wait_for_start_loop.Quit();
  256. }
  257. void OnStop(const StopArgs&) override { events_->wait_for_stop_loop.Quit(); }
  258. private:
  259. static Events* events_;
  260. };
  261. CustomDataSource::Events* CustomDataSource::events_;
  262. TEST_F(TracingServiceTest, PerfettoClientProducer) {
  263. // Set up API bindings.
  264. EnableClientApiConsumer();
  265. EnableClientApiProducer();
  266. perfetto::DataSourceDescriptor dsd;
  267. dsd.set_name("com.example.custom_data_source");
  268. CustomDataSource::Events ds_events;
  269. CustomDataSource::set_events(&ds_events);
  270. CustomDataSource::Register(dsd);
  271. // Start a tracing session using the client API.
  272. auto session =
  273. perfetto::Tracing::NewTrace(perfetto::BackendType::kCustomBackend);
  274. perfetto::TraceConfig perfetto_config;
  275. perfetto_config.add_buffers()->set_size_kb(1024);
  276. auto* ds_cfg = perfetto_config.add_data_sources()->mutable_config();
  277. ds_cfg->set_name("com.example.custom_data_source");
  278. session->Setup(perfetto_config);
  279. session->Start();
  280. ds_events.wait_for_setup_loop.Run();
  281. ds_events.wait_for_start_loop.Run();
  282. // Write more data to check the commit flow works too.
  283. size_t kNumPackets = 1000;
  284. CustomDataSource::Trace([kNumPackets](CustomDataSource::TraceContext ctx) {
  285. for (size_t i = 0; i < kNumPackets / 2; i++) {
  286. ctx.NewTracePacket()->set_for_testing()->set_str(
  287. tracing::kPerfettoTestString);
  288. }
  289. ctx.Flush();
  290. });
  291. // Write half of the data from another thread to check TLS is hooked up
  292. // properly.
  293. base::Thread thread("TestThread");
  294. thread.Start();
  295. thread.task_runner()->PostTask(
  296. FROM_HERE, base::BindLambdaForTesting([kNumPackets] {
  297. CustomDataSource::Trace(
  298. [kNumPackets](CustomDataSource::TraceContext ctx) {
  299. for (size_t i = 0; i < kNumPackets / 2; i++) {
  300. ctx.NewTracePacket()->set_for_testing()->set_str(
  301. tracing::kPerfettoTestString);
  302. }
  303. ctx.Flush();
  304. });
  305. }));
  306. thread.Stop();
  307. // Stop the session and wait for it to stop. Note that we can't use the
  308. // blocking variants here because the service runs on the current sequence.
  309. base::RunLoop wait_for_stop_loop;
  310. session->SetOnStopCallback(
  311. [&wait_for_stop_loop] { wait_for_stop_loop.Quit(); });
  312. session->Stop();
  313. ds_events.wait_for_stop_loop.Run();
  314. wait_for_stop_loop.Run();
  315. // Read and verify the data.
  316. EXPECT_EQ(kNumPackets, ReadAndCountTestPackets(*session));
  317. }
  318. #endif // BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
  319. #if !BUILDFLAG(IS_WIN)
  320. // TODO(crbug.com/1158482): Support tracing to file on Windows.
  321. TEST_F(TracingServiceTest, TraceToFile) {
  322. // Set up API bindings.
  323. EnableClientApiConsumer();
  324. // Register a mock producer with an in-process Perfetto service.
  325. auto pid = 123;
  326. size_t kNumPackets = 10;
  327. base::RunLoop wait_for_start;
  328. base::RunLoop wait_for_registration;
  329. std::unique_ptr<MockProducer> producer = std::make_unique<MockProducer>(
  330. std::string("org.chromium-") + base::NumberToString(pid),
  331. "com.example.mock_data_source", perfetto_service(),
  332. wait_for_registration.QuitClosure(), wait_for_start.QuitClosure(),
  333. kNumPackets);
  334. wait_for_registration.Run();
  335. base::FilePath output_file_path;
  336. ASSERT_TRUE(base::CreateTemporaryFile(&output_file_path));
  337. base::File output_file;
  338. output_file.Initialize(output_file_path,
  339. base::File::FLAG_OPEN | base::File::FLAG_WRITE);
  340. // Start a tracing session using the client API.
  341. auto session =
  342. perfetto::Tracing::NewTrace(perfetto::BackendType::kCustomBackend);
  343. perfetto::TraceConfig perfetto_config;
  344. perfetto_config.add_buffers()->set_size_kb(1024);
  345. auto* ds_cfg = perfetto_config.add_data_sources()->mutable_config();
  346. ds_cfg->set_name("com.example.mock_data_source");
  347. session->Setup(perfetto_config, output_file.TakePlatformFile());
  348. session->Start();
  349. wait_for_start.Run();
  350. // Stop the session and wait for it to stop. Note that we can't use the
  351. // blocking API here because the service runs on the current sequence.
  352. base::RunLoop wait_for_stop_loop;
  353. session->SetOnStopCallback(
  354. [&wait_for_stop_loop] { wait_for_stop_loop.Quit(); });
  355. session->Stop();
  356. wait_for_stop_loop.Run();
  357. // Read and verify the data.
  358. std::string trace;
  359. base::ScopedAllowBlockingForTesting allow_blocking;
  360. ASSERT_TRUE(base::ReadFileToString(output_file_path, &trace));
  361. EXPECT_EQ(kNumPackets, CountTestPackets(trace.data(), trace.length()));
  362. }
  363. #endif
  364. } // namespace tracing