1 /*
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 <fcntl.h>
18
19 #include <chrono>
20 #include <condition_variable>
21 #include <functional>
22 #include <list>
23 #include <mutex>
24 #include <regex>
25 #include <thread>
26 #include <vector>
27
28 // We also want to test legacy trace events.
29 #define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 1
30
31 #include "perfetto/tracing.h"
32 #include "test/gtest_and_gmock.h"
33
34 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
35 #include <Windows.h> // For CreateFile().
36 #endif
37
38 // Deliberately not pulling any non-public perfetto header to spot accidental
39 // header public -> non-public dependency while building this file.
40
41 // These two are the only headers allowed here, see comments in
42 // api_test_support.h.
43 #include "src/tracing/test/api_test_support.h"
44 #include "src/tracing/test/tracing_module.h"
45
46 #include "perfetto/tracing/core/data_source_descriptor.h"
47 #include "perfetto/tracing/core/trace_config.h"
48
49 // xxx.pbzero.h includes are for the writing path (the code that pretends to be
50 // production code).
51 // yyy.gen.h includes are for the test readback path (the code in the test that
52 // checks that the results are valid).
53 #include "protos/perfetto/common/builtin_clock.pbzero.h"
54 #include "protos/perfetto/common/interceptor_descriptor.gen.h"
55 #include "protos/perfetto/common/trace_stats.gen.h"
56 #include "protos/perfetto/common/tracing_service_state.gen.h"
57 #include "protos/perfetto/common/track_event_descriptor.gen.h"
58 #include "protos/perfetto/config/interceptor_config.gen.h"
59 #include "protos/perfetto/config/track_event/track_event_config.gen.h"
60 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
61 #include "protos/perfetto/trace/gpu/gpu_render_stage_event.gen.h"
62 #include "protos/perfetto/trace/gpu/gpu_render_stage_event.pbzero.h"
63 #include "protos/perfetto/trace/interned_data/interned_data.gen.h"
64 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
65 #include "protos/perfetto/trace/profiling/profile_common.gen.h"
66 #include "protos/perfetto/trace/test_event.gen.h"
67 #include "protos/perfetto/trace/test_event.pbzero.h"
68 #include "protos/perfetto/trace/test_extensions.pbzero.h"
69 #include "protos/perfetto/trace/trace.gen.h"
70 #include "protos/perfetto/trace/trace.pbzero.h"
71 #include "protos/perfetto/trace/trace_packet.gen.h"
72 #include "protos/perfetto/trace/trace_packet.pbzero.h"
73 #include "protos/perfetto/trace/track_event/chrome_process_descriptor.gen.h"
74 #include "protos/perfetto/trace/track_event/chrome_process_descriptor.pbzero.h"
75 #include "protos/perfetto/trace/track_event/counter_descriptor.gen.h"
76 #include "protos/perfetto/trace/track_event/debug_annotation.gen.h"
77 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
78 #include "protos/perfetto/trace/track_event/log_message.gen.h"
79 #include "protos/perfetto/trace/track_event/log_message.pbzero.h"
80 #include "protos/perfetto/trace/track_event/process_descriptor.gen.h"
81 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
82 #include "protos/perfetto/trace/track_event/source_location.gen.h"
83 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
84 #include "protos/perfetto/trace/track_event/thread_descriptor.gen.h"
85 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
86 #include "protos/perfetto/trace/track_event/track_descriptor.gen.h"
87 #include "protos/perfetto/trace/track_event/track_event.gen.h"
88
89 // Events in categories starting with "dynamic" will use dynamic category
90 // lookup.
91 PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES("dynamic");
92
93 // Trace categories used in the tests.
94 PERFETTO_DEFINE_CATEGORIES(
95 perfetto::Category("test")
96 .SetDescription("This is a test category")
97 .SetTags("tag"),
98 perfetto::Category("foo"),
99 perfetto::Category("bar"),
100 perfetto::Category("cat").SetTags("slow"),
101 perfetto::Category("cat.verbose").SetTags("debug"),
102 perfetto::Category("cat-with-dashes"),
103 perfetto::Category::Group("foo,bar"),
104 perfetto::Category::Group("baz,bar,quux"),
105 perfetto::Category::Group("red,green,blue,foo"),
106 perfetto::Category::Group("red,green,blue,yellow"),
107 perfetto::Category(TRACE_DISABLED_BY_DEFAULT("cat")));
108 PERFETTO_TRACK_EVENT_STATIC_STORAGE();
109
110 // For testing interning of complex objects.
111 using SourceLocation = std::tuple<const char* /* file_name */,
112 const char* /* function_name */,
113 uint32_t /* line_number */>;
114
115 template <>
116 struct std::hash<SourceLocation> {
operator ()std::hash117 size_t operator()(const SourceLocation& value) const {
118 auto hasher = hash<size_t>();
119 return hasher(reinterpret_cast<size_t>(get<0>(value))) ^
120 hasher(reinterpret_cast<size_t>(get<1>(value))) ^
121 hasher(get<2>(value));
122 }
123 };
124
125 // Represents an opaque (from Perfetto's point of view) thread identifier (e.g.,
126 // base::PlatformThreadId in Chromium).
127 struct MyThreadId {
MyThreadIdMyThreadId128 explicit MyThreadId(int tid_) : tid(tid_) {}
129
130 const int tid = 0;
131 };
132
133 // Represents an opaque timestamp (e.g., base::TimeTicks in Chromium).
134 class MyTimestamp {
135 public:
MyTimestamp(uint64_t ts_)136 explicit MyTimestamp(uint64_t ts_) : ts(ts_) {}
137
138 const uint64_t ts;
139 };
140
141 namespace perfetto {
142 namespace legacy {
143
144 template <>
ConvertThreadId(const MyThreadId & thread)145 ThreadTrack ConvertThreadId(const MyThreadId& thread) {
146 return perfetto::ThreadTrack::ForThread(
147 static_cast<base::PlatformThreadId>(thread.tid));
148 }
149
150 } // namespace legacy
151
152 template <>
153 struct TraceTimestampTraits<MyTimestamp> {
ConvertTimestampToTraceTimeNsperfetto::TraceTimestampTraits154 static TraceTimestamp ConvertTimestampToTraceTimeNs(
155 const MyTimestamp& timestamp) {
156 return {TrackEvent::GetTraceClockId(), timestamp.ts};
157 }
158 };
159
160 } // namespace perfetto
161
162 namespace {
163
164 using perfetto::TracingInitArgs;
165 using ::testing::_;
166 using ::testing::ContainerEq;
167 using ::testing::ElementsAre;
168 using ::testing::HasSubstr;
169 using ::testing::Invoke;
170 using ::testing::InvokeWithoutArgs;
171 using ::testing::NiceMock;
172 using ::testing::Not;
173 using ::testing::Property;
174 using ::testing::StrEq;
175
176 // ------------------------------
177 // Declarations of helper classes
178 // ------------------------------
179
180 class WaitableTestEvent {
181 public:
notified()182 bool notified() {
183 std::unique_lock<std::mutex> lock(mutex_);
184 return notified_;
185 }
186
Wait()187 void Wait() {
188 std::unique_lock<std::mutex> lock(mutex_);
189 // TSAN gets confused by wait_for, which we would use here in a perfect
190 // world.
191 cv_.wait(lock, [this] { return notified_; });
192 }
193
Notify()194 void Notify() {
195 {
196 std::lock_guard<std::mutex> lock(mutex_);
197 notified_ = true;
198 }
199 // Do not notify while holding the lock, because then we wake up the other
200 // end, only for it to fail to acquire the lock.
201 cv_.notify_one();
202 }
203
204 private:
205 std::mutex mutex_;
206 std::condition_variable cv_;
207 bool notified_ = false;
208 };
209
210 class MockDataSource;
211
212 // We can't easily use gmock here because instances of data sources are lazily
213 // created by the service and are not owned by the test fixture.
214 struct TestDataSourceHandle {
215 WaitableTestEvent on_create;
216 WaitableTestEvent on_setup;
217 WaitableTestEvent on_start;
218 WaitableTestEvent on_stop;
219 MockDataSource* instance;
220 perfetto::DataSourceConfig config;
221 bool handle_stop_asynchronously = false;
222 std::function<void()> on_start_callback;
223 std::function<void()> on_stop_callback;
224 std::function<void()> async_stop_closure;
225 };
226
227 class MockDataSource : public perfetto::DataSource<MockDataSource> {
228 public:
229 void OnSetup(const SetupArgs&) override;
230 void OnStart(const StartArgs&) override;
231 void OnStop(const StopArgs&) override;
232 TestDataSourceHandle* handle_ = nullptr;
233 };
234
235 constexpr int kTestDataSourceArg = 123;
236
237 class MockDataSource2 : public perfetto::DataSource<MockDataSource2> {
238 public:
MockDataSource2(int arg)239 MockDataSource2(int arg) { EXPECT_EQ(arg, kTestDataSourceArg); }
OnSetup(const SetupArgs &)240 void OnSetup(const SetupArgs&) override {}
OnStart(const StartArgs &)241 void OnStart(const StartArgs&) override {}
OnStop(const StopArgs &)242 void OnStop(const StopArgs&) override {}
243 };
244
245 // Used to verify that track event data sources in different namespaces register
246 // themselves correctly in the muxer.
247 class MockTracingMuxer : public perfetto::internal::TracingMuxer {
248 public:
249 struct DataSource {
250 const perfetto::DataSourceDescriptor dsd;
251 perfetto::internal::DataSourceStaticState* static_state;
252 };
253
MockTracingMuxer()254 MockTracingMuxer() : TracingMuxer(nullptr), prev_instance_(instance_) {
255 instance_ = this;
256 }
~MockTracingMuxer()257 ~MockTracingMuxer() override { instance_ = prev_instance_; }
258
RegisterDataSource(const perfetto::DataSourceDescriptor & dsd,DataSourceFactory,perfetto::internal::DataSourceStaticState * static_state)259 bool RegisterDataSource(
260 const perfetto::DataSourceDescriptor& dsd,
261 DataSourceFactory,
262 perfetto::internal::DataSourceStaticState* static_state) override {
263 data_sources.emplace_back(DataSource{dsd, static_state});
264 return true;
265 }
266
CreateTraceWriter(perfetto::internal::DataSourceStaticState *,uint32_t,perfetto::internal::DataSourceState *,perfetto::BufferExhaustedPolicy)267 std::unique_ptr<perfetto::TraceWriterBase> CreateTraceWriter(
268 perfetto::internal::DataSourceStaticState*,
269 uint32_t,
270 perfetto::internal::DataSourceState*,
271 perfetto::BufferExhaustedPolicy) override {
272 return nullptr;
273 }
274
DestroyStoppedTraceWritersForCurrentThread()275 void DestroyStoppedTraceWritersForCurrentThread() override {}
RegisterInterceptor(const perfetto::InterceptorDescriptor &,InterceptorFactory,perfetto::InterceptorBase::TLSFactory,perfetto::InterceptorBase::TracePacketCallback)276 void RegisterInterceptor(
277 const perfetto::InterceptorDescriptor&,
278 InterceptorFactory,
279 perfetto::InterceptorBase::TLSFactory,
280 perfetto::InterceptorBase::TracePacketCallback) override {}
281
282 std::vector<DataSource> data_sources;
283
284 private:
285 TracingMuxer* prev_instance_;
286 };
287
288 struct TestIncrementalState {
TestIncrementalState__anone89577de0111::TestIncrementalState289 TestIncrementalState() { constructed = true; }
290 // Note: a virtual destructor is not required for incremental state.
~TestIncrementalState__anone89577de0111::TestIncrementalState291 ~TestIncrementalState() { destroyed = true; }
292
293 int count = 100;
294 bool flag = false;
295 static bool constructed;
296 static bool destroyed;
297 };
298
299 bool TestIncrementalState::constructed;
300 bool TestIncrementalState::destroyed;
301
302 struct TestIncrementalDataSourceTraits
303 : public perfetto::DefaultDataSourceTraits {
304 using IncrementalStateType = TestIncrementalState;
305 };
306
307 class TestIncrementalDataSource
308 : public perfetto::DataSource<TestIncrementalDataSource,
309 TestIncrementalDataSourceTraits> {
310 public:
OnSetup(const SetupArgs &)311 void OnSetup(const SetupArgs&) override {}
OnStart(const StartArgs &)312 void OnStart(const StartArgs&) override {}
OnStop(const StopArgs &)313 void OnStop(const StopArgs&) override {}
314 };
315
316 // A convenience wrapper around TracingSession that allows to do block on
317 //
318 struct TestTracingSessionHandle {
get__anone89577de0111::TestTracingSessionHandle319 perfetto::TracingSession* get() { return session.get(); }
320 std::unique_ptr<perfetto::TracingSession> session;
321 WaitableTestEvent on_stop;
322 };
323
324 class MyDebugAnnotation : public perfetto::DebugAnnotation {
325 public:
326 ~MyDebugAnnotation() override = default;
327
Add(perfetto::protos::pbzero::DebugAnnotation * annotation) const328 void Add(
329 perfetto::protos::pbzero::DebugAnnotation* annotation) const override {
330 annotation->set_legacy_json_value(R"({"key": 123})");
331 }
332 };
333
334 class TestTracingPolicy : public perfetto::TracingPolicy {
335 public:
ShouldAllowConsumerSession(const ShouldAllowConsumerSessionArgs & args)336 void ShouldAllowConsumerSession(
337 const ShouldAllowConsumerSessionArgs& args) override {
338 EXPECT_NE(args.backend_type, perfetto::BackendType::kUnspecifiedBackend);
339 args.result_callback(should_allow_consumer_connection);
340 }
341
342 bool should_allow_consumer_connection = true;
343 };
344
345 TestTracingPolicy* g_test_tracing_policy = new TestTracingPolicy(); // Leaked.
346
347 // -------------------------
348 // Declaration of test class
349 // -------------------------
350 class PerfettoApiTest : public ::testing::TestWithParam<perfetto::BackendType> {
351 public:
352 static PerfettoApiTest* instance;
353
SetUp()354 void SetUp() override {
355 instance = this;
356 g_test_tracing_policy->should_allow_consumer_connection = true;
357
358 // Start a fresh system service for this test, tearing down any previous
359 // service that was running.
360 uint32_t supported_backends =
361 perfetto::kInProcessBackend | perfetto::kSystemBackend;
362 if (!perfetto::test::StartSystemService())
363 supported_backends &= ~perfetto::kSystemBackend;
364
365 // If the system backend wasn't supported, skip all system backend tests.
366 auto backend = GetParam();
367 if (!(supported_backends & backend))
368 GTEST_SKIP();
369
370 static bool was_initialized;
371 if (!was_initialized) {
372 EXPECT_FALSE(perfetto::Tracing::IsInitialized());
373 was_initialized = true;
374 } else {
375 EXPECT_TRUE(perfetto::Tracing::IsInitialized());
376 }
377
378 // Since the client API can only be initialized once per process, initialize
379 // both the in-process and system backends for every test here. The actual
380 // service to be used is chosen by the test parameter.
381 TracingInitArgs args;
382 args.backends = supported_backends;
383 args.tracing_policy = g_test_tracing_policy;
384 perfetto::Tracing::Initialize(args);
385 RegisterDataSource<MockDataSource>("my_data_source");
386 perfetto::TrackEvent::Register();
387
388 // Make sure our data source always has a valid handle.
389 data_sources_["my_data_source"];
390
391 // If this wasn't the first test to run in this process, any producers
392 // connected to the old system service will have been disconnected by the
393 // service restarting above. Wait for all producers to connect again before
394 // proceeding with the test.
395 perfetto::test::SyncProducers();
396
397 perfetto::test::DisableReconnectLimit();
398 }
399
TearDown()400 void TearDown() override { instance = nullptr; }
401
402 template <typename DataSourceType>
RegisterDataSource(std::string name)403 TestDataSourceHandle* RegisterDataSource(std::string name) {
404 EXPECT_EQ(data_sources_.count(name), 0u);
405 TestDataSourceHandle* handle = &data_sources_[name];
406 perfetto::DataSourceDescriptor dsd;
407 dsd.set_name(name);
408 DataSourceType::Register(dsd);
409 return handle;
410 }
411
NewTrace(const perfetto::TraceConfig & cfg,int fd=-1)412 TestTracingSessionHandle* NewTrace(const perfetto::TraceConfig& cfg,
413 int fd = -1) {
414 return NewTrace(cfg, /*backend_type=*/GetParam(), fd);
415 }
416
NewTrace(const perfetto::TraceConfig & cfg,perfetto::BackendType backend_type,int fd=-1)417 TestTracingSessionHandle* NewTrace(const perfetto::TraceConfig& cfg,
418 perfetto::BackendType backend_type,
419 int fd = -1) {
420 sessions_.emplace_back();
421 TestTracingSessionHandle* handle = &sessions_.back();
422 handle->session = perfetto::Tracing::NewTrace(backend_type);
423 handle->session->SetOnStopCallback([handle] { handle->on_stop.Notify(); });
424 handle->session->Setup(cfg, fd);
425 return handle;
426 }
427
NewTraceWithCategories(std::vector<std::string> categories)428 TestTracingSessionHandle* NewTraceWithCategories(
429 std::vector<std::string> categories) {
430 perfetto::TraceConfig cfg;
431 cfg.set_duration_ms(500);
432 cfg.add_buffers()->set_size_kb(1024);
433 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
434 ds_cfg->set_name("track_event");
435
436 perfetto::protos::gen::TrackEventConfig te_cfg;
437 te_cfg.add_disabled_categories("*");
438 for (const auto& category : categories)
439 te_cfg.add_enabled_categories(category);
440 ds_cfg->set_track_event_config_raw(te_cfg.SerializeAsString());
441
442 return NewTrace(cfg);
443 }
444
ReadLogMessagesFromTrace(perfetto::TracingSession * tracing_session)445 std::vector<std::string> ReadLogMessagesFromTrace(
446 perfetto::TracingSession* tracing_session) {
447 std::vector<char> raw_trace = tracing_session->ReadTraceBlocking();
448 EXPECT_GE(raw_trace.size(), 0u);
449
450 // Read back the trace, maintaining interning tables as we go.
451 std::vector<std::string> log_messages;
452 std::map<uint64_t, std::string> log_message_bodies;
453 std::map<uint64_t, perfetto::protos::gen::SourceLocation> source_locations;
454 perfetto::protos::gen::Trace parsed_trace;
455 EXPECT_TRUE(
456 parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
457
458 for (const auto& packet : parsed_trace.packet()) {
459 if (!packet.has_track_event())
460 continue;
461
462 if (packet.has_interned_data()) {
463 const auto& interned_data = packet.interned_data();
464 for (const auto& it : interned_data.log_message_body()) {
465 EXPECT_GE(it.iid(), 1u);
466 EXPECT_EQ(log_message_bodies.find(it.iid()),
467 log_message_bodies.end());
468 log_message_bodies[it.iid()] = it.body();
469 }
470 for (const auto& it : interned_data.source_locations()) {
471 EXPECT_GE(it.iid(), 1u);
472 EXPECT_EQ(source_locations.find(it.iid()), source_locations.end());
473 source_locations[it.iid()] = it;
474 }
475 }
476 const auto& track_event = packet.track_event();
477 if (track_event.type() !=
478 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN)
479 continue;
480
481 EXPECT_TRUE(track_event.has_log_message());
482 const auto& log = track_event.log_message();
483 if (log.source_location_iid()) {
484 std::stringstream msg;
485 const auto& source_location =
486 source_locations[log.source_location_iid()];
487 msg << source_location.function_name() << "("
488 << source_location.file_name() << ":"
489 << source_location.line_number()
490 << "): " << log_message_bodies[log.body_iid()];
491 log_messages.emplace_back(msg.str());
492 } else {
493 log_messages.emplace_back(log_message_bodies[log.body_iid()]);
494 }
495 }
496 return log_messages;
497 }
498
ReadSlicesFromTrace(perfetto::TracingSession * tracing_session)499 std::vector<std::string> ReadSlicesFromTrace(
500 perfetto::TracingSession* tracing_session) {
501 std::vector<char> raw_trace = tracing_session->ReadTraceBlocking();
502 EXPECT_GE(raw_trace.size(), 0u);
503
504 // Read back the trace, maintaining interning tables as we go.
505 std::vector<std::string> slices;
506 std::map<uint64_t, std::string> categories;
507 std::map<uint64_t, std::string> event_names;
508 std::map<uint64_t, std::string> debug_annotation_names;
509 std::set<uint64_t> seen_tracks;
510 perfetto::protos::gen::Trace parsed_trace;
511 EXPECT_TRUE(
512 parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
513
514 bool incremental_state_was_cleared = false;
515 uint32_t sequence_id = 0;
516 for (const auto& packet : parsed_trace.packet()) {
517 if (packet.sequence_flags() & perfetto::protos::pbzero::TracePacket::
518 SEQ_INCREMENTAL_STATE_CLEARED) {
519 incremental_state_was_cleared = true;
520 categories.clear();
521 event_names.clear();
522 debug_annotation_names.clear();
523 seen_tracks.clear();
524 }
525
526 if (packet.has_track_descriptor()) {
527 // Make sure we haven't seen any events on this track before the
528 // descriptor was written.
529 EXPECT_EQ(seen_tracks.find(packet.track_descriptor().uuid()),
530 seen_tracks.end());
531 }
532
533 if (!packet.has_track_event())
534 continue;
535
536 // Make sure we only see track events on one sequence.
537 if (packet.trusted_packet_sequence_id()) {
538 if (!sequence_id)
539 sequence_id = packet.trusted_packet_sequence_id();
540 EXPECT_EQ(sequence_id, packet.trusted_packet_sequence_id());
541 }
542
543 // Update incremental state.
544 if (packet.has_interned_data()) {
545 const auto& interned_data = packet.interned_data();
546 for (const auto& it : interned_data.event_categories()) {
547 EXPECT_EQ(categories.find(it.iid()), categories.end());
548 categories[it.iid()] = it.name();
549 }
550 for (const auto& it : interned_data.event_names()) {
551 EXPECT_EQ(event_names.find(it.iid()), event_names.end());
552 event_names[it.iid()] = it.name();
553 }
554 for (const auto& it : interned_data.debug_annotation_names()) {
555 EXPECT_EQ(debug_annotation_names.find(it.iid()),
556 debug_annotation_names.end());
557 debug_annotation_names[it.iid()] = it.name();
558 }
559 }
560 const auto& track_event = packet.track_event();
561 std::string slice;
562
563 if (track_event.has_track_uuid()) {
564 seen_tracks.insert(track_event.track_uuid());
565 std::stringstream track;
566 track << "[track=" << track_event.track_uuid() << "]";
567 slice += track.str();
568 }
569
570 switch (track_event.type()) {
571 case perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN:
572 slice += "B";
573 break;
574 case perfetto::protos::gen::TrackEvent::TYPE_SLICE_END:
575 slice += "E";
576 break;
577 case perfetto::protos::gen::TrackEvent::TYPE_INSTANT:
578 slice += "I";
579 break;
580 case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED: {
581 EXPECT_TRUE(track_event.has_legacy_event());
582 EXPECT_FALSE(track_event.type());
583 auto legacy_event = track_event.legacy_event();
584 slice += "Legacy_" +
585 std::string(1, static_cast<char>(legacy_event.phase()));
586 break;
587 }
588 case perfetto::protos::gen::TrackEvent::TYPE_COUNTER:
589 slice += "C";
590 break;
591 default:
592 ADD_FAILURE();
593 }
594 if (track_event.has_legacy_event()) {
595 auto legacy_event = track_event.legacy_event();
596 std::stringstream id;
597 if (legacy_event.has_unscoped_id()) {
598 id << "(unscoped_id=" << legacy_event.unscoped_id() << ")";
599 } else if (legacy_event.has_local_id()) {
600 id << "(local_id=" << legacy_event.local_id() << ")";
601 } else if (legacy_event.has_global_id()) {
602 id << "(global_id=" << legacy_event.global_id() << ")";
603 } else if (legacy_event.has_bind_id()) {
604 id << "(bind_id=" << legacy_event.bind_id() << ")";
605 }
606 if (legacy_event.has_id_scope())
607 id << "(id_scope=\"" << legacy_event.id_scope() << "\")";
608 if (legacy_event.use_async_tts())
609 id << "(use_async_tts)";
610 if (legacy_event.bind_to_enclosing())
611 id << "(bind_to_enclosing)";
612 if (legacy_event.has_flow_direction())
613 id << "(flow_direction=" << legacy_event.flow_direction() << ")";
614 if (legacy_event.has_pid_override())
615 id << "(pid_override=" << legacy_event.pid_override() << ")";
616 if (legacy_event.has_tid_override())
617 id << "(tid_override=" << legacy_event.tid_override() << ")";
618 slice += id.str();
619 }
620 size_t category_count = 0;
621 for (const auto& it : track_event.category_iids())
622 slice += (category_count++ ? "," : ":") + categories[it];
623 for (const auto& it : track_event.categories())
624 slice += (category_count++ ? ",$" : ":$") + it;
625 if (track_event.has_name_iid())
626 slice += "." + event_names[track_event.name_iid()];
627
628 if (track_event.debug_annotations_size()) {
629 slice += "(";
630 bool first_annotation = true;
631 for (const auto& it : track_event.debug_annotations()) {
632 if (!first_annotation) {
633 slice += ",";
634 }
635 slice += debug_annotation_names[it.name_iid()] + "=";
636 std::stringstream value;
637 if (it.has_bool_value()) {
638 value << "(bool)" << it.bool_value();
639 } else if (it.has_uint_value()) {
640 value << "(uint)" << it.uint_value();
641 } else if (it.has_int_value()) {
642 value << "(int)" << it.int_value();
643 } else if (it.has_double_value()) {
644 value << "(double)" << it.double_value();
645 } else if (it.has_string_value()) {
646 value << "(string)" << it.string_value();
647 } else if (it.has_pointer_value()) {
648 value << "(pointer)" << std::hex << it.pointer_value();
649 } else if (it.has_legacy_json_value()) {
650 value << "(json)" << it.legacy_json_value();
651 } else if (it.has_nested_value()) {
652 value << "(nested)" << it.nested_value().string_value();
653 }
654 slice += value.str();
655 first_annotation = false;
656 }
657 slice += ")";
658 }
659
660 slices.push_back(slice);
661 }
662 EXPECT_TRUE(incremental_state_was_cleared);
663 return slices;
664 }
665
GetMainThreadPacketSequenceId(const perfetto::protos::gen::Trace & trace)666 uint32_t GetMainThreadPacketSequenceId(
667 const perfetto::protos::gen::Trace& trace) {
668 for (const auto& packet : trace.packet()) {
669 if (packet.has_track_descriptor() &&
670 packet.track_descriptor().thread().tid() ==
671 static_cast<int32_t>(perfetto::base::GetThreadId())) {
672 return packet.trusted_packet_sequence_id();
673 }
674 }
675 ADD_FAILURE() << "Main thread not found";
676 return 0;
677 }
678
679 std::map<std::string, TestDataSourceHandle> data_sources_;
680 std::list<TestTracingSessionHandle> sessions_; // Needs stable pointers.
681 };
682
683 // ---------------------------------------------
684 // Definitions for non-inlineable helper methods
685 // ---------------------------------------------
686 PerfettoApiTest* PerfettoApiTest::instance;
687
OnSetup(const SetupArgs & args)688 void MockDataSource::OnSetup(const SetupArgs& args) {
689 EXPECT_EQ(handle_, nullptr);
690 auto it = PerfettoApiTest::instance->data_sources_.find(args.config->name());
691
692 // We should not see an OnSetup for a data source that we didn't register
693 // before via PerfettoApiTest::RegisterDataSource().
694 EXPECT_NE(it, PerfettoApiTest::instance->data_sources_.end());
695 handle_ = &it->second;
696 handle_->config = *args.config; // Deliberate copy.
697 handle_->on_setup.Notify();
698 }
699
OnStart(const StartArgs &)700 void MockDataSource::OnStart(const StartArgs&) {
701 EXPECT_NE(handle_, nullptr);
702 if (handle_->on_start_callback)
703 handle_->on_start_callback();
704 handle_->on_start.Notify();
705 }
706
OnStop(const StopArgs & args)707 void MockDataSource::OnStop(const StopArgs& args) {
708 EXPECT_NE(handle_, nullptr);
709 if (handle_->handle_stop_asynchronously)
710 handle_->async_stop_closure = args.HandleStopAsynchronously();
711 if (handle_->on_stop_callback)
712 handle_->on_stop_callback();
713 handle_->on_stop.Notify();
714 }
715
716 // -------------
717 // Test fixtures
718 // -------------
719
TEST_P(PerfettoApiTest,StartAndStopWithoutDataSources)720 TEST_P(PerfettoApiTest, StartAndStopWithoutDataSources) {
721 // Create a new trace session without any data sources configured.
722 perfetto::TraceConfig cfg;
723 cfg.add_buffers()->set_size_kb(1024);
724 auto* tracing_session = NewTrace(cfg);
725 // This should not timeout.
726 tracing_session->get()->StartBlocking();
727 tracing_session->get()->StopBlocking();
728 }
729
730 // Disabled by default because it leaks tracing sessions into subsequent tests,
731 // which can result in the per-uid tracing session limit (5) to be hit in later
732 // tests.
TEST_P(PerfettoApiTest,DISABLED_TrackEventStartStopAndDestroy)733 TEST_P(PerfettoApiTest, DISABLED_TrackEventStartStopAndDestroy) {
734 // This test used to cause a use after free as the tracing session got
735 // destroyed. It needed to be run approximately 2000 times to catch it so test
736 // with --gtest_repeat=3000 (less if running under GDB).
737
738 // Setup the trace config.
739 perfetto::TraceConfig cfg;
740 cfg.set_duration_ms(500);
741 cfg.add_buffers()->set_size_kb(1024);
742 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
743 ds_cfg->set_name("track_event");
744
745 // Create five new trace sessions.
746 std::vector<std::unique_ptr<perfetto::TracingSession>> sessions;
747 for (size_t i = 0; i < 5; ++i) {
748 sessions.push_back(perfetto::Tracing::NewTrace(/*BackendType=*/GetParam()));
749 sessions[i]->Setup(cfg);
750 sessions[i]->Start();
751 sessions[i]->Stop();
752 }
753 }
754
TEST_P(PerfettoApiTest,TrackEventStartStopAndStopBlocking)755 TEST_P(PerfettoApiTest, TrackEventStartStopAndStopBlocking) {
756 // This test used to cause a deadlock (due to StopBlocking() after the session
757 // already stopped). This usually occurred within 1 or 2 runs of the test so
758 // use --gtest_repeat=10
759
760 // Setup the trace config.
761 perfetto::TraceConfig cfg;
762 cfg.set_duration_ms(500);
763 cfg.add_buffers()->set_size_kb(1024);
764 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
765 ds_cfg->set_name("track_event");
766
767 // Create five new trace sessions.
768 std::vector<std::unique_ptr<perfetto::TracingSession>> sessions;
769 for (size_t i = 0; i < 5; ++i) {
770 sessions.push_back(perfetto::Tracing::NewTrace(/*BackendType=*/GetParam()));
771 sessions[i]->Setup(cfg);
772 sessions[i]->Start();
773 sessions[i]->Stop();
774 }
775 for (auto& session : sessions) {
776 session->StopBlocking();
777 }
778 }
779
TEST_P(PerfettoApiTest,ChangeTraceConfiguration)780 TEST_P(PerfettoApiTest, ChangeTraceConfiguration) {
781 // Setup the trace config.
782 perfetto::TraceConfig trace_config;
783 trace_config.set_duration_ms(2000);
784 trace_config.add_buffers()->set_size_kb(1024);
785 auto* data_source = trace_config.add_data_sources();
786
787 // Configure track events with category "foo".
788 auto* ds_cfg = data_source->mutable_config();
789 ds_cfg->set_name("track_event");
790 perfetto::protos::gen::TrackEventConfig te_cfg;
791 te_cfg.add_disabled_categories("*");
792 te_cfg.add_enabled_categories("foo");
793 ds_cfg->set_track_event_config_raw(te_cfg.SerializeAsString());
794
795 // Initially, exclude all producers (the client library's producer is named
796 // after current process's name, which will not match
797 // "all_producers_excluded").
798 data_source->add_producer_name_filter("all_producers_excluded");
799
800 auto* tracing_session = NewTrace(trace_config);
801
802 tracing_session->get()->StartBlocking();
803
804 // Emit a first trace event, this one should be filtered out due
805 // to the mismatching producer name filter.
806 TRACE_EVENT_BEGIN("foo", "EventFilteredOut");
807 TRACE_EVENT_END("foo");
808
809 // Remove the producer name filter by changing configs.
810 data_source->clear_producer_name_filter();
811 tracing_session->get()->ChangeTraceConfig(trace_config);
812
813 // We don't have a blocking version of ChangeTraceConfig, because there is
814 // currently no response to it from producers or the service. Instead, we sync
815 // the consumer and producer IPC streams for this test, to ensure that the
816 // producer_name_filter change has propagated.
817 tracing_session->get()->GetTraceStatsBlocking(); // sync consumer stream.
818 perfetto::test::SyncProducers(); // sync producer stream.
819
820 // Emit a second trace event, this one should be included because
821 // the producer name filter was cleared.
822 TRACE_EVENT_BEGIN("foo", "EventIncluded");
823 TRACE_EVENT_END("foo");
824 tracing_session->get()->StopBlocking();
825
826 // Verify that only the second event is in the trace data.
827 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
828 std::string trace(raw_trace.data(), raw_trace.size());
829 EXPECT_THAT(trace, Not(HasSubstr("EventFilteredOut")));
830 EXPECT_THAT(trace, HasSubstr("EventIncluded"));
831 }
832
833 // This is a build-only regression test that checks you can have a track event
834 // inside a template.
835 template <typename T>
TestTrackEventInsideTemplate(T)836 void TestTrackEventInsideTemplate(T) {
837 TRACE_EVENT_BEGIN("cat", "Name");
838 }
839
840 // This is a build-only regression test that checks you can specify the tracing
841 // category as a template argument.
842 constexpr const char kTestCategory[] = "foo";
843 template <const char* category>
TestCategoryAsTemplateParameter()844 void TestCategoryAsTemplateParameter() {
845 TRACE_EVENT_BEGIN(category, "Name");
846 }
847
TEST_P(PerfettoApiTest,TrackEvent)848 TEST_P(PerfettoApiTest, TrackEvent) {
849 // Create a new trace session.
850 auto* tracing_session = NewTraceWithCategories({"test"});
851 tracing_session->get()->StartBlocking();
852
853 // Emit one complete track event.
854 TRACE_EVENT_BEGIN("test", "TestEvent");
855 TRACE_EVENT_END("test");
856 perfetto::TrackEvent::Flush();
857
858 tracing_session->on_stop.Wait();
859 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
860 ASSERT_GE(raw_trace.size(), 0u);
861
862 // Read back the trace, maintaining interning tables as we go.
863 perfetto::protos::gen::Trace trace;
864 std::map<uint64_t, std::string> categories;
865 std::map<uint64_t, std::string> event_names;
866 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
867
868 auto now = perfetto::TrackEvent::GetTraceTimeNs();
869 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
870 !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
871 auto clock_id = perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
872 #else
873 auto clock_id = perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
874 #endif
875 EXPECT_EQ(clock_id, perfetto::TrackEvent::GetTraceClockId());
876
877 bool incremental_state_was_cleared = false;
878 bool begin_found = false;
879 bool end_found = false;
880 bool process_descriptor_found = false;
881 uint32_t sequence_id = 0;
882 int32_t cur_pid = perfetto::test::GetCurrentProcessId();
883 for (const auto& packet : trace.packet()) {
884 if (packet.has_track_descriptor()) {
885 const auto& desc = packet.track_descriptor();
886 if (desc.has_process()) {
887 EXPECT_FALSE(process_descriptor_found);
888 const auto& pd = desc.process();
889 EXPECT_EQ(cur_pid, pd.pid());
890 process_descriptor_found = true;
891 }
892 }
893 if (packet.sequence_flags() &
894 perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
895 EXPECT_TRUE(packet.has_trace_packet_defaults());
896 incremental_state_was_cleared = true;
897 categories.clear();
898 event_names.clear();
899 }
900
901 if (!packet.has_track_event())
902 continue;
903 EXPECT_TRUE(
904 packet.sequence_flags() &
905 (perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED |
906 perfetto::protos::pbzero::TracePacket::SEQ_NEEDS_INCREMENTAL_STATE));
907 const auto& track_event = packet.track_event();
908
909 // Make sure we only see track events on one sequence.
910 if (packet.trusted_packet_sequence_id()) {
911 if (!sequence_id)
912 sequence_id = packet.trusted_packet_sequence_id();
913 EXPECT_EQ(sequence_id, packet.trusted_packet_sequence_id());
914 }
915
916 // Update incremental state.
917 if (packet.has_interned_data()) {
918 const auto& interned_data = packet.interned_data();
919 for (const auto& it : interned_data.event_categories()) {
920 EXPECT_EQ(categories.find(it.iid()), categories.end());
921 categories[it.iid()] = it.name();
922 }
923 for (const auto& it : interned_data.event_names()) {
924 EXPECT_EQ(event_names.find(it.iid()), event_names.end());
925 event_names[it.iid()] = it.name();
926 }
927 }
928
929 EXPECT_GT(packet.timestamp(), 0u);
930 EXPECT_LE(packet.timestamp(), now);
931 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \
932 !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
933 EXPECT_FALSE(packet.has_timestamp_clock_id());
934 #else
935 constexpr auto kClockMonotonic =
936 perfetto::protos::pbzero::ClockSnapshot::Clock::MONOTONIC;
937 EXPECT_EQ(packet.timestamp_clock_id(),
938 static_cast<uint32_t>(kClockMonotonic));
939 #endif
940 if (track_event.type() ==
941 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN) {
942 EXPECT_FALSE(begin_found);
943 EXPECT_EQ(track_event.category_iids().size(), 1u);
944 EXPECT_GE(track_event.category_iids()[0], 1u);
945 EXPECT_EQ("test", categories[track_event.category_iids()[0]]);
946 EXPECT_EQ("TestEvent", event_names[track_event.name_iid()]);
947 begin_found = true;
948 } else if (track_event.type() ==
949 perfetto::protos::gen::TrackEvent::TYPE_SLICE_END) {
950 EXPECT_FALSE(end_found);
951 EXPECT_EQ(track_event.category_iids().size(), 0u);
952 EXPECT_EQ(0u, track_event.name_iid());
953 end_found = true;
954 }
955 }
956 EXPECT_TRUE(incremental_state_was_cleared);
957 EXPECT_TRUE(process_descriptor_found);
958 EXPECT_TRUE(begin_found);
959 EXPECT_TRUE(end_found);
960
961 // Dummy instantiation of test templates.
962 TestTrackEventInsideTemplate(true);
963 TestCategoryAsTemplateParameter<kTestCategory>();
964 }
965
TEST_P(PerfettoApiTest,TrackEventCategories)966 TEST_P(PerfettoApiTest, TrackEventCategories) {
967 // Create a new trace session.
968 auto* tracing_session = NewTraceWithCategories({"bar"});
969 tracing_session->get()->StartBlocking();
970
971 // Emit some track events.
972 TRACE_EVENT_BEGIN("foo", "NotEnabled");
973 TRACE_EVENT_END("foo");
974 TRACE_EVENT_BEGIN("bar", "Enabled");
975 TRACE_EVENT_END("bar");
976
977 tracing_session->get()->StopBlocking();
978 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
979 std::string trace(raw_trace.data(), raw_trace.size());
980 // TODO(skyostil): Come up with a nicer way to verify trace contents.
981 EXPECT_THAT(trace, HasSubstr("Enabled"));
982 EXPECT_THAT(trace, Not(HasSubstr("NotEnabled")));
983 }
984
TEST_P(PerfettoApiTest,ClearIncrementalState)985 TEST_P(PerfettoApiTest, ClearIncrementalState) {
986 perfetto::DataSourceDescriptor dsd;
987 dsd.set_name("incr_data_source");
988 TestIncrementalDataSource::Register(dsd);
989 perfetto::test::SyncProducers();
990
991 // Setup the trace config with an incremental state clearing period.
992 perfetto::TraceConfig cfg;
993 cfg.set_duration_ms(500);
994 cfg.add_buffers()->set_size_kb(1024);
995 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
996 ds_cfg->set_name("incr_data_source");
997 auto* is_cfg = cfg.mutable_incremental_state_config();
998 is_cfg->set_clear_period_ms(10);
999
1000 // Create a new trace session.
1001 auto* tracing_session = NewTrace(cfg);
1002 tracing_session->get()->StartBlocking();
1003
1004 // Observe at least 5 incremental state resets.
1005 constexpr size_t kMaxLoops = 100;
1006 size_t loops = 0;
1007 size_t times_cleared = 0;
1008 while (times_cleared < 5) {
1009 ASSERT_LT(loops++, kMaxLoops);
1010 TestIncrementalDataSource::Trace(
1011 [&](TestIncrementalDataSource::TraceContext ctx) {
1012 auto* incr_state = ctx.GetIncrementalState();
1013 if (!incr_state->flag) {
1014 incr_state->flag = true;
1015 times_cleared++;
1016 }
1017 });
1018 std::this_thread::sleep_for(std::chrono::milliseconds(10));
1019 }
1020 tracing_session->get()->StopBlocking();
1021 }
1022
TEST_P(PerfettoApiTest,TrackEventRegistrationWithModule)1023 TEST_P(PerfettoApiTest, TrackEventRegistrationWithModule) {
1024 MockTracingMuxer muxer;
1025
1026 // Each track event namespace registers its own data source.
1027 perfetto::TrackEvent::Register();
1028 EXPECT_EQ(1u, muxer.data_sources.size());
1029
1030 tracing_module::InitializeCategories();
1031 EXPECT_EQ(2u, muxer.data_sources.size());
1032
1033 // Both data sources have the same name but distinct static data (i.e.,
1034 // individual instance states).
1035 EXPECT_EQ("track_event", muxer.data_sources[0].dsd.name());
1036 EXPECT_EQ("track_event", muxer.data_sources[1].dsd.name());
1037 EXPECT_NE(muxer.data_sources[0].static_state,
1038 muxer.data_sources[1].static_state);
1039 }
1040
TEST_P(PerfettoApiTest,TrackEventDescriptor)1041 TEST_P(PerfettoApiTest, TrackEventDescriptor) {
1042 MockTracingMuxer muxer;
1043
1044 perfetto::TrackEvent::Register();
1045 EXPECT_EQ(1u, muxer.data_sources.size());
1046 EXPECT_EQ("track_event", muxer.data_sources[0].dsd.name());
1047
1048 perfetto::protos::gen::TrackEventDescriptor desc;
1049 auto desc_raw = muxer.data_sources[0].dsd.track_event_descriptor_raw();
1050 EXPECT_TRUE(desc.ParseFromArray(desc_raw.data(), desc_raw.size()));
1051
1052 // Check that the advertised categories match PERFETTO_DEFINE_CATEGORIES (see
1053 // above).
1054 EXPECT_EQ(7, desc.available_categories_size());
1055 EXPECT_EQ("test", desc.available_categories()[0].name());
1056 EXPECT_EQ("This is a test category",
1057 desc.available_categories()[0].description());
1058 EXPECT_EQ("tag", desc.available_categories()[0].tags()[0]);
1059 EXPECT_EQ("foo", desc.available_categories()[1].name());
1060 EXPECT_EQ("bar", desc.available_categories()[2].name());
1061 EXPECT_EQ("cat", desc.available_categories()[3].name());
1062 EXPECT_EQ("slow", desc.available_categories()[3].tags()[0]);
1063 EXPECT_EQ("cat.verbose", desc.available_categories()[4].name());
1064 EXPECT_EQ("debug", desc.available_categories()[4].tags()[0]);
1065 EXPECT_EQ("cat-with-dashes", desc.available_categories()[5].name());
1066 EXPECT_EQ("disabled-by-default-cat", desc.available_categories()[6].name());
1067 EXPECT_EQ("slow", desc.available_categories()[6].tags()[0]);
1068 }
1069
TEST_P(PerfettoApiTest,TrackEventSharedIncrementalState)1070 TEST_P(PerfettoApiTest, TrackEventSharedIncrementalState) {
1071 tracing_module::InitializeCategories();
1072
1073 // Setup the trace config.
1074 perfetto::TraceConfig cfg;
1075 cfg.set_duration_ms(500);
1076 cfg.add_buffers()->set_size_kb(1024);
1077 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
1078 ds_cfg->set_name("track_event");
1079 auto* tracing_session = NewTrace(cfg);
1080 tracing_session->get()->StartBlocking();
1081
1082 perfetto::internal::TrackEventIncrementalState* main_state = nullptr;
1083 perfetto::TrackEvent::Trace(
1084 [&main_state](perfetto::TrackEvent::TraceContext ctx) {
1085 main_state = ctx.GetIncrementalState();
1086 });
1087 perfetto::internal::TrackEventIncrementalState* module_state =
1088 tracing_module::GetIncrementalState();
1089
1090 // Both track event data sources should use the same incremental state (thanks
1091 // to sharing TLS).
1092 EXPECT_NE(nullptr, main_state);
1093 EXPECT_EQ(main_state, module_state);
1094 tracing_session->get()->StopBlocking();
1095 }
1096
TEST_P(PerfettoApiTest,TrackEventCategoriesWithModule)1097 TEST_P(PerfettoApiTest, TrackEventCategoriesWithModule) {
1098 // Check that categories defined in two different category registries are
1099 // enabled and disabled correctly.
1100 tracing_module::InitializeCategories();
1101
1102 // Create a new trace session. Only the "foo" category is enabled. It also
1103 // exists both locally and in the existing module.
1104 auto* tracing_session = NewTraceWithCategories({"foo"});
1105 tracing_session->get()->StartBlocking();
1106
1107 // Emit some track events locally and from the test module.
1108 TRACE_EVENT_BEGIN("foo", "FooEventFromMain");
1109 TRACE_EVENT_END("foo");
1110 tracing_module::EmitTrackEvents();
1111 tracing_module::EmitTrackEvents2();
1112 TRACE_EVENT_BEGIN("bar", "DisabledEventFromMain");
1113 TRACE_EVENT_END("bar");
1114
1115 tracing_session->get()->StopBlocking();
1116 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1117 std::string trace(raw_trace.data(), raw_trace.size());
1118 EXPECT_THAT(trace, HasSubstr("FooEventFromMain"));
1119 EXPECT_THAT(trace, Not(HasSubstr("DisabledEventFromMain")));
1120 EXPECT_THAT(trace, HasSubstr("FooEventFromModule"));
1121 EXPECT_THAT(trace, Not(HasSubstr("DisabledEventFromModule")));
1122 EXPECT_THAT(trace, HasSubstr("FooEventFromModule2"));
1123 EXPECT_THAT(trace, Not(HasSubstr("DisabledEventFromModule2")));
1124
1125 perfetto::protos::gen::Trace parsed_trace;
1126 ASSERT_TRUE(parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1127
1128 uint32_t sequence_id = 0;
1129 for (const auto& packet : parsed_trace.packet()) {
1130 if (!packet.has_track_event())
1131 continue;
1132
1133 // Make sure we only see track events on one sequence. This means all track
1134 // event modules are sharing the same trace writer (by using the same TLS
1135 // index).
1136 if (packet.trusted_packet_sequence_id()) {
1137 if (!sequence_id)
1138 sequence_id = packet.trusted_packet_sequence_id();
1139 EXPECT_EQ(sequence_id, packet.trusted_packet_sequence_id());
1140 }
1141 }
1142 }
1143
TEST_P(PerfettoApiTest,TrackEventDynamicCategories)1144 TEST_P(PerfettoApiTest, TrackEventDynamicCategories) {
1145 // Setup the trace config.
1146 perfetto::TraceConfig cfg;
1147 cfg.set_duration_ms(500);
1148 cfg.add_buffers()->set_size_kb(1024);
1149 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
1150 ds_cfg->set_name("track_event");
1151
1152 // Session #1 enabled the "dynamic" category.
1153 auto* tracing_session = NewTraceWithCategories({"dynamic"});
1154 tracing_session->get()->StartBlocking();
1155
1156 // Session #2 enables "dynamic_2".
1157 auto* tracing_session2 = NewTraceWithCategories({"dynamic_2"});
1158 tracing_session2->get()->StartBlocking();
1159
1160 // Test naming dynamic categories with std::string.
1161 perfetto::DynamicCategory dynamic{"dynamic"};
1162 TRACE_EVENT_BEGIN(dynamic, "EventInDynamicCategory");
1163 perfetto::DynamicCategory dynamic_disabled{"dynamic_disabled"};
1164 TRACE_EVENT_BEGIN(dynamic_disabled, "EventInDisabledDynamicCategory");
1165
1166 // Test naming dynamic categories statically.
1167 TRACE_EVENT_BEGIN("dynamic", "EventInStaticallyNamedDynamicCategory");
1168
1169 perfetto::DynamicCategory dynamic_2{"dynamic_2"};
1170 TRACE_EVENT_BEGIN(dynamic_2, "EventInSecondDynamicCategory");
1171 TRACE_EVENT_BEGIN("dynamic_2", "EventInSecondStaticallyNamedDynamicCategory");
1172
1173 std::thread thread([] {
1174 // Make sure the category name can actually be computed at runtime.
1175 std::string name = "dyn";
1176 if (perfetto::base::GetThreadId())
1177 name += "amic";
1178 perfetto::DynamicCategory cat{name};
1179 TRACE_EVENT_BEGIN(cat, "DynamicFromOtherThread");
1180 perfetto::DynamicCategory cat2{"dynamic_disabled"};
1181 TRACE_EVENT_BEGIN(cat2, "EventInDisabledDynamicCategory");
1182 });
1183 thread.join();
1184
1185 perfetto::TrackEvent::Flush();
1186 tracing_session->get()->StopBlocking();
1187 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1188 std::string trace(raw_trace.data(), raw_trace.size());
1189 EXPECT_THAT(trace, HasSubstr("EventInDynamicCategory"));
1190 EXPECT_THAT(trace, Not(HasSubstr("EventInDisabledDynamicCategory")));
1191 EXPECT_THAT(trace, HasSubstr("DynamicFromOtherThread"));
1192 EXPECT_THAT(trace, Not(HasSubstr("EventInSecondDynamicCategory")));
1193 EXPECT_THAT(trace, HasSubstr("EventInStaticallyNamedDynamicCategory"));
1194 EXPECT_THAT(trace,
1195 Not(HasSubstr("EventInSecondStaticallyNamedDynamicCategory")));
1196
1197 tracing_session2->get()->StopBlocking();
1198 raw_trace = tracing_session2->get()->ReadTraceBlocking();
1199 trace = std::string(raw_trace.data(), raw_trace.size());
1200 EXPECT_THAT(trace, Not(HasSubstr("EventInDynamicCategory")));
1201 EXPECT_THAT(trace, Not(HasSubstr("EventInDisabledDynamicCategory")));
1202 EXPECT_THAT(trace, Not(HasSubstr("DynamicFromOtherThread")));
1203 EXPECT_THAT(trace, HasSubstr("EventInSecondDynamicCategory"));
1204 EXPECT_THAT(trace, Not(HasSubstr("EventInStaticallyNamedDynamicCategory")));
1205 EXPECT_THAT(trace, HasSubstr("EventInSecondStaticallyNamedDynamicCategory"));
1206 }
1207
TEST_P(PerfettoApiTest,TrackEventConcurrentSessions)1208 TEST_P(PerfettoApiTest, TrackEventConcurrentSessions) {
1209 // Check that categories that are enabled and disabled in two parallel tracing
1210 // sessions don't interfere.
1211
1212 // Session #1 enables the "foo" category.
1213 auto* tracing_session = NewTraceWithCategories({"foo"});
1214 tracing_session->get()->StartBlocking();
1215
1216 // Session #2 enables the "bar" category.
1217 auto* tracing_session2 = NewTraceWithCategories({"bar"});
1218 tracing_session2->get()->StartBlocking();
1219
1220 // Emit some track events under both categories.
1221 TRACE_EVENT_BEGIN("foo", "Session1_First");
1222 TRACE_EVENT_END("foo");
1223 TRACE_EVENT_BEGIN("bar", "Session2_First");
1224 TRACE_EVENT_END("bar");
1225
1226 tracing_session->get()->StopBlocking();
1227 TRACE_EVENT_BEGIN("foo", "Session1_Second");
1228 TRACE_EVENT_END("foo");
1229 TRACE_EVENT_BEGIN("bar", "Session2_Second");
1230 TRACE_EVENT_END("bar");
1231
1232 tracing_session2->get()->StopBlocking();
1233 TRACE_EVENT_BEGIN("foo", "Session1_Third");
1234 TRACE_EVENT_END("foo");
1235 TRACE_EVENT_BEGIN("bar", "Session2_Third");
1236 TRACE_EVENT_END("bar");
1237
1238 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1239 std::string trace(raw_trace.data(), raw_trace.size());
1240 EXPECT_THAT(trace, HasSubstr("Session1_First"));
1241 EXPECT_THAT(trace, Not(HasSubstr("Session1_Second")));
1242 EXPECT_THAT(trace, Not(HasSubstr("Session1_Third")));
1243 EXPECT_THAT(trace, Not(HasSubstr("Session2_First")));
1244 EXPECT_THAT(trace, Not(HasSubstr("Session2_Second")));
1245 EXPECT_THAT(trace, Not(HasSubstr("Session2_Third")));
1246
1247 std::vector<char> raw_trace2 = tracing_session2->get()->ReadTraceBlocking();
1248 std::string trace2(raw_trace2.data(), raw_trace2.size());
1249 EXPECT_THAT(trace2, Not(HasSubstr("Session1_First")));
1250 EXPECT_THAT(trace2, Not(HasSubstr("Session1_Second")));
1251 EXPECT_THAT(trace2, Not(HasSubstr("Session1_Third")));
1252 EXPECT_THAT(trace2, HasSubstr("Session2_First"));
1253 EXPECT_THAT(trace2, HasSubstr("Session2_Second"));
1254 EXPECT_THAT(trace2, Not(HasSubstr("Session2_Third")));
1255 }
1256
TEST_P(PerfettoApiTest,TrackEventProcessAndThreadDescriptors)1257 TEST_P(PerfettoApiTest, TrackEventProcessAndThreadDescriptors) {
1258 // Thread and process descriptors can be set before tracing is enabled.
1259 perfetto::TrackEvent::SetProcessDescriptor(
1260 [](perfetto::protos::pbzero::TrackDescriptor* desc) {
1261 desc->set_name("hello.exe");
1262 desc->set_chrome_process()->set_process_priority(1);
1263 });
1264
1265 // Erased tracks shouldn't show up anywhere.
1266 perfetto::Track erased(1234u);
1267 perfetto::TrackEvent::SetTrackDescriptor(
1268 erased, [](perfetto::protos::pbzero::TrackDescriptor* desc) {
1269 desc->set_name("ErasedTrack");
1270 });
1271 perfetto::TrackEvent::EraseTrackDescriptor(erased);
1272
1273 // Setup the trace config.
1274 perfetto::TraceConfig cfg;
1275 cfg.set_duration_ms(500);
1276 cfg.add_buffers()->set_size_kb(1024);
1277 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
1278 ds_cfg->set_name("track_event");
1279
1280 // Create a new trace session.
1281 auto* tracing_session = NewTrace(cfg);
1282 tracing_session->get()->StartBlocking();
1283 TRACE_EVENT_INSTANT("test", "MainThreadEvent");
1284
1285 std::thread thread([&] {
1286 perfetto::TrackEvent::SetThreadDescriptor(
1287 [](perfetto::protos::pbzero::TrackDescriptor* desc) {
1288 desc->set_name("TestThread");
1289 });
1290 TRACE_EVENT_INSTANT("test", "ThreadEvent");
1291 });
1292 thread.join();
1293
1294 // Update the process descriptor while tracing is enabled. It should be
1295 // immediately reflected in the trace.
1296 perfetto::TrackEvent::SetProcessDescriptor(
1297 [](perfetto::protos::pbzero::TrackDescriptor* desc) {
1298 desc->set_name("goodbye.exe");
1299 });
1300 perfetto::TrackEvent::Flush();
1301
1302 tracing_session->get()->StopBlocking();
1303
1304 // After tracing ends, setting the descriptor has no immediate effect.
1305 perfetto::TrackEvent::SetProcessDescriptor(
1306 [](perfetto::protos::pbzero::TrackDescriptor* desc) {
1307 desc->set_name("noop.exe");
1308 });
1309
1310 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1311 perfetto::protos::gen::Trace trace;
1312 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1313
1314 std::vector<perfetto::protos::gen::TrackDescriptor> descs;
1315 std::vector<perfetto::protos::gen::TrackDescriptor> thread_descs;
1316 uint32_t main_thread_sequence = GetMainThreadPacketSequenceId(trace);
1317 for (const auto& packet : trace.packet()) {
1318 if (packet.has_track_descriptor()) {
1319 if (packet.trusted_packet_sequence_id() == main_thread_sequence) {
1320 descs.push_back(packet.track_descriptor());
1321 } else {
1322 thread_descs.push_back(packet.track_descriptor());
1323 }
1324 }
1325 }
1326
1327 // The main thread records the initial process name as well as the one that's
1328 // set during tracing. Additionally it records a thread descriptor for the
1329 // main thread.
1330
1331 EXPECT_EQ(3u, descs.size());
1332
1333 // Default track for the main thread.
1334 EXPECT_EQ(0, descs[0].process().pid());
1335 EXPECT_NE(0, descs[0].thread().pid());
1336
1337 // First process descriptor.
1338 EXPECT_NE(0, descs[1].process().pid());
1339 EXPECT_EQ("hello.exe", descs[1].name());
1340
1341 // Second process descriptor.
1342 EXPECT_NE(0, descs[2].process().pid());
1343 EXPECT_EQ("goodbye.exe", descs[2].name());
1344
1345 // The child thread records only its own thread descriptor (twice, since it
1346 // was mutated).
1347 EXPECT_EQ(2u, thread_descs.size());
1348 EXPECT_EQ("TestThread", thread_descs[0].name());
1349 EXPECT_NE(0, thread_descs[0].thread().pid());
1350 EXPECT_NE(0, thread_descs[0].thread().tid());
1351 EXPECT_EQ("TestThread", thread_descs[1].name());
1352 EXPECT_NE(0, thread_descs[1].thread().pid());
1353 EXPECT_NE(0, thread_descs[1].thread().tid());
1354 }
1355
TEST_P(PerfettoApiTest,CustomTrackDescriptor)1356 TEST_P(PerfettoApiTest, CustomTrackDescriptor) {
1357 // Setup the trace config.
1358 perfetto::TraceConfig cfg;
1359 cfg.set_duration_ms(500);
1360 cfg.add_buffers()->set_size_kb(1024);
1361 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
1362 ds_cfg->set_name("track_event");
1363
1364 // Create a new trace session.
1365 auto* tracing_session = NewTrace(cfg);
1366 tracing_session->get()->StartBlocking();
1367
1368 auto track = perfetto::ProcessTrack::Current();
1369 auto desc = track.Serialize();
1370 desc.mutable_process()->set_process_name("testing.exe");
1371 desc.mutable_thread()->set_tid(
1372 static_cast<int32_t>(perfetto::base::GetThreadId()));
1373 desc.mutable_chrome_process()->set_process_priority(123);
1374 perfetto::TrackEvent::SetTrackDescriptor(track, std::move(desc));
1375 perfetto::TrackEvent::Flush();
1376
1377 tracing_session->get()->StopBlocking();
1378
1379 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1380 perfetto::protos::gen::Trace trace;
1381 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1382
1383 uint32_t main_thread_sequence = GetMainThreadPacketSequenceId(trace);
1384 bool found_desc = false;
1385 for (const auto& packet : trace.packet()) {
1386 if (packet.trusted_packet_sequence_id() != main_thread_sequence)
1387 continue;
1388 if (packet.has_track_descriptor()) {
1389 auto td = packet.track_descriptor();
1390 EXPECT_TRUE(td.has_process());
1391 EXPECT_NE(0, td.process().pid());
1392 EXPECT_TRUE(td.has_chrome_process());
1393 EXPECT_EQ("testing.exe", td.process().process_name());
1394 EXPECT_EQ(123, td.chrome_process().process_priority());
1395 found_desc = true;
1396 }
1397 }
1398 EXPECT_TRUE(found_desc);
1399 }
1400
TEST_P(PerfettoApiTest,TrackEventCustomTrack)1401 TEST_P(PerfettoApiTest, TrackEventCustomTrack) {
1402 // Create a new trace session.
1403 auto* tracing_session = NewTraceWithCategories({"bar"});
1404 tracing_session->get()->StartBlocking();
1405
1406 // Declare a custom track and give it a name.
1407 uint64_t async_id = 123;
1408 perfetto::TrackEvent::SetTrackDescriptor(
1409 perfetto::Track(async_id),
1410 [](perfetto::protos::pbzero::TrackDescriptor* desc) {
1411 desc->set_name("MyCustomTrack");
1412 });
1413
1414 // Start events on one thread and end them on another.
1415 TRACE_EVENT_BEGIN("bar", "AsyncEvent", perfetto::Track(async_id), "debug_arg",
1416 123);
1417
1418 TRACE_EVENT_BEGIN("bar", "SubEvent", perfetto::Track(async_id),
1419 [](perfetto::EventContext) {});
1420 const auto main_thread_track =
1421 perfetto::Track(async_id, perfetto::ThreadTrack::Current());
1422 std::thread thread([&] {
1423 TRACE_EVENT_END("bar", perfetto::Track(async_id));
1424 TRACE_EVENT_END("bar", perfetto::Track(async_id), "arg1", false, "arg2",
1425 true);
1426 const auto thread_track =
1427 perfetto::Track(async_id, perfetto::ThreadTrack::Current());
1428 // Thread-scoped tracks will have different uuids on different thread even
1429 // if the id matches.
1430 ASSERT_NE(main_thread_track.uuid, thread_track.uuid);
1431 });
1432 thread.join();
1433
1434 perfetto::TrackEvent::Flush();
1435 tracing_session->get()->StopBlocking();
1436
1437 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1438 perfetto::protos::gen::Trace trace;
1439 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1440
1441 // Check that the track uuids match on the begin and end events.
1442 const auto track = perfetto::Track(async_id);
1443 uint32_t main_thread_sequence = GetMainThreadPacketSequenceId(trace);
1444 int event_count = 0;
1445 bool found_descriptor = false;
1446 for (const auto& packet : trace.packet()) {
1447 if (packet.has_track_descriptor() &&
1448 !packet.track_descriptor().has_process() &&
1449 !packet.track_descriptor().has_thread()) {
1450 auto td = packet.track_descriptor();
1451 EXPECT_EQ("MyCustomTrack", td.name());
1452 EXPECT_EQ(track.uuid, td.uuid());
1453 EXPECT_EQ(perfetto::ProcessTrack::Current().uuid, td.parent_uuid());
1454 found_descriptor = true;
1455 continue;
1456 }
1457
1458 if (!packet.has_track_event())
1459 continue;
1460 auto track_event = packet.track_event();
1461 if (track_event.type() ==
1462 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN) {
1463 EXPECT_EQ(main_thread_sequence, packet.trusted_packet_sequence_id());
1464 EXPECT_EQ(track.uuid, track_event.track_uuid());
1465 } else {
1466 EXPECT_NE(main_thread_sequence, packet.trusted_packet_sequence_id());
1467 EXPECT_EQ(track.uuid, track_event.track_uuid());
1468 }
1469 event_count++;
1470 }
1471 EXPECT_TRUE(found_descriptor);
1472 EXPECT_EQ(4, event_count);
1473 perfetto::TrackEvent::EraseTrackDescriptor(track);
1474 }
1475
TEST_P(PerfettoApiTest,LegacyEventWithThreadOverride)1476 TEST_P(PerfettoApiTest, LegacyEventWithThreadOverride) {
1477 // Create a new trace session.
1478 auto* tracing_session = NewTraceWithCategories({"cat"});
1479 tracing_session->get()->StartBlocking();
1480
1481 TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("cat", "Name", 1,
1482 MyThreadId(456), MyTimestamp{0});
1483 perfetto::TrackEvent::Flush();
1484 tracing_session->get()->StopBlocking();
1485
1486 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1487 perfetto::protos::gen::Trace trace;
1488 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1489
1490 // Check that we wrote a track descriptor for the custom thread track, and
1491 // that the event was associated with that track.
1492 const auto track = perfetto::ThreadTrack::ForThread(456);
1493 bool found_descriptor = false;
1494 bool found_event = false;
1495 for (const auto& packet : trace.packet()) {
1496 if (packet.has_track_descriptor() &&
1497 packet.track_descriptor().has_thread()) {
1498 auto td = packet.track_descriptor().thread();
1499 if (td.tid() == 456) {
1500 EXPECT_EQ(track.uuid, packet.track_descriptor().uuid());
1501 found_descriptor = true;
1502 }
1503 }
1504
1505 if (!packet.has_track_event())
1506 continue;
1507 auto track_event = packet.track_event();
1508 if (track_event.legacy_event().phase() == TRACE_EVENT_PHASE_ASYNC_BEGIN) {
1509 EXPECT_EQ(track.uuid, track_event.track_uuid());
1510 found_event = true;
1511 }
1512 }
1513 EXPECT_TRUE(found_descriptor);
1514 EXPECT_TRUE(found_event);
1515 perfetto::TrackEvent::EraseTrackDescriptor(track);
1516 }
1517
TEST_P(PerfettoApiTest,LegacyEventWithProcessOverride)1518 TEST_P(PerfettoApiTest, LegacyEventWithProcessOverride) {
1519 // Create a new trace session.
1520 auto* tracing_session = NewTraceWithCategories({"cat"});
1521 tracing_session->get()->StartBlocking();
1522
1523 // Note: there's no direct entrypoint for adding trace events for another
1524 // process, so we're using the internal support macro here.
1525 INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(
1526 TRACE_EVENT_PHASE_INSTANT, "cat", "Name", 0, MyThreadId{789},
1527 MyTimestamp{0}, TRACE_EVENT_FLAG_HAS_PROCESS_ID);
1528 perfetto::TrackEvent::Flush();
1529 tracing_session->get()->StopBlocking();
1530
1531 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1532 perfetto::protos::gen::Trace trace;
1533 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1534
1535 // Check that the event has a pid_override matching MyThread above.
1536 bool found_event = false;
1537 for (const auto& packet : trace.packet()) {
1538 if (!packet.has_track_event())
1539 continue;
1540 auto track_event = packet.track_event();
1541 if (track_event.type() == perfetto::protos::gen::TrackEvent::TYPE_INSTANT) {
1542 EXPECT_EQ(789, track_event.legacy_event().pid_override());
1543 EXPECT_EQ(-1, track_event.legacy_event().tid_override());
1544 found_event = true;
1545 }
1546 }
1547 EXPECT_TRUE(found_event);
1548 }
1549
TEST_P(PerfettoApiTest,TrackDescriptorWrittenBeforeEvent)1550 TEST_P(PerfettoApiTest, TrackDescriptorWrittenBeforeEvent) {
1551 // Create a new trace session.
1552 auto* tracing_session = NewTraceWithCategories({"bar"});
1553 tracing_session->get()->StartBlocking();
1554
1555 // Emit an event on a custom track.
1556 TRACE_EVENT_INSTANT("bar", "Event", perfetto::Track(8086));
1557 perfetto::TrackEvent::Flush();
1558 tracing_session->get()->StopBlocking();
1559
1560 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1561 perfetto::protos::gen::Trace trace;
1562 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1563
1564 // Check that the descriptor was written before the event.
1565 std::set<uint64_t> seen_descriptors;
1566 for (const auto& packet : trace.packet()) {
1567 if (packet.has_track_descriptor())
1568 seen_descriptors.insert(packet.track_descriptor().uuid());
1569
1570 if (!packet.has_track_event())
1571 continue;
1572 auto track_event = packet.track_event();
1573 EXPECT_TRUE(seen_descriptors.find(track_event.track_uuid()) !=
1574 seen_descriptors.end());
1575 }
1576 }
1577
TEST_P(PerfettoApiTest,TrackEventCustomTrackAndTimestamp)1578 TEST_P(PerfettoApiTest, TrackEventCustomTrackAndTimestamp) {
1579 // Create a new trace session.
1580 auto* tracing_session = NewTraceWithCategories({"bar"});
1581 tracing_session->get()->StartBlocking();
1582
1583 // Custom track.
1584 perfetto::Track track(789);
1585
1586 auto empty_lambda = [](perfetto::EventContext) {};
1587 constexpr uint64_t kBeginEventTime = 10;
1588 const MyTimestamp kEndEventTime{15};
1589 TRACE_EVENT_BEGIN("bar", "Event", track, kBeginEventTime, empty_lambda);
1590 TRACE_EVENT_END("bar", track, kEndEventTime, empty_lambda);
1591
1592 constexpr uint64_t kInstantEventTime = 1;
1593 TRACE_EVENT_INSTANT("bar", "InstantEvent", track, kInstantEventTime,
1594 empty_lambda);
1595
1596 perfetto::TrackEvent::Flush();
1597 tracing_session->get()->StopBlocking();
1598
1599 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1600 perfetto::protos::gen::Trace trace;
1601 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1602
1603 int event_count = 0;
1604 for (const auto& packet : trace.packet()) {
1605 if (!packet.has_track_event())
1606 continue;
1607 event_count++;
1608 switch (packet.track_event().type()) {
1609 case perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN:
1610 EXPECT_EQ(packet.timestamp(), kBeginEventTime);
1611 break;
1612 case perfetto::protos::gen::TrackEvent::TYPE_SLICE_END:
1613 EXPECT_EQ(packet.timestamp(), kEndEventTime.ts);
1614 break;
1615 case perfetto::protos::gen::TrackEvent::TYPE_INSTANT:
1616 EXPECT_EQ(packet.timestamp(), kInstantEventTime);
1617 break;
1618 case perfetto::protos::gen::TrackEvent::TYPE_COUNTER:
1619 case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED:
1620 ADD_FAILURE();
1621 }
1622 }
1623 EXPECT_EQ(event_count, 3);
1624 perfetto::TrackEvent::EraseTrackDescriptor(track);
1625 }
1626
TEST_P(PerfettoApiTest,TrackEventCustomTrackAndTimestampNoLambda)1627 TEST_P(PerfettoApiTest, TrackEventCustomTrackAndTimestampNoLambda) {
1628 auto* tracing_session = NewTraceWithCategories({"bar"});
1629 tracing_session->get()->StartBlocking();
1630
1631 perfetto::Track track(789);
1632
1633 constexpr uint64_t kBeginEventTime = 10;
1634 constexpr uint64_t kEndEventTime = 15;
1635 TRACE_EVENT_BEGIN("bar", "Event", track, kBeginEventTime);
1636 TRACE_EVENT_END("bar", track, kEndEventTime);
1637
1638 perfetto::TrackEvent::Flush();
1639 tracing_session->get()->StopBlocking();
1640
1641 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1642 perfetto::protos::gen::Trace trace;
1643 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1644
1645 int event_count = 0;
1646 for (const auto& packet : trace.packet()) {
1647 if (!packet.has_track_event())
1648 continue;
1649 event_count++;
1650 switch (packet.track_event().type()) {
1651 case perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN:
1652 EXPECT_EQ(packet.timestamp(), kBeginEventTime);
1653 break;
1654 case perfetto::protos::gen::TrackEvent::TYPE_SLICE_END:
1655 EXPECT_EQ(packet.timestamp(), kEndEventTime);
1656 break;
1657 case perfetto::protos::gen::TrackEvent::TYPE_INSTANT:
1658 case perfetto::protos::gen::TrackEvent::TYPE_COUNTER:
1659 case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED:
1660 ADD_FAILURE();
1661 }
1662 }
1663
1664 EXPECT_EQ(event_count, 2);
1665 }
1666
TEST_P(PerfettoApiTest,TrackEventAnonymousCustomTrack)1667 TEST_P(PerfettoApiTest, TrackEventAnonymousCustomTrack) {
1668 // Create a new trace session.
1669 auto* tracing_session = NewTraceWithCategories({"bar"});
1670 tracing_session->get()->StartBlocking();
1671
1672 // Emit an async event without giving it an explicit descriptor.
1673 uint64_t async_id = 4004;
1674 auto track = perfetto::Track(async_id, perfetto::ThreadTrack::Current());
1675 TRACE_EVENT_BEGIN("bar", "AsyncEvent", track);
1676 std::thread thread([&] { TRACE_EVENT_END("bar", track); });
1677 thread.join();
1678
1679 perfetto::TrackEvent::Flush();
1680 tracing_session->get()->StopBlocking();
1681
1682 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1683 perfetto::protos::gen::Trace trace;
1684 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1685
1686 // Check that a descriptor for the track was emitted.
1687 bool found_descriptor = false;
1688 for (const auto& packet : trace.packet()) {
1689 if (packet.has_track_descriptor() &&
1690 !packet.track_descriptor().has_process() &&
1691 !packet.track_descriptor().has_thread()) {
1692 auto td = packet.track_descriptor();
1693 EXPECT_EQ(track.uuid, td.uuid());
1694 EXPECT_EQ(perfetto::ThreadTrack::Current().uuid, td.parent_uuid());
1695 found_descriptor = true;
1696 }
1697 }
1698 EXPECT_TRUE(found_descriptor);
1699 }
1700
TEST_P(PerfettoApiTest,TrackEventTypedArgs)1701 TEST_P(PerfettoApiTest, TrackEventTypedArgs) {
1702 // Create a new trace session.
1703 auto* tracing_session = NewTraceWithCategories({"foo"});
1704 tracing_session->get()->StartBlocking();
1705
1706 auto random_value = rand();
1707 TRACE_EVENT_BEGIN("foo", "EventWithTypedArg",
1708 [random_value](perfetto::EventContext ctx) {
1709 auto* log = ctx.event()->set_log_message();
1710 log->set_source_location_iid(1);
1711 log->set_body_iid(2);
1712 auto* dbg = ctx.event()->add_debug_annotations();
1713 dbg->set_name("random");
1714 dbg->set_int_value(random_value);
1715 });
1716 TRACE_EVENT_END("foo");
1717
1718 tracing_session->get()->StopBlocking();
1719 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1720 std::string trace(raw_trace.data(), raw_trace.size());
1721
1722 perfetto::protos::gen::Trace parsed_trace;
1723 ASSERT_TRUE(parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1724
1725 bool found_args = false;
1726 for (const auto& packet : parsed_trace.packet()) {
1727 if (!packet.has_track_event())
1728 continue;
1729 const auto& track_event = packet.track_event();
1730 if (track_event.type() !=
1731 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN)
1732 continue;
1733
1734 EXPECT_TRUE(track_event.has_log_message());
1735 const auto& log = track_event.log_message();
1736 EXPECT_EQ(1u, log.source_location_iid());
1737 EXPECT_EQ(2u, log.body_iid());
1738
1739 const auto& dbg = track_event.debug_annotations()[0];
1740 EXPECT_EQ("random", dbg.name());
1741 EXPECT_EQ(random_value, dbg.int_value());
1742
1743 found_args = true;
1744 }
1745 EXPECT_TRUE(found_args);
1746 }
1747
TEST_P(PerfettoApiTest,InlineTrackEventTypedArgs_SimpleRepeated)1748 TEST_P(PerfettoApiTest, InlineTrackEventTypedArgs_SimpleRepeated) {
1749 // Create a new trace session.
1750 auto* tracing_session = NewTraceWithCategories({"foo"});
1751 tracing_session->get()->StartBlocking();
1752
1753 std::vector<uint64_t> flow_ids{1, 2, 3};
1754 TRACE_EVENT_BEGIN("foo", "EventWithTypedArg",
1755 perfetto::protos::pbzero::TrackEvent::kFlowIds, flow_ids);
1756 TRACE_EVENT_END("foo");
1757
1758 tracing_session->get()->StopBlocking();
1759 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1760 std::string trace(raw_trace.data(), raw_trace.size());
1761
1762 perfetto::protos::gen::Trace parsed_trace;
1763 ASSERT_TRUE(parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1764
1765 bool found_args = false;
1766 for (const auto& packet : parsed_trace.packet()) {
1767 if (!packet.has_track_event())
1768 continue;
1769 const auto& track_event = packet.track_event();
1770 if (track_event.type() !=
1771 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN) {
1772 continue;
1773 }
1774
1775 EXPECT_THAT(track_event.flow_ids(), testing::ElementsAre(1, 2, 3));
1776 found_args = true;
1777 }
1778 EXPECT_TRUE(found_args);
1779 }
1780
TEST_P(PerfettoApiTest,InlineTrackEventTypedArgs_NestedSingle)1781 TEST_P(PerfettoApiTest, InlineTrackEventTypedArgs_NestedSingle) {
1782 struct LogMessage {
1783 void WriteIntoTrace(
1784 perfetto::TracedProto<perfetto::protos::pbzero::LogMessage> context)
1785 const {
1786 context->set_source_location_iid(1);
1787 context->set_body_iid(2);
1788 }
1789 };
1790
1791 // Create a new trace session.
1792 auto* tracing_session = NewTraceWithCategories({"foo"});
1793 tracing_session->get()->StartBlocking();
1794
1795 TRACE_EVENT_BEGIN("foo", "EventWithTypedArg",
1796 perfetto::protos::pbzero::TrackEvent::kLogMessage,
1797 LogMessage());
1798 TRACE_EVENT_END("foo");
1799
1800 tracing_session->get()->StopBlocking();
1801 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
1802 std::string trace(raw_trace.data(), raw_trace.size());
1803
1804 perfetto::protos::gen::Trace parsed_trace;
1805 ASSERT_TRUE(parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
1806
1807 bool found_args = false;
1808 for (const auto& packet : parsed_trace.packet()) {
1809 if (!packet.has_track_event())
1810 continue;
1811 const auto& track_event = packet.track_event();
1812 if (track_event.type() !=
1813 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN) {
1814 continue;
1815 }
1816
1817 EXPECT_TRUE(track_event.has_log_message());
1818 const auto& log = track_event.log_message();
1819 EXPECT_EQ(1u, log.source_location_iid());
1820 EXPECT_EQ(2u, log.body_iid());
1821 found_args = true;
1822 }
1823 EXPECT_TRUE(found_args);
1824 }
1825
1826 struct InternedLogMessageBody
1827 : public perfetto::TrackEventInternedDataIndex<
1828 InternedLogMessageBody,
1829 perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
1830 std::string> {
Add__anone89577de0111::InternedLogMessageBody1831 static void Add(perfetto::protos::pbzero::InternedData* interned_data,
1832 size_t iid,
1833 const std::string& value) {
1834 auto l = interned_data->add_log_message_body();
1835 l->set_iid(iid);
1836 l->set_body(value.data(), value.size());
1837 commit_count++;
1838 }
1839
1840 static int commit_count;
1841 };
1842
1843 int InternedLogMessageBody::commit_count = 0;
1844
TEST_P(PerfettoApiTest,TrackEventTypedArgsWithInterning)1845 TEST_P(PerfettoApiTest, TrackEventTypedArgsWithInterning) {
1846 // Create a new trace session.
1847 auto* tracing_session = NewTraceWithCategories({"foo"});
1848 tracing_session->get()->StartBlocking();
1849
1850 std::stringstream large_message;
1851 for (size_t i = 0; i < 512; i++)
1852 large_message << i << ". Something wicked this way comes. ";
1853
1854 size_t body_iid;
1855 InternedLogMessageBody::commit_count = 0;
1856 TRACE_EVENT_BEGIN("foo", "EventWithState", [&](perfetto::EventContext ctx) {
1857 EXPECT_EQ(0, InternedLogMessageBody::commit_count);
1858 body_iid = InternedLogMessageBody::Get(&ctx, "Alas, poor Yorick!");
1859 auto log = ctx.event()->set_log_message();
1860 log->set_body_iid(body_iid);
1861 EXPECT_EQ(1, InternedLogMessageBody::commit_count);
1862
1863 auto body_iid2 = InternedLogMessageBody::Get(&ctx, "Alas, poor Yorick!");
1864 EXPECT_EQ(body_iid, body_iid2);
1865 EXPECT_EQ(1, InternedLogMessageBody::commit_count);
1866 });
1867 TRACE_EVENT_END("foo");
1868
1869 TRACE_EVENT_BEGIN("foo", "EventWithState", [&](perfetto::EventContext ctx) {
1870 // Check that very large amounts of interned data works.
1871 auto log = ctx.event()->set_log_message();
1872 log->set_body_iid(InternedLogMessageBody::Get(&ctx, large_message.str()));
1873 EXPECT_EQ(2, InternedLogMessageBody::commit_count);
1874 });
1875 TRACE_EVENT_END("foo");
1876
1877 // Make sure interned data persists across trace points.
1878 TRACE_EVENT_BEGIN("foo", "EventWithState", [&](perfetto::EventContext ctx) {
1879 auto body_iid2 = InternedLogMessageBody::Get(&ctx, "Alas, poor Yorick!");
1880 EXPECT_EQ(body_iid, body_iid2);
1881
1882 auto body_iid3 = InternedLogMessageBody::Get(&ctx, "I knew him, Horatio");
1883 EXPECT_NE(body_iid, body_iid3);
1884 auto log = ctx.event()->set_log_message();
1885 log->set_body_iid(body_iid3);
1886 EXPECT_EQ(3, InternedLogMessageBody::commit_count);
1887 });
1888 TRACE_EVENT_END("foo");
1889
1890 tracing_session->get()->StopBlocking();
1891 auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
1892 EXPECT_THAT(log_messages,
1893 ElementsAre("Alas, poor Yorick!", large_message.str(),
1894 "I knew him, Horatio"));
1895 }
1896
1897 struct InternedLogMessageBodySmall
1898 : public perfetto::TrackEventInternedDataIndex<
1899 InternedLogMessageBodySmall,
1900 perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
1901 const char*,
1902 perfetto::SmallInternedDataTraits> {
Add__anone89577de0111::InternedLogMessageBodySmall1903 static void Add(perfetto::protos::pbzero::InternedData* interned_data,
1904 size_t iid,
1905 const char* value) {
1906 auto l = interned_data->add_log_message_body();
1907 l->set_iid(iid);
1908 l->set_body(value);
1909 }
1910 };
1911
TEST_P(PerfettoApiTest,TrackEventTypedArgsWithInterningByValue)1912 TEST_P(PerfettoApiTest, TrackEventTypedArgsWithInterningByValue) {
1913 // Create a new trace session.
1914 auto* tracing_session = NewTraceWithCategories({"foo"});
1915 tracing_session->get()->StartBlocking();
1916
1917 size_t body_iid;
1918 TRACE_EVENT_BEGIN("foo", "EventWithState", [&](perfetto::EventContext ctx) {
1919 body_iid = InternedLogMessageBodySmall::Get(&ctx, "This above all:");
1920 auto log = ctx.event()->set_log_message();
1921 log->set_body_iid(body_iid);
1922
1923 auto body_iid2 = InternedLogMessageBodySmall::Get(&ctx, "This above all:");
1924 EXPECT_EQ(body_iid, body_iid2);
1925
1926 auto body_iid3 =
1927 InternedLogMessageBodySmall::Get(&ctx, "to thine own self be true");
1928 EXPECT_NE(body_iid, body_iid3);
1929 });
1930 TRACE_EVENT_END("foo");
1931
1932 tracing_session->get()->StopBlocking();
1933 auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
1934 EXPECT_THAT(log_messages, ElementsAre("This above all:"));
1935 }
1936
1937 struct InternedLogMessageBodyHashed
1938 : public perfetto::TrackEventInternedDataIndex<
1939 InternedLogMessageBodyHashed,
1940 perfetto::protos::pbzero::InternedData::kLogMessageBodyFieldNumber,
1941 std::string,
1942 perfetto::HashedInternedDataTraits> {
Add__anone89577de0111::InternedLogMessageBodyHashed1943 static void Add(perfetto::protos::pbzero::InternedData* interned_data,
1944 size_t iid,
1945 const std::string& value) {
1946 auto l = interned_data->add_log_message_body();
1947 l->set_iid(iid);
1948 l->set_body(value.data(), value.size());
1949 }
1950 };
1951
TEST_P(PerfettoApiTest,TrackEventTypedArgsWithInterningByHashing)1952 TEST_P(PerfettoApiTest, TrackEventTypedArgsWithInterningByHashing) {
1953 // Create a new trace session.
1954 auto* tracing_session = NewTraceWithCategories({"foo"});
1955 tracing_session->get()->StartBlocking();
1956
1957 size_t body_iid;
1958 TRACE_EVENT_BEGIN("foo", "EventWithState", [&](perfetto::EventContext ctx) {
1959 // Test using a dynamically created interned value.
1960 body_iid = InternedLogMessageBodyHashed::Get(
1961 &ctx, std::string("Though this ") + "be madness,");
1962 auto log = ctx.event()->set_log_message();
1963 log->set_body_iid(body_iid);
1964
1965 auto body_iid2 =
1966 InternedLogMessageBodyHashed::Get(&ctx, "Though this be madness,");
1967 EXPECT_EQ(body_iid, body_iid2);
1968
1969 auto body_iid3 =
1970 InternedLogMessageBodyHashed::Get(&ctx, "yet there is method in’t");
1971 EXPECT_NE(body_iid, body_iid3);
1972 });
1973 TRACE_EVENT_END("foo");
1974
1975 tracing_session->get()->StopBlocking();
1976 auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
1977 EXPECT_THAT(log_messages, ElementsAre("Though this be madness,"));
1978 }
1979
1980 struct InternedSourceLocation
1981 : public perfetto::TrackEventInternedDataIndex<
1982 InternedSourceLocation,
1983 perfetto::protos::pbzero::InternedData::kSourceLocationsFieldNumber,
1984 SourceLocation> {
Add__anone89577de0111::InternedSourceLocation1985 static void Add(perfetto::protos::pbzero::InternedData* interned_data,
1986 size_t iid,
1987 const SourceLocation& value) {
1988 auto l = interned_data->add_source_locations();
1989 auto file_name = std::get<0>(value);
1990 auto function_name = std::get<1>(value);
1991 auto line_number = std::get<2>(value);
1992 l->set_iid(iid);
1993 l->set_file_name(file_name);
1994 l->set_function_name(function_name);
1995 l->set_line_number(line_number);
1996 }
1997 };
1998
TEST_P(PerfettoApiTest,TrackEventTypedArgsWithInterningComplexValue)1999 TEST_P(PerfettoApiTest, TrackEventTypedArgsWithInterningComplexValue) {
2000 // Create a new trace session.
2001 auto* tracing_session = NewTraceWithCategories({"foo"});
2002 tracing_session->get()->StartBlocking();
2003
2004 TRACE_EVENT_BEGIN("foo", "EventWithState", [&](perfetto::EventContext ctx) {
2005 const SourceLocation location{"file.cc", "SomeFunction", 123};
2006 auto location_iid = InternedSourceLocation::Get(&ctx, location);
2007 auto body_iid = InternedLogMessageBody::Get(&ctx, "To be, or not to be");
2008 auto log = ctx.event()->set_log_message();
2009 log->set_source_location_iid(location_iid);
2010 log->set_body_iid(body_iid);
2011
2012 auto location_iid2 = InternedSourceLocation::Get(&ctx, location);
2013 EXPECT_EQ(location_iid, location_iid2);
2014
2015 const SourceLocation location2{"file.cc", "SomeFunction", 456};
2016 auto location_iid3 = InternedSourceLocation::Get(&ctx, location2);
2017 EXPECT_NE(location_iid, location_iid3);
2018 });
2019 TRACE_EVENT_END("foo");
2020
2021 tracing_session->get()->StopBlocking();
2022 auto log_messages = ReadLogMessagesFromTrace(tracing_session->get());
2023 EXPECT_THAT(log_messages,
2024 ElementsAre("SomeFunction(file.cc:123): To be, or not to be"));
2025 }
2026
TEST_P(PerfettoApiTest,TrackEventScoped)2027 TEST_P(PerfettoApiTest, TrackEventScoped) {
2028 // Create a new trace session.
2029 auto* tracing_session = NewTraceWithCategories({"test"});
2030 tracing_session->get()->StartBlocking();
2031
2032 {
2033 uint64_t arg = 123;
2034 TRACE_EVENT("test", "TestEventWithArgs", [&](perfetto::EventContext ctx) {
2035 ctx.event()->set_log_message()->set_body_iid(arg);
2036 });
2037 }
2038
2039 // Ensure a single line if statement counts as a valid scope for the macro.
2040 if (true)
2041 TRACE_EVENT("test", "SingleLineTestEvent");
2042
2043 {
2044 // Make sure you can have multiple scoped events in the same scope.
2045 TRACE_EVENT("test", "TestEvent");
2046 TRACE_EVENT("test", "AnotherEvent");
2047 TRACE_EVENT("foo", "DisabledEvent");
2048 }
2049 perfetto::TrackEvent::Flush();
2050
2051 tracing_session->get()->StopBlocking();
2052 auto slices = ReadSlicesFromTrace(tracing_session->get());
2053 EXPECT_THAT(
2054 slices,
2055 ElementsAre("B:test.TestEventWithArgs", "E", "B:test.SingleLineTestEvent",
2056 "E", "B:test.TestEvent", "B:test.AnotherEvent", "E", "E"));
2057 }
2058
2059 // A class similar to what Protozero generates for extended message.
2060 class TestTrackEvent : public perfetto::protos::pbzero::TrackEvent {
2061 public:
2062 static const int field_number = 9901;
2063
set_extension_value(int value)2064 void set_extension_value(int value) {
2065 // 9900-10000 is the range of extension field numbers reserved for testing.
2066 AppendTinyVarInt(field_number, value);
2067 }
2068 };
2069
TEST_P(PerfettoApiTest,ExtensionClass)2070 TEST_P(PerfettoApiTest, ExtensionClass) {
2071 auto* tracing_session = NewTraceWithCategories({"test"});
2072 tracing_session->get()->StartBlocking();
2073
2074 {
2075 TRACE_EVENT("test", "TestEventWithExtensionArgs",
2076 [&](perfetto::EventContext ctx) {
2077 ctx.event<perfetto::protos::pbzero::TestExtension>()
2078 ->add_int_extension_for_testing(42);
2079 });
2080 }
2081
2082 perfetto::TrackEvent::Flush();
2083 tracing_session->get()->StopBlocking();
2084
2085 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2086 EXPECT_GE(raw_trace.size(), 0u);
2087
2088 bool found_extension = false;
2089 perfetto::protos::pbzero::Trace_Decoder trace(
2090 reinterpret_cast<uint8_t*>(raw_trace.data()), raw_trace.size());
2091
2092 for (auto it = trace.packet(); it; ++it) {
2093 perfetto::protos::pbzero::TracePacket_Decoder packet(it->data(),
2094 it->size());
2095
2096 if (!packet.has_track_event())
2097 continue;
2098
2099 auto track_event = packet.track_event();
2100 protozero::ProtoDecoder decoder(track_event.data, track_event.size);
2101
2102 for (protozero::Field f = decoder.ReadField(); f.valid();
2103 f = decoder.ReadField()) {
2104 if (f.id() == perfetto::protos::pbzero::TestExtension::
2105 FieldMetadata_IntExtensionForTesting::kFieldId) {
2106 found_extension = true;
2107 }
2108 }
2109 }
2110
2111 EXPECT_TRUE(found_extension);
2112 }
2113
TEST_P(PerfettoApiTest,InlineTypedExtensionField)2114 TEST_P(PerfettoApiTest, InlineTypedExtensionField) {
2115 auto* tracing_session = NewTraceWithCategories({"test"});
2116 tracing_session->get()->StartBlocking();
2117
2118 {
2119 TRACE_EVENT(
2120 "test", "TestEventWithExtensionArgs",
2121 perfetto::protos::pbzero::TestExtension::kIntExtensionForTesting,
2122 std::vector<int>{42});
2123 }
2124
2125 perfetto::TrackEvent::Flush();
2126 tracing_session->get()->StopBlocking();
2127
2128 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2129 EXPECT_GE(raw_trace.size(), 0u);
2130
2131 bool found_extension = false;
2132 perfetto::protos::pbzero::Trace_Decoder trace(
2133 reinterpret_cast<uint8_t*>(raw_trace.data()), raw_trace.size());
2134
2135 for (auto it = trace.packet(); it; ++it) {
2136 perfetto::protos::pbzero::TracePacket_Decoder packet(it->data(),
2137 it->size());
2138
2139 if (!packet.has_track_event())
2140 continue;
2141
2142 auto track_event = packet.track_event();
2143 protozero::ProtoDecoder decoder(track_event.data, track_event.size);
2144
2145 for (protozero::Field f = decoder.ReadField(); f.valid();
2146 f = decoder.ReadField()) {
2147 if (f.id() == perfetto::protos::pbzero::TestExtension::
2148 FieldMetadata_IntExtensionForTesting::kFieldId) {
2149 found_extension = true;
2150 }
2151 }
2152 }
2153
2154 EXPECT_TRUE(found_extension);
2155 }
2156
TEST_P(PerfettoApiTest,TrackEventInstant)2157 TEST_P(PerfettoApiTest, TrackEventInstant) {
2158 // Create a new trace session.
2159 auto* tracing_session = NewTraceWithCategories({"test"});
2160 tracing_session->get()->StartBlocking();
2161
2162 TRACE_EVENT_INSTANT("test", "TestEvent");
2163 TRACE_EVENT_INSTANT("test", "AnotherEvent");
2164 perfetto::TrackEvent::Flush();
2165
2166 tracing_session->get()->StopBlocking();
2167 auto slices = ReadSlicesFromTrace(tracing_session->get());
2168 EXPECT_THAT(slices, ElementsAre("I:test.TestEvent", "I:test.AnotherEvent"));
2169 }
2170
TEST_P(PerfettoApiTest,TrackEventDefaultGlobalTrack)2171 TEST_P(PerfettoApiTest, TrackEventDefaultGlobalTrack) {
2172 // Create a new trace session.
2173 auto* tracing_session = NewTraceWithCategories({"test"});
2174 tracing_session->get()->StartBlocking();
2175
2176 TRACE_EVENT_INSTANT("test", "ThreadEvent");
2177 TRACE_EVENT_INSTANT("test", "GlobalEvent", perfetto::Track::Global(0u));
2178 perfetto::TrackEvent::Flush();
2179
2180 tracing_session->get()->StopBlocking();
2181 auto slices = ReadSlicesFromTrace(tracing_session->get());
2182 EXPECT_THAT(slices,
2183 ElementsAre("I:test.ThreadEvent", "[track=0]I:test.GlobalEvent"));
2184 }
2185
TEST_P(PerfettoApiTest,TrackEventTrackFromPointer)2186 TEST_P(PerfettoApiTest, TrackEventTrackFromPointer) {
2187 // Create a new trace session.
2188 auto* tracing_session = NewTraceWithCategories({"test"});
2189 tracing_session->get()->StartBlocking();
2190
2191 perfetto::Track parent_track(1);
2192 int* ptr = reinterpret_cast<int*>(2);
2193 TRACE_EVENT_INSTANT("test", "Event",
2194 perfetto::Track::FromPointer(ptr, parent_track));
2195 perfetto::TrackEvent::Flush();
2196
2197 perfetto::Track track(reinterpret_cast<uintptr_t>(ptr), parent_track);
2198
2199 tracing_session->get()->StopBlocking();
2200 auto slices = ReadSlicesFromTrace(tracing_session->get());
2201 EXPECT_THAT(slices, ElementsAre("[track=" + std::to_string(track.uuid) +
2202 "]I:test.Event"));
2203 }
2204
TEST_P(PerfettoApiTest,TrackEventDebugAnnotations)2205 TEST_P(PerfettoApiTest, TrackEventDebugAnnotations) {
2206 // Create a new trace session.
2207 auto* tracing_session = NewTraceWithCategories({"test"});
2208 tracing_session->get()->StartBlocking();
2209
2210 enum MyEnum : uint32_t { ENUM_FOO, ENUM_BAR };
2211 enum MySignedEnum : int32_t { SIGNED_ENUM_FOO = -1, SIGNED_ENUM_BAR };
2212 enum class MyClassEnum { VALUE };
2213
2214 TRACE_EVENT_BEGIN("test", "E", "bool_arg", false);
2215 TRACE_EVENT_BEGIN("test", "E", "int_arg", -123);
2216 TRACE_EVENT_BEGIN("test", "E", "uint_arg", 456u);
2217 TRACE_EVENT_BEGIN("test", "E", "float_arg", 3.14159262f);
2218 TRACE_EVENT_BEGIN("test", "E", "double_arg", 6.22);
2219 TRACE_EVENT_BEGIN("test", "E", "str_arg", "hello", "str_arg2",
2220 std::string("tracing"));
2221 TRACE_EVENT_BEGIN("test", "E", "ptr_arg",
2222 reinterpret_cast<void*>(static_cast<intptr_t>(0xbaadf00d)));
2223 TRACE_EVENT_BEGIN("test", "E", "size_t_arg", size_t{42});
2224 TRACE_EVENT_BEGIN("test", "E", "ptrdiff_t_arg", ptrdiff_t{-7});
2225 TRACE_EVENT_BEGIN("test", "E", "enum_arg", ENUM_BAR);
2226 TRACE_EVENT_BEGIN("test", "E", "signed_enum_arg", SIGNED_ENUM_FOO);
2227 TRACE_EVENT_BEGIN("test", "E", "class_enum_arg", MyClassEnum::VALUE);
2228 TRACE_EVENT_BEGIN("test", "E", "traced_value",
2229 [&](perfetto::TracedValue context) {
2230 std::move(context).WriteInt64(42);
2231 });
2232 perfetto::TrackEvent::Flush();
2233
2234 tracing_session->get()->StopBlocking();
2235 auto slices = ReadSlicesFromTrace(tracing_session->get());
2236 EXPECT_THAT(
2237 slices,
2238 ElementsAre(
2239 "B:test.E(bool_arg=(bool)0)", "B:test.E(int_arg=(int)-123)",
2240 "B:test.E(uint_arg=(uint)456)", "B:test.E(float_arg=(double)3.14159)",
2241 "B:test.E(double_arg=(double)6.22)",
2242 "B:test.E(str_arg=(string)hello,str_arg2=(string)tracing)",
2243 "B:test.E(ptr_arg=(pointer)baadf00d)",
2244 "B:test.E(size_t_arg=(uint)42)", "B:test.E(ptrdiff_t_arg=(int)-7)",
2245 "B:test.E(enum_arg=(uint)1)", "B:test.E(signed_enum_arg=(int)-1)",
2246 "B:test.E(class_enum_arg=(int)0)", "B:test.E(traced_value=(int)42)"));
2247 }
2248
TEST_P(PerfettoApiTest,TrackEventCustomDebugAnnotations)2249 TEST_P(PerfettoApiTest, TrackEventCustomDebugAnnotations) {
2250 // Create a new trace session.
2251 auto* tracing_session = NewTraceWithCategories({"test"});
2252 tracing_session->get()->StartBlocking();
2253
2254 std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
2255
2256 TRACE_EVENT_BEGIN("test", "E", "custom_arg", MyDebugAnnotation());
2257 TRACE_EVENT_BEGIN("test", "E", "normal_arg", "x", "custom_arg",
2258 std::move(owned_annotation));
2259 perfetto::TrackEvent::Flush();
2260
2261 tracing_session->get()->StopBlocking();
2262 auto slices = ReadSlicesFromTrace(tracing_session->get());
2263 EXPECT_THAT(
2264 slices,
2265 ElementsAre(
2266 R"(B:test.E(custom_arg=(json){"key": 123}))",
2267 R"(B:test.E(normal_arg=(string)x,custom_arg=(json){"key": 123}))"));
2268 }
2269
TEST_P(PerfettoApiTest,TrackEventCustomRawDebugAnnotations)2270 TEST_P(PerfettoApiTest, TrackEventCustomRawDebugAnnotations) {
2271 // Note: this class is also testing a non-moveable and non-copiable argument.
2272 class MyRawDebugAnnotation : public perfetto::DebugAnnotation {
2273 public:
2274 MyRawDebugAnnotation() { msg_->set_string_value("nested_value"); }
2275 ~MyRawDebugAnnotation() = default;
2276
2277 // |msg_| already deletes these implicitly, but let's be explicit for safety
2278 // against future changes.
2279 MyRawDebugAnnotation(const MyRawDebugAnnotation&) = delete;
2280 MyRawDebugAnnotation(MyRawDebugAnnotation&&) = delete;
2281
2282 void Add(perfetto::protos::pbzero::DebugAnnotation* annotation) const {
2283 auto ranges = msg_.GetRanges();
2284 annotation->AppendScatteredBytes(
2285 perfetto::protos::pbzero::DebugAnnotation::kNestedValueFieldNumber,
2286 &ranges[0], ranges.size());
2287 }
2288
2289 private:
2290 mutable protozero::HeapBuffered<
2291 perfetto::protos::pbzero::DebugAnnotation::NestedValue>
2292 msg_;
2293 };
2294
2295 // Create a new trace session.
2296 auto* tracing_session = NewTraceWithCategories({"test"});
2297 tracing_session->get()->StartBlocking();
2298
2299 TRACE_EVENT_BEGIN("test", "E", "raw_arg", MyRawDebugAnnotation());
2300 TRACE_EVENT_BEGIN("test", "E", "plain_arg", 42, "raw_arg",
2301 MyRawDebugAnnotation());
2302 perfetto::TrackEvent::Flush();
2303
2304 tracing_session->get()->StopBlocking();
2305 auto slices = ReadSlicesFromTrace(tracing_session->get());
2306 EXPECT_THAT(
2307 slices,
2308 ElementsAre("B:test.E(raw_arg=(nested)nested_value)",
2309 "B:test.E(plain_arg=(int)42,raw_arg=(nested)nested_value)"));
2310 }
2311
TEST_P(PerfettoApiTest,ManyDebugAnnotations)2312 TEST_P(PerfettoApiTest, ManyDebugAnnotations) {
2313 // Create a new trace session.
2314 auto* tracing_session = NewTraceWithCategories({"test"});
2315 tracing_session->get()->StartBlocking();
2316
2317 TRACE_EVENT_BEGIN("test", "E", "arg1", 1, "arg2", 2, "arg3", 3);
2318 perfetto::TrackEvent::Flush();
2319
2320 tracing_session->get()->StopBlocking();
2321 auto slices = ReadSlicesFromTrace(tracing_session->get());
2322 EXPECT_THAT(slices,
2323 ElementsAre("B:test.E(arg1=(int)1,arg2=(int)2,arg3=(int)3)"));
2324 }
2325
TEST_P(PerfettoApiTest,DebugAnnotationAndLambda)2326 TEST_P(PerfettoApiTest, DebugAnnotationAndLambda) {
2327 // Create a new trace session.
2328 auto* tracing_session = NewTraceWithCategories({"test"});
2329 tracing_session->get()->StartBlocking();
2330
2331 enum MyEnum : uint32_t { ENUM_FOO, ENUM_BAR };
2332 enum MySignedEnum : int32_t { SIGNED_ENUM_FOO = -1, SIGNED_ENUM_BAR };
2333 enum class MyClassEnum { VALUE };
2334
2335 TRACE_EVENT_BEGIN(
2336 "test", "E", "key", "value", [](perfetto::EventContext ctx) {
2337 ctx.event()->set_log_message()->set_source_location_iid(42);
2338 });
2339 perfetto::TrackEvent::Flush();
2340
2341 tracing_session->get()->StopBlocking();
2342 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2343 std::string trace(raw_trace.data(), raw_trace.size());
2344
2345 perfetto::protos::gen::Trace parsed_trace;
2346 ASSERT_TRUE(parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
2347
2348 bool found_args = false;
2349 for (const auto& packet : parsed_trace.packet()) {
2350 if (!packet.has_track_event())
2351 continue;
2352 const auto& track_event = packet.track_event();
2353 if (track_event.type() !=
2354 perfetto::protos::gen::TrackEvent::TYPE_SLICE_BEGIN)
2355 continue;
2356
2357 EXPECT_TRUE(track_event.has_log_message());
2358 const auto& log = track_event.log_message();
2359 EXPECT_EQ(42u, log.source_location_iid());
2360
2361 const auto& dbg = track_event.debug_annotations()[0];
2362 EXPECT_EQ("value", dbg.string_value());
2363
2364 found_args = true;
2365 }
2366 EXPECT_TRUE(found_args);
2367 }
2368
TEST_P(PerfettoApiTest,TrackEventComputedName)2369 TEST_P(PerfettoApiTest, TrackEventComputedName) {
2370 // Setup the trace config.
2371 perfetto::TraceConfig cfg;
2372 cfg.set_duration_ms(500);
2373 cfg.add_buffers()->set_size_kb(1024);
2374 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2375 ds_cfg->set_name("track_event");
2376
2377 // Create a new trace session.
2378 auto* tracing_session = NewTrace(cfg);
2379 tracing_session->get()->StartBlocking();
2380
2381 // New macros require perfetto::StaticString{} annotation.
2382 for (int i = 0; i < 3; i++)
2383 TRACE_EVENT_BEGIN("test", perfetto::StaticString{i % 2 ? "Odd" : "Even"});
2384
2385 // Legacy macros assume all arguments are static strings.
2386 for (int i = 0; i < 3; i++)
2387 TRACE_EVENT_BEGIN0("test", i % 2 ? "Odd" : "Even");
2388
2389 perfetto::TrackEvent::Flush();
2390
2391 tracing_session->get()->StopBlocking();
2392 auto slices = ReadSlicesFromTrace(tracing_session->get());
2393 EXPECT_THAT(slices, ElementsAre("B:test.Even", "B:test.Odd", "B:test.Even",
2394 "B:test.Even", "B:test.Odd", "B:test.Even"));
2395 }
2396
TEST_P(PerfettoApiTest,TrackEventArgumentsNotEvaluatedWhenDisabled)2397 TEST_P(PerfettoApiTest, TrackEventArgumentsNotEvaluatedWhenDisabled) {
2398 // Create a new trace session.
2399 auto* tracing_session = NewTraceWithCategories({"foo"});
2400 tracing_session->get()->StartBlocking();
2401
2402 bool called = false;
2403 auto ArgumentFunction = [&] {
2404 called = true;
2405 return 123;
2406 };
2407
2408 TRACE_EVENT_BEGIN("test", "DisabledEvent", "arg", ArgumentFunction());
2409 { TRACE_EVENT("test", "DisabledScopedEvent", "arg", ArgumentFunction()); }
2410 perfetto::TrackEvent::Flush();
2411
2412 tracing_session->get()->StopBlocking();
2413 EXPECT_FALSE(called);
2414
2415 ArgumentFunction();
2416 EXPECT_TRUE(called);
2417 }
2418
TEST_P(PerfettoApiTest,TrackEventConfig)2419 TEST_P(PerfettoApiTest, TrackEventConfig) {
2420 auto check_config = [&](perfetto::protos::gen::TrackEventConfig te_cfg) {
2421 perfetto::TraceConfig cfg;
2422 cfg.set_duration_ms(500);
2423 cfg.add_buffers()->set_size_kb(1024);
2424 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2425 ds_cfg->set_name("track_event");
2426 ds_cfg->set_track_event_config_raw(te_cfg.SerializeAsString());
2427
2428 auto* tracing_session = NewTrace(cfg);
2429 tracing_session->get()->StartBlocking();
2430
2431 TRACE_EVENT_BEGIN("foo", "FooEvent");
2432 TRACE_EVENT_BEGIN("bar", "BarEvent");
2433 TRACE_EVENT_BEGIN("foo,bar", "MultiFooBar");
2434 TRACE_EVENT_BEGIN("baz,bar,quux", "MultiBar");
2435 TRACE_EVENT_BEGIN("red,green,blue,foo", "MultiFoo");
2436 TRACE_EVENT_BEGIN("red,green,blue,yellow", "MultiNone");
2437 TRACE_EVENT_BEGIN("cat", "SlowEvent");
2438 TRACE_EVENT_BEGIN("cat.verbose", "DebugEvent");
2439 TRACE_EVENT_BEGIN("test", "TagEvent");
2440 TRACE_EVENT_BEGIN(TRACE_DISABLED_BY_DEFAULT("cat"), "SlowDisabledEvent");
2441 TRACE_EVENT_BEGIN("dynamic,foo", "DynamicGroupFooEvent");
2442 perfetto::DynamicCategory dyn{"dynamic,bar"};
2443 TRACE_EVENT_BEGIN(dyn, "DynamicGroupBarEvent");
2444
2445 perfetto::TrackEvent::Flush();
2446 tracing_session->get()->StopBlocking();
2447 auto slices = ReadSlicesFromTrace(tracing_session->get());
2448 tracing_session->session.reset();
2449 return slices;
2450 };
2451
2452 // Empty config should enable all categories except slow ones.
2453 {
2454 perfetto::protos::gen::TrackEventConfig te_cfg;
2455 auto slices = check_config(te_cfg);
2456 EXPECT_THAT(
2457 slices,
2458 ElementsAre("B:foo.FooEvent", "B:bar.BarEvent", "B:foo,bar.MultiFooBar",
2459 "B:baz,bar,quux.MultiBar", "B:red,green,blue,foo.MultiFoo",
2460 "B:red,green,blue,yellow.MultiNone", "B:test.TagEvent",
2461 "B:$dynamic,$foo.DynamicGroupFooEvent",
2462 "B:$dynamic,$bar.DynamicGroupBarEvent"));
2463 }
2464
2465 // Enable exactly one category.
2466 {
2467 perfetto::protos::gen::TrackEventConfig te_cfg;
2468 te_cfg.add_disabled_categories("*");
2469 te_cfg.add_enabled_categories("foo");
2470 auto slices = check_config(te_cfg);
2471 EXPECT_THAT(slices, ElementsAre("B:foo.FooEvent", "B:foo,bar.MultiFooBar",
2472 "B:red,green,blue,foo.MultiFoo",
2473 "B:$dynamic,$foo.DynamicGroupFooEvent"));
2474 }
2475
2476 // Enable exactly one dynamic category.
2477 {
2478 perfetto::protos::gen::TrackEventConfig te_cfg;
2479 te_cfg.add_disabled_categories("*");
2480 te_cfg.add_enabled_categories("dynamic");
2481 auto slices = check_config(te_cfg);
2482 EXPECT_THAT(slices, ElementsAre("B:$dynamic,$foo.DynamicGroupFooEvent",
2483 "B:$dynamic,$bar.DynamicGroupBarEvent"));
2484 }
2485
2486 // Enable two categories.
2487 {
2488 perfetto::protos::gen::TrackEventConfig te_cfg;
2489 te_cfg.add_disabled_categories("*");
2490 te_cfg.add_enabled_categories("foo");
2491 te_cfg.add_enabled_categories("baz");
2492 te_cfg.add_enabled_categories("bar");
2493 auto slices = check_config(te_cfg);
2494 EXPECT_THAT(
2495 slices,
2496 ElementsAre("B:foo.FooEvent", "B:bar.BarEvent", "B:foo,bar.MultiFooBar",
2497 "B:baz,bar,quux.MultiBar", "B:red,green,blue,foo.MultiFoo",
2498 "B:$dynamic,$foo.DynamicGroupFooEvent",
2499 "B:$dynamic,$bar.DynamicGroupBarEvent"));
2500 }
2501
2502 // Enabling all categories with a pattern doesn't enable slow ones.
2503 {
2504 perfetto::protos::gen::TrackEventConfig te_cfg;
2505 te_cfg.add_enabled_categories("*");
2506 auto slices = check_config(te_cfg);
2507 EXPECT_THAT(
2508 slices,
2509 ElementsAre("B:foo.FooEvent", "B:bar.BarEvent", "B:foo,bar.MultiFooBar",
2510 "B:baz,bar,quux.MultiBar", "B:red,green,blue,foo.MultiFoo",
2511 "B:red,green,blue,yellow.MultiNone", "B:test.TagEvent",
2512 "B:$dynamic,$foo.DynamicGroupFooEvent",
2513 "B:$dynamic,$bar.DynamicGroupBarEvent"));
2514 }
2515
2516 // Enable with a pattern.
2517 {
2518 perfetto::protos::gen::TrackEventConfig te_cfg;
2519 te_cfg.add_disabled_categories("*");
2520 te_cfg.add_enabled_categories("fo*");
2521 auto slices = check_config(te_cfg);
2522 EXPECT_THAT(slices, ElementsAre("B:foo.FooEvent", "B:foo,bar.MultiFooBar",
2523 "B:red,green,blue,foo.MultiFoo",
2524 "B:$dynamic,$foo.DynamicGroupFooEvent"));
2525 }
2526
2527 // Enable with a tag.
2528 {
2529 perfetto::protos::gen::TrackEventConfig te_cfg;
2530 te_cfg.add_disabled_categories("*");
2531 te_cfg.add_enabled_tags("tag");
2532 auto slices = check_config(te_cfg);
2533 EXPECT_THAT(slices, ElementsAre("B:test.TagEvent"));
2534 }
2535
2536 // Enable just slow categories.
2537 {
2538 perfetto::protos::gen::TrackEventConfig te_cfg;
2539 te_cfg.add_disabled_categories("*");
2540 te_cfg.add_enabled_tags("slow");
2541 auto slices = check_config(te_cfg);
2542 EXPECT_THAT(slices,
2543 ElementsAre("B:cat.SlowEvent",
2544 "B:disabled-by-default-cat.SlowDisabledEvent"));
2545 }
2546
2547 // Enable everything including slow/debug categories.
2548 {
2549 perfetto::protos::gen::TrackEventConfig te_cfg;
2550 te_cfg.add_enabled_categories("*");
2551 te_cfg.add_enabled_tags("slow");
2552 te_cfg.add_enabled_tags("debug");
2553 auto slices = check_config(te_cfg);
2554 EXPECT_THAT(
2555 slices,
2556 ElementsAre("B:foo.FooEvent", "B:bar.BarEvent", "B:foo,bar.MultiFooBar",
2557 "B:baz,bar,quux.MultiBar", "B:red,green,blue,foo.MultiFoo",
2558 "B:red,green,blue,yellow.MultiNone", "B:cat.SlowEvent",
2559 "B:cat.verbose.DebugEvent", "B:test.TagEvent",
2560 "B:disabled-by-default-cat.SlowDisabledEvent",
2561 "B:$dynamic,$foo.DynamicGroupFooEvent",
2562 "B:$dynamic,$bar.DynamicGroupBarEvent"));
2563 }
2564 }
2565
TEST_P(PerfettoApiTest,OneDataSourceOneEvent)2566 TEST_P(PerfettoApiTest, OneDataSourceOneEvent) {
2567 auto* data_source = &data_sources_["my_data_source"];
2568
2569 // Setup the trace config.
2570 perfetto::TraceConfig cfg;
2571 cfg.set_duration_ms(500);
2572 cfg.add_buffers()->set_size_kb(1024);
2573 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2574 ds_cfg->set_name("my_data_source");
2575 ds_cfg->set_legacy_config("test config");
2576
2577 // Create a new trace session.
2578 auto* tracing_session = NewTrace(cfg);
2579
2580 MockDataSource::Trace([](MockDataSource::TraceContext) {
2581 FAIL() << "Should not be called because the trace was not started";
2582 });
2583 MockDataSource::CallIfEnabled([](uint32_t) {
2584 FAIL() << "Should not be called because the trace was not started";
2585 });
2586
2587 tracing_session->get()->Start();
2588 data_source->on_setup.Wait();
2589 EXPECT_EQ(data_source->config.legacy_config(), "test config");
2590 data_source->on_start.Wait();
2591
2592 // Emit one trace event.
2593 std::atomic<int> trace_lambda_calls{0};
2594 MockDataSource::Trace(
2595 [&trace_lambda_calls](MockDataSource::TraceContext ctx) {
2596 auto packet = ctx.NewTracePacket();
2597 packet->set_timestamp(42);
2598 packet->set_for_testing()->set_str("event 1");
2599 trace_lambda_calls++;
2600 packet->Finalize();
2601
2602 // The SMB scraping logic will skip the last packet because it cannot
2603 // guarantee it's finalized. Create an empty packet so we get the
2604 // previous one and this empty one is ignored.
2605 packet = ctx.NewTracePacket();
2606 });
2607
2608 uint32_t active_instances = 0;
2609 MockDataSource::CallIfEnabled([&active_instances](uint32_t instances) {
2610 active_instances = instances;
2611 });
2612 EXPECT_EQ(1u, active_instances);
2613
2614 data_source->on_stop.Wait();
2615 tracing_session->on_stop.Wait();
2616 EXPECT_EQ(trace_lambda_calls, 1);
2617
2618 MockDataSource::Trace([](MockDataSource::TraceContext) {
2619 FAIL() << "Should not be called because the trace is now stopped";
2620 });
2621 MockDataSource::CallIfEnabled([](uint32_t) {
2622 FAIL() << "Should not be called because the trace is now stopped";
2623 });
2624
2625 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2626 ASSERT_GE(raw_trace.size(), 0u);
2627
2628 perfetto::protos::gen::Trace trace;
2629 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
2630 bool test_packet_found = false;
2631 for (const auto& packet : trace.packet()) {
2632 if (!packet.has_for_testing())
2633 continue;
2634 EXPECT_FALSE(test_packet_found);
2635 EXPECT_EQ(packet.timestamp(), 42U);
2636 EXPECT_EQ(packet.for_testing().str(), "event 1");
2637 test_packet_found = true;
2638 }
2639 EXPECT_TRUE(test_packet_found);
2640 }
2641
TEST_P(PerfettoApiTest,ReentrantTracing)2642 TEST_P(PerfettoApiTest, ReentrantTracing) {
2643 auto* data_source = &data_sources_["my_data_source"];
2644
2645 // Setup the trace config.
2646 perfetto::TraceConfig cfg;
2647 cfg.set_duration_ms(500);
2648 cfg.add_buffers()->set_size_kb(1024);
2649 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2650 ds_cfg->set_name("my_data_source");
2651
2652 // Create a new trace session.
2653 auto* tracing_session = NewTrace(cfg);
2654 tracing_session->get()->Start();
2655 data_source->on_start.Wait();
2656
2657 // Check that only one level of trace lambda calls is allowed.
2658 std::atomic<int> trace_lambda_calls{0};
2659 MockDataSource::Trace([&trace_lambda_calls](MockDataSource::TraceContext) {
2660 trace_lambda_calls++;
2661 MockDataSource::Trace([&trace_lambda_calls](MockDataSource::TraceContext) {
2662 trace_lambda_calls++;
2663 });
2664 });
2665
2666 tracing_session->get()->StopBlocking();
2667 EXPECT_EQ(trace_lambda_calls, 1);
2668 }
2669
TEST_P(PerfettoApiTest,ConsumerFlush)2670 TEST_P(PerfettoApiTest, ConsumerFlush) {
2671 auto* data_source = &data_sources_["my_data_source"];
2672
2673 // Setup the trace config.
2674 perfetto::TraceConfig cfg;
2675 cfg.add_buffers()->set_size_kb(1024);
2676 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2677 ds_cfg->set_name("my_data_source");
2678 ds_cfg->set_legacy_config("test config");
2679
2680 // Create a new trace session.
2681 auto* tracing_session = NewTrace(cfg);
2682
2683 tracing_session->get()->Start();
2684 data_source->on_start.Wait();
2685
2686 MockDataSource::Trace([&](MockDataSource::TraceContext ctx) {
2687 auto packet = ctx.NewTracePacket();
2688 packet->set_timestamp(42);
2689 packet->set_for_testing()->set_str("flushed event");
2690 packet->Finalize();
2691
2692 // The SMB scraping logic will skip the last packet because it cannot
2693 // guarantee it's finalized. Create an empty packet so we get the
2694 // previous one and this empty one is ignored.
2695 packet = ctx.NewTracePacket();
2696 });
2697
2698 EXPECT_TRUE(tracing_session->get()->FlushBlocking());
2699
2700 // Deliberately doing ReadTraceBlocking() before StopBlocking() to avoid
2701 // hitting the auto scrape-on-stop behavior of the service.
2702 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2703 tracing_session->get()->StopBlocking();
2704
2705 ASSERT_GE(raw_trace.size(), 0u);
2706 perfetto::protos::gen::Trace trace;
2707 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
2708 bool test_packet_found = false;
2709 for (const auto& packet : trace.packet()) {
2710 if (!packet.has_for_testing())
2711 continue;
2712 EXPECT_FALSE(test_packet_found);
2713 EXPECT_EQ(packet.timestamp(), 42U);
2714 EXPECT_EQ(packet.for_testing().str(), "flushed event");
2715 test_packet_found = true;
2716 }
2717 EXPECT_TRUE(test_packet_found);
2718 }
2719
TEST_P(PerfettoApiTest,WithBatching)2720 TEST_P(PerfettoApiTest, WithBatching) {
2721 auto* data_source = &data_sources_["my_data_source"];
2722
2723 // Setup the trace config.
2724 perfetto::TraceConfig cfg;
2725 cfg.set_duration_ms(500);
2726 cfg.add_buffers()->set_size_kb(1024);
2727 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2728 ds_cfg->set_name("my_data_source");
2729 ds_cfg->set_legacy_config("test config");
2730
2731 // Create a new trace session.
2732 auto* tracing_session = NewTrace(cfg);
2733
2734 tracing_session->get()->Start();
2735 data_source->on_setup.Wait();
2736 data_source->on_start.Wait();
2737
2738 std::stringstream first_large_message;
2739 for (size_t i = 0; i < 512; i++)
2740 first_large_message << i << ". Something wicked this way comes. ";
2741 auto first_large_message_str = first_large_message.str();
2742
2743 // Emit one trace event before we begin batching.
2744 MockDataSource::Trace(
2745 [&first_large_message_str](MockDataSource::TraceContext ctx) {
2746 auto packet = ctx.NewTracePacket();
2747 packet->set_timestamp(42);
2748 packet->set_for_testing()->set_str(first_large_message_str);
2749 packet->Finalize();
2750 });
2751
2752 // Simulate the start of a batching cycle by first setting the batching period
2753 // to a very large value and then force-flushing when we are done writing
2754 // data.
2755 ASSERT_TRUE(
2756 perfetto::test::EnableDirectSMBPatching(/*BackendType=*/GetParam()));
2757 perfetto::test::SetBatchCommitsDuration(UINT32_MAX,
2758 /*BackendType=*/GetParam());
2759
2760 std::stringstream second_large_message;
2761 for (size_t i = 0; i < 512; i++)
2762 second_large_message << i << ". Something else wicked this way comes. ";
2763 auto second_large_message_str = second_large_message.str();
2764
2765 // Emit another trace event.
2766 MockDataSource::Trace(
2767 [&second_large_message_str](MockDataSource::TraceContext ctx) {
2768 auto packet = ctx.NewTracePacket();
2769 packet->set_timestamp(43);
2770 packet->set_for_testing()->set_str(second_large_message_str);
2771 packet->Finalize();
2772
2773 // Simulate the end of the batching cycle.
2774 ctx.Flush();
2775 });
2776
2777 data_source->on_stop.Wait();
2778 tracing_session->on_stop.Wait();
2779
2780 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2781 ASSERT_GE(raw_trace.size(), 0u);
2782
2783 perfetto::protos::gen::Trace trace;
2784 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
2785 bool test_packet_1_found = false;
2786 bool test_packet_2_found = false;
2787 for (const auto& packet : trace.packet()) {
2788 if (!packet.has_for_testing())
2789 continue;
2790 EXPECT_TRUE(packet.timestamp() == 42U || packet.timestamp() == 43U);
2791 if (packet.timestamp() == 42U) {
2792 EXPECT_FALSE(test_packet_1_found);
2793 EXPECT_EQ(packet.for_testing().str(), first_large_message_str);
2794 test_packet_1_found = true;
2795 } else {
2796 EXPECT_FALSE(test_packet_2_found);
2797 EXPECT_EQ(packet.for_testing().str(), second_large_message_str);
2798 test_packet_2_found = true;
2799 }
2800 }
2801 EXPECT_TRUE(test_packet_1_found && test_packet_2_found);
2802 }
2803
TEST_P(PerfettoApiTest,BlockingStartAndStop)2804 TEST_P(PerfettoApiTest, BlockingStartAndStop) {
2805 auto* data_source = &data_sources_["my_data_source"];
2806
2807 // Register a second data source to get a bit more coverage.
2808 perfetto::DataSourceDescriptor dsd;
2809 dsd.set_name("my_data_source2");
2810 MockDataSource2::Register(dsd, kTestDataSourceArg);
2811 perfetto::test::SyncProducers();
2812
2813 // Setup the trace config.
2814 perfetto::TraceConfig cfg;
2815 cfg.set_duration_ms(500);
2816 cfg.add_buffers()->set_size_kb(1024);
2817 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2818 ds_cfg->set_name("my_data_source");
2819 ds_cfg = cfg.add_data_sources()->mutable_config();
2820 ds_cfg->set_name("my_data_source2");
2821
2822 // Create a new trace session.
2823 auto* tracing_session = NewTrace(cfg);
2824
2825 tracing_session->get()->StartBlocking();
2826 EXPECT_TRUE(data_source->on_setup.notified());
2827 EXPECT_TRUE(data_source->on_start.notified());
2828
2829 tracing_session->get()->StopBlocking();
2830 EXPECT_TRUE(data_source->on_stop.notified());
2831 EXPECT_TRUE(tracing_session->on_stop.notified());
2832 }
2833
TEST_P(PerfettoApiTest,BlockingStartAndStopOnEmptySession)2834 TEST_P(PerfettoApiTest, BlockingStartAndStopOnEmptySession) {
2835 // Setup the trace config.
2836 perfetto::TraceConfig cfg;
2837 cfg.set_duration_ms(500);
2838 cfg.add_buffers()->set_size_kb(1024);
2839 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2840 ds_cfg->set_name("non_existent_data_source");
2841
2842 // Create a new trace session.
2843 auto* tracing_session = NewTrace(cfg);
2844 tracing_session->get()->StartBlocking();
2845 tracing_session->get()->StopBlocking();
2846 EXPECT_TRUE(tracing_session->on_stop.notified());
2847 }
2848
TEST_P(PerfettoApiTest,WriteEventsAfterDeferredStop)2849 TEST_P(PerfettoApiTest, WriteEventsAfterDeferredStop) {
2850 auto* data_source = &data_sources_["my_data_source"];
2851 data_source->handle_stop_asynchronously = true;
2852
2853 // Setup the trace config and start the tracing session.
2854 perfetto::TraceConfig cfg;
2855 cfg.set_duration_ms(500);
2856 cfg.add_buffers()->set_size_kb(1024);
2857 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2858 ds_cfg->set_name("my_data_source");
2859 auto* tracing_session = NewTrace(cfg);
2860 tracing_session->get()->StartBlocking();
2861
2862 // Stop and wait for the producer to have seen the stop event.
2863 WaitableTestEvent consumer_stop_signal;
2864 tracing_session->get()->SetOnStopCallback(
2865 [&consumer_stop_signal] { consumer_stop_signal.Notify(); });
2866 tracing_session->get()->Stop();
2867 data_source->on_stop.Wait();
2868
2869 // At this point tracing should be still allowed because of the
2870 // HandleStopAsynchronously() call.
2871 bool lambda_called = false;
2872
2873 // This usleep is here just to prevent that we accidentally pass the test
2874 // just by virtue of hitting some race. We should be able to trace up until
2875 // 5 seconds after seeing the stop when using the deferred stop mechanism.
2876 std::this_thread::sleep_for(std::chrono::milliseconds(250));
2877
2878 MockDataSource::Trace([&lambda_called](MockDataSource::TraceContext ctx) {
2879 auto packet = ctx.NewTracePacket();
2880 packet->set_for_testing()->set_str("event written after OnStop");
2881 packet->Finalize();
2882 ctx.Flush();
2883 lambda_called = true;
2884 });
2885 ASSERT_TRUE(lambda_called);
2886
2887 // Now call the async stop closure. This acks the stop to the service and
2888 // disallows further Trace() calls.
2889 EXPECT_TRUE(data_source->async_stop_closure);
2890 data_source->async_stop_closure();
2891
2892 // Wait that the stop is propagated to the consumer.
2893 consumer_stop_signal.Wait();
2894
2895 MockDataSource::Trace([](MockDataSource::TraceContext) {
2896 FAIL() << "Should not be called after the stop is acked";
2897 });
2898
2899 // Check the contents of the trace.
2900 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
2901 ASSERT_GE(raw_trace.size(), 0u);
2902 perfetto::protos::gen::Trace trace;
2903 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
2904 int test_packet_found = 0;
2905 for (const auto& packet : trace.packet()) {
2906 if (!packet.has_for_testing())
2907 continue;
2908 EXPECT_EQ(packet.for_testing().str(), "event written after OnStop");
2909 test_packet_found++;
2910 }
2911 EXPECT_EQ(test_packet_found, 1);
2912 }
2913
TEST_P(PerfettoApiTest,RepeatedStartAndStop)2914 TEST_P(PerfettoApiTest, RepeatedStartAndStop) {
2915 perfetto::TraceConfig cfg;
2916 cfg.set_duration_ms(500);
2917 cfg.add_buffers()->set_size_kb(1024);
2918 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2919 ds_cfg->set_name("my_data_source");
2920
2921 for (int i = 0; i < 5; i++) {
2922 auto* tracing_session = NewTrace(cfg);
2923 tracing_session->get()->Start();
2924 std::atomic<bool> stop_called{false};
2925 tracing_session->get()->SetOnStopCallback(
2926 [&stop_called] { stop_called = true; });
2927 tracing_session->get()->StopBlocking();
2928 EXPECT_TRUE(stop_called);
2929 }
2930 }
2931
TEST_P(PerfettoApiTest,SetupWithFile)2932 TEST_P(PerfettoApiTest, SetupWithFile) {
2933 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
2934 if (GetParam() == perfetto::kSystemBackend)
2935 GTEST_SKIP() << "write_into_file + system mode is not supported on Windows";
2936 #endif
2937 auto temp_file = perfetto::test::CreateTempFile();
2938 perfetto::TraceConfig cfg;
2939 cfg.set_duration_ms(500);
2940 cfg.add_buffers()->set_size_kb(1024);
2941 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2942 ds_cfg->set_name("my_data_source");
2943 // Write a trace into |fd|.
2944 auto* tracing_session = NewTrace(cfg, temp_file.fd);
2945 tracing_session->get()->StartBlocking();
2946 tracing_session->get()->StopBlocking();
2947 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
2948 // Check that |fd| didn't get closed.
2949 EXPECT_EQ(0, fcntl(temp_file.fd, F_GETFD, 0));
2950 #endif
2951 // Check that the trace got written.
2952 EXPECT_GT(lseek(temp_file.fd, 0, SEEK_END), 0);
2953 EXPECT_EQ(0, close(temp_file.fd));
2954 // Clean up.
2955 EXPECT_EQ(0, remove(temp_file.path.c_str()));
2956 }
2957
TEST_P(PerfettoApiTest,MultipleRegistrations)2958 TEST_P(PerfettoApiTest, MultipleRegistrations) {
2959 // Attempt to register the same data source again.
2960 perfetto::DataSourceDescriptor dsd;
2961 dsd.set_name("my_data_source");
2962 EXPECT_TRUE(MockDataSource::Register(dsd));
2963 perfetto::test::SyncProducers();
2964
2965 // Setup the trace config.
2966 perfetto::TraceConfig cfg;
2967 cfg.set_duration_ms(500);
2968 cfg.add_buffers()->set_size_kb(1024);
2969 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2970 ds_cfg->set_name("my_data_source");
2971
2972 // Create a new trace session.
2973 auto* tracing_session = NewTrace(cfg);
2974 tracing_session->get()->StartBlocking();
2975
2976 // Emit one trace event.
2977 std::atomic<int> trace_lambda_calls{0};
2978 MockDataSource::Trace([&trace_lambda_calls](MockDataSource::TraceContext) {
2979 trace_lambda_calls++;
2980 });
2981
2982 // Make sure the data source got called only once.
2983 tracing_session->get()->StopBlocking();
2984 EXPECT_EQ(trace_lambda_calls, 1);
2985 }
2986
TEST_P(PerfettoApiTest,CustomIncrementalState)2987 TEST_P(PerfettoApiTest, CustomIncrementalState) {
2988 perfetto::DataSourceDescriptor dsd;
2989 dsd.set_name("incr_data_source");
2990 TestIncrementalDataSource::Register(dsd);
2991 perfetto::test::SyncProducers();
2992
2993 // Setup the trace config.
2994 perfetto::TraceConfig cfg;
2995 cfg.set_duration_ms(500);
2996 cfg.add_buffers()->set_size_kb(1024);
2997 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
2998 ds_cfg->set_name("incr_data_source");
2999
3000 // Create a new trace session.
3001 auto* tracing_session = NewTrace(cfg);
3002 tracing_session->get()->StartBlocking();
3003
3004 // First emit a no-op trace event that initializes the incremental state as a
3005 // side effect.
3006 TestIncrementalDataSource::Trace(
3007 [](TestIncrementalDataSource::TraceContext) {});
3008 EXPECT_TRUE(TestIncrementalState::constructed);
3009
3010 // Check that the incremental state is carried across trace events.
3011 TestIncrementalDataSource::Trace(
3012 [](TestIncrementalDataSource::TraceContext ctx) {
3013 auto* state = ctx.GetIncrementalState();
3014 EXPECT_TRUE(state);
3015 EXPECT_EQ(100, state->count);
3016 state->count++;
3017 });
3018
3019 TestIncrementalDataSource::Trace(
3020 [](TestIncrementalDataSource::TraceContext ctx) {
3021 auto* state = ctx.GetIncrementalState();
3022 EXPECT_EQ(101, state->count);
3023 });
3024
3025 // Make sure the incremental state gets cleaned up between sessions.
3026 tracing_session->get()->StopBlocking();
3027 tracing_session = NewTrace(cfg);
3028 tracing_session->get()->StartBlocking();
3029 TestIncrementalDataSource::Trace(
3030 [](TestIncrementalDataSource::TraceContext ctx) {
3031 auto* state = ctx.GetIncrementalState();
3032 EXPECT_TRUE(TestIncrementalState::destroyed);
3033 EXPECT_TRUE(state);
3034 EXPECT_EQ(100, state->count);
3035 });
3036 tracing_session->get()->StopBlocking();
3037 }
3038
3039 // Regression test for b/139110180. Checks that GetDataSourceLocked() can be
3040 // called from OnStart() and OnStop() callbacks without deadlocking.
TEST_P(PerfettoApiTest,GetDataSourceLockedFromCallbacks)3041 TEST_P(PerfettoApiTest, GetDataSourceLockedFromCallbacks) {
3042 auto* data_source = &data_sources_["my_data_source"];
3043
3044 // Setup the trace config.
3045 perfetto::TraceConfig cfg;
3046 cfg.set_duration_ms(1);
3047 cfg.add_buffers()->set_size_kb(1024);
3048 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3049 ds_cfg->set_name("my_data_source");
3050
3051 // Create a new trace session.
3052 auto* tracing_session = NewTrace(cfg);
3053
3054 data_source->on_start_callback = [] {
3055 MockDataSource::Trace([](MockDataSource::TraceContext ctx) {
3056 ctx.NewTracePacket()->set_for_testing()->set_str("on-start");
3057 auto ds = ctx.GetDataSourceLocked();
3058 ASSERT_TRUE(!!ds);
3059 ctx.NewTracePacket()->set_for_testing()->set_str("on-start-locked");
3060 });
3061 };
3062
3063 data_source->on_stop_callback = [] {
3064 MockDataSource::Trace([](MockDataSource::TraceContext ctx) {
3065 ctx.NewTracePacket()->set_for_testing()->set_str("on-stop");
3066 auto ds = ctx.GetDataSourceLocked();
3067 ASSERT_TRUE(!!ds);
3068 ctx.NewTracePacket()->set_for_testing()->set_str("on-stop-locked");
3069 ctx.Flush();
3070 });
3071 };
3072
3073 tracing_session->get()->Start();
3074 data_source->on_stop.Wait();
3075 tracing_session->on_stop.Wait();
3076
3077 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
3078 ASSERT_GE(raw_trace.size(), 0u);
3079
3080 perfetto::protos::gen::Trace trace;
3081 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
3082 int packets_found = 0;
3083 for (const auto& packet : trace.packet()) {
3084 if (!packet.has_for_testing())
3085 continue;
3086 packets_found |= packet.for_testing().str() == "on-start" ? 1 : 0;
3087 packets_found |= packet.for_testing().str() == "on-start-locked" ? 2 : 0;
3088 packets_found |= packet.for_testing().str() == "on-stop" ? 4 : 0;
3089 packets_found |= packet.for_testing().str() == "on-stop-locked" ? 8 : 0;
3090 }
3091 EXPECT_EQ(packets_found, 1 | 2 | 4 | 8);
3092 }
3093
TEST_P(PerfettoApiTest,OnStartCallback)3094 TEST_P(PerfettoApiTest, OnStartCallback) {
3095 perfetto::TraceConfig cfg;
3096 cfg.set_duration_ms(60000);
3097 cfg.add_buffers()->set_size_kb(1024);
3098 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3099 ds_cfg->set_name("track_event");
3100 auto* tracing_session = NewTrace(cfg);
3101
3102 WaitableTestEvent got_start;
3103 tracing_session->get()->SetOnStartCallback([&] { got_start.Notify(); });
3104 tracing_session->get()->Start();
3105 got_start.Wait();
3106
3107 tracing_session->get()->StopBlocking();
3108 }
3109
TEST_P(PerfettoApiTest,OnErrorCallback)3110 TEST_P(PerfettoApiTest, OnErrorCallback) {
3111 perfetto::TraceConfig cfg;
3112
3113 // Requesting too long |duration_ms| will cause EnableTracing() to fail.
3114 cfg.set_duration_ms(static_cast<uint32_t>(-1));
3115 cfg.add_buffers()->set_size_kb(1024);
3116 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3117 ds_cfg->set_name("track_event");
3118 auto* tracing_session = NewTrace(cfg);
3119
3120 WaitableTestEvent got_error;
3121 tracing_session->get()->SetOnErrorCallback([&](perfetto::TracingError error) {
3122 EXPECT_EQ(perfetto::TracingError::kTracingFailed, error.code);
3123 EXPECT_FALSE(error.message.empty());
3124 got_error.Notify();
3125 });
3126
3127 tracing_session->get()->Start();
3128 got_error.Wait();
3129
3130 // Registered error callback will be triggered also by OnDisconnect()
3131 // function. This may happen after exiting this test what would result in
3132 // system crash (|got_error| will not exist at that time). To prevent that
3133 // scenario, error callback has to be cleared.
3134 tracing_session->get()->SetOnErrorCallback(nullptr);
3135 tracing_session->get()->StopBlocking();
3136 }
3137
TEST_P(PerfettoApiTest,UnsupportedBackend)3138 TEST_P(PerfettoApiTest, UnsupportedBackend) {
3139 // Create a new trace session with an invalid backend type specified.
3140 // Specifically, the custom backend isn't initialized for these tests.
3141 perfetto::TraceConfig cfg;
3142 cfg.add_buffers()->set_size_kb(1024);
3143 auto* tracing_session = NewTrace(cfg, perfetto::BackendType::kCustomBackend);
3144
3145 // Creating the consumer should cause an asynchronous disconnect error.
3146 WaitableTestEvent got_error;
3147 tracing_session->get()->SetOnErrorCallback([&](perfetto::TracingError error) {
3148 EXPECT_EQ(perfetto::TracingError::kDisconnected, error.code);
3149 EXPECT_FALSE(error.message.empty());
3150 got_error.Notify();
3151 });
3152 got_error.Wait();
3153
3154 // Clear the callback for test tear down.
3155 tracing_session->get()->SetOnErrorCallback(nullptr);
3156 // Synchronize the consumer channel to ensure the callback has propagated.
3157 tracing_session->get()->StopBlocking();
3158 }
3159
TEST_P(PerfettoApiTest,ForbiddenConsumer)3160 TEST_P(PerfettoApiTest, ForbiddenConsumer) {
3161 g_test_tracing_policy->should_allow_consumer_connection = false;
3162
3163 // Create a new trace session while consumer connections are forbidden.
3164 perfetto::TraceConfig cfg;
3165 cfg.add_buffers()->set_size_kb(1024);
3166 auto* tracing_session = NewTrace(cfg);
3167
3168 // Creating the consumer should cause an asynchronous disconnect error.
3169 WaitableTestEvent got_error;
3170 tracing_session->get()->SetOnErrorCallback([&](perfetto::TracingError error) {
3171 EXPECT_EQ(perfetto::TracingError::kDisconnected, error.code);
3172 EXPECT_FALSE(error.message.empty());
3173 got_error.Notify();
3174 });
3175 got_error.Wait();
3176
3177 // Clear the callback for test tear down.
3178 tracing_session->get()->SetOnErrorCallback(nullptr);
3179 // Synchronize the consumer channel to ensure the callback has propagated.
3180 tracing_session->get()->StopBlocking();
3181
3182 g_test_tracing_policy->should_allow_consumer_connection = true;
3183 }
3184
TEST_P(PerfettoApiTest,GetTraceStats)3185 TEST_P(PerfettoApiTest, GetTraceStats) {
3186 perfetto::TraceConfig cfg;
3187 cfg.set_duration_ms(500);
3188 cfg.add_buffers()->set_size_kb(1024);
3189 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3190 ds_cfg->set_name("track_event");
3191 auto* tracing_session = NewTrace(cfg);
3192 tracing_session->get()->StartBlocking();
3193
3194 // Asynchronous read.
3195 WaitableTestEvent got_stats;
3196 tracing_session->get()->GetTraceStats(
3197 [&got_stats](perfetto::TracingSession::GetTraceStatsCallbackArgs args) {
3198 perfetto::protos::gen::TraceStats trace_stats;
3199 EXPECT_TRUE(args.success);
3200 EXPECT_TRUE(trace_stats.ParseFromArray(args.trace_stats_data.data(),
3201 args.trace_stats_data.size()));
3202 EXPECT_EQ(1, trace_stats.buffer_stats_size());
3203 got_stats.Notify();
3204 });
3205 got_stats.Wait();
3206
3207 // Blocking read.
3208 auto stats = tracing_session->get()->GetTraceStatsBlocking();
3209 perfetto::protos::gen::TraceStats trace_stats;
3210 EXPECT_TRUE(stats.success);
3211 EXPECT_TRUE(trace_stats.ParseFromArray(stats.trace_stats_data.data(),
3212 stats.trace_stats_data.size()));
3213 EXPECT_EQ(1, trace_stats.buffer_stats_size());
3214
3215 tracing_session->get()->StopBlocking();
3216 }
3217
TEST_P(PerfettoApiTest,QueryServiceState)3218 TEST_P(PerfettoApiTest, QueryServiceState) {
3219 class QueryTestDataSource : public perfetto::DataSource<QueryTestDataSource> {
3220 };
3221 RegisterDataSource<QueryTestDataSource>("query_test_data_source");
3222 perfetto::test::SyncProducers();
3223
3224 auto tracing_session =
3225 perfetto::Tracing::NewTrace(/*BackendType=*/GetParam());
3226 // Asynchronous read.
3227 WaitableTestEvent got_state;
3228 tracing_session->QueryServiceState(
3229 [&got_state](
3230 perfetto::TracingSession::QueryServiceStateCallbackArgs result) {
3231 perfetto::protos::gen::TracingServiceState state;
3232 EXPECT_TRUE(result.success);
3233 EXPECT_TRUE(state.ParseFromArray(result.service_state_data.data(),
3234 result.service_state_data.size()));
3235 EXPECT_EQ(1, state.producers_size());
3236 EXPECT_NE(std::string::npos,
3237 state.producers()[0].name().find("integrationtest"));
3238 bool found_ds = false;
3239 for (const auto& ds : state.data_sources())
3240 found_ds |= ds.ds_descriptor().name() == "query_test_data_source";
3241 EXPECT_TRUE(found_ds);
3242 got_state.Notify();
3243 });
3244 got_state.Wait();
3245
3246 // Blocking read.
3247 auto result = tracing_session->QueryServiceStateBlocking();
3248 perfetto::protos::gen::TracingServiceState state;
3249 EXPECT_TRUE(result.success);
3250 EXPECT_TRUE(state.ParseFromArray(result.service_state_data.data(),
3251 result.service_state_data.size()));
3252 EXPECT_EQ(1, state.producers_size());
3253 EXPECT_NE(std::string::npos,
3254 state.producers()[0].name().find("integrationtest"));
3255 bool found_ds = false;
3256 for (const auto& ds : state.data_sources())
3257 found_ds |= ds.ds_descriptor().name() == "query_test_data_source";
3258 EXPECT_TRUE(found_ds);
3259 }
3260
TEST_P(PerfettoApiTest,LegacyTraceEvents)3261 TEST_P(PerfettoApiTest, LegacyTraceEvents) {
3262 auto is_new_session = [] {
3263 bool result;
3264 TRACE_EVENT_IS_NEW_TRACE(&result);
3265 return result;
3266 };
3267
3268 // Create a new trace session.
3269 EXPECT_FALSE(is_new_session());
3270 auto* tracing_session =
3271 NewTraceWithCategories({"cat", TRACE_DISABLED_BY_DEFAULT("cat")});
3272 tracing_session->get()->StartBlocking();
3273 EXPECT_TRUE(is_new_session());
3274 EXPECT_FALSE(is_new_session());
3275
3276 // Basic events.
3277 TRACE_EVENT_INSTANT0("cat", "LegacyEvent", TRACE_EVENT_SCOPE_GLOBAL);
3278 TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", 123);
3279 TRACE_EVENT_END2("cat", "LegacyEvent", "arg", "string", "arg2", 0.123f);
3280
3281 // Scoped event.
3282 { TRACE_EVENT0("cat", "ScopedLegacyEvent"); }
3283
3284 // Event with flow (and disabled category).
3285 TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("cat"), "LegacyFlowEvent",
3286 0xdadacafe, TRACE_EVENT_FLAG_FLOW_IN);
3287
3288 // Event with timestamp.
3289 TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("cat", "LegacyInstantEvent",
3290 TRACE_EVENT_SCOPE_GLOBAL,
3291 MyTimestamp{123456789ul});
3292
3293 // Event with id, thread id and timestamp (and dynamic name).
3294 TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
3295 "cat", std::string("LegacyWithIdTidAndTimestamp").c_str(), 1,
3296 MyThreadId(123), MyTimestamp{3});
3297
3298 // Event with id.
3299 TRACE_COUNTER1("cat", "LegacyCounter", 1234);
3300 TRACE_COUNTER_ID1("cat", "LegacyCounterWithId", 1234, 9000);
3301
3302 // Metadata event.
3303 TRACE_EVENT_METADATA1("cat", "LegacyMetadata", "obsolete", true);
3304
3305 perfetto::TrackEvent::Flush();
3306 tracing_session->get()->StopBlocking();
3307 auto slices = ReadSlicesFromTrace(tracing_session->get());
3308 EXPECT_THAT(
3309 slices,
3310 ElementsAre(
3311 "[track=0]I:cat.LegacyEvent", "B:cat.LegacyEvent(arg=(int)123)",
3312 "E(arg=(string)string,arg2=(double)0.123)", "B:cat.ScopedLegacyEvent",
3313 "E",
3314 "B(bind_id=3671771902)(flow_direction=1):disabled-by-default-cat."
3315 "LegacyFlowEvent",
3316 "[track=0]I:cat.LegacyInstantEvent",
3317 std::string("[track=") +
3318 std::to_string(perfetto::ThreadTrack::ForThread(123).uuid) +
3319 "]Legacy_S(unscoped_id=1):cat.LegacyWithIdTidAndTimestamp",
3320 "Legacy_C:cat.LegacyCounter(value=(int)1234)",
3321 "Legacy_C(unscoped_id=1234):cat.LegacyCounterWithId(value=(int)9000)",
3322 "Legacy_M:cat.LegacyMetadata"));
3323 }
3324
TEST_P(PerfettoApiTest,LegacyTraceEventsWithCustomAnnotation)3325 TEST_P(PerfettoApiTest, LegacyTraceEventsWithCustomAnnotation) {
3326 // Create a new trace session.
3327 auto* tracing_session = NewTraceWithCategories({"cat"});
3328 tracing_session->get()->StartBlocking();
3329
3330 MyDebugAnnotation annotation;
3331 TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", annotation);
3332
3333 std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
3334 TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", std::move(owned_annotation));
3335
3336 perfetto::TrackEvent::Flush();
3337 tracing_session->get()->StopBlocking();
3338 auto slices = ReadSlicesFromTrace(tracing_session->get());
3339 EXPECT_THAT(slices,
3340 ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})",
3341 "B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
3342 }
3343
TEST_P(PerfettoApiTest,LegacyTraceEventsWithConcurrentSessions)3344 TEST_P(PerfettoApiTest, LegacyTraceEventsWithConcurrentSessions) {
3345 // Make sure that a uniquely owned debug annotation can be written into
3346 // multiple concurrent tracing sessions.
3347
3348 auto* tracing_session = NewTraceWithCategories({"cat"});
3349 tracing_session->get()->StartBlocking();
3350
3351 auto* tracing_session2 = NewTraceWithCategories({"cat"});
3352 tracing_session2->get()->StartBlocking();
3353
3354 std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
3355 TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", std::move(owned_annotation));
3356
3357 perfetto::TrackEvent::Flush();
3358 tracing_session->get()->StopBlocking();
3359 auto slices = ReadSlicesFromTrace(tracing_session->get());
3360 EXPECT_THAT(slices,
3361 ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
3362
3363 tracing_session2->get()->StopBlocking();
3364 slices = ReadSlicesFromTrace(tracing_session2->get());
3365 EXPECT_THAT(slices,
3366 ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
3367 }
3368
TEST_P(PerfettoApiTest,LegacyTraceEventsWithId)3369 TEST_P(PerfettoApiTest, LegacyTraceEventsWithId) {
3370 auto* tracing_session = NewTraceWithCategories({"cat"});
3371 tracing_session->get()->StartBlocking();
3372
3373 TRACE_EVENT_ASYNC_BEGIN0("cat", "UnscopedId", 0x1000);
3374 TRACE_EVENT_ASYNC_BEGIN0("cat", "LocalId", TRACE_ID_LOCAL(0x2000));
3375 TRACE_EVENT_ASYNC_BEGIN0("cat", "GlobalId", TRACE_ID_GLOBAL(0x3000));
3376 TRACE_EVENT_ASYNC_BEGIN0(
3377 "cat", "WithScope",
3378 TRACE_ID_WITH_SCOPE("scope string", TRACE_ID_GLOBAL(0x4000)));
3379
3380 perfetto::TrackEvent::Flush();
3381 tracing_session->get()->StopBlocking();
3382 auto slices = ReadSlicesFromTrace(tracing_session->get());
3383 EXPECT_THAT(slices, ElementsAre("Legacy_S(unscoped_id=4096):cat.UnscopedId",
3384 "Legacy_S(local_id=8192):cat.LocalId",
3385 "Legacy_S(global_id=12288):cat.GlobalId",
3386 "Legacy_S(global_id=16384)(id_scope=\"scope "
3387 "string\"):cat.WithScope"));
3388 }
3389
TEST_P(PerfettoApiTest,LegacyTraceEventsWithFlow)3390 TEST_P(PerfettoApiTest, LegacyTraceEventsWithFlow) {
3391 auto* tracing_session = NewTraceWithCategories({"cat"});
3392 tracing_session->get()->StartBlocking();
3393
3394 const uint64_t flow_id = 1234;
3395 {
3396 TRACE_EVENT_WITH_FLOW1("cat", "LatencyInfo.Flow", TRACE_ID_GLOBAL(flow_id),
3397 TRACE_EVENT_FLAG_FLOW_OUT, "step", "Begin");
3398 }
3399
3400 {
3401 TRACE_EVENT_WITH_FLOW2("cat", "LatencyInfo.Flow", TRACE_ID_GLOBAL(flow_id),
3402 TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
3403 "step", "Middle", "value", false);
3404 }
3405
3406 {
3407 TRACE_EVENT_WITH_FLOW1("cat", "LatencyInfo.Flow", TRACE_ID_GLOBAL(flow_id),
3408 TRACE_EVENT_FLAG_FLOW_IN, "step", "End");
3409 }
3410
3411 perfetto::TrackEvent::Flush();
3412 tracing_session->get()->StopBlocking();
3413 auto slices = ReadSlicesFromTrace(tracing_session->get());
3414 EXPECT_THAT(slices,
3415 ElementsAre("B(bind_id=1234)(flow_direction=2):cat.LatencyInfo."
3416 "Flow(step=(string)Begin)",
3417 "E",
3418 "B(bind_id=1234)(flow_direction=3):cat.LatencyInfo."
3419 "Flow(step=(string)Middle,value=(bool)0)",
3420 "E",
3421 "B(bind_id=1234)(flow_direction=1):cat.LatencyInfo."
3422 "Flow(step=(string)End)",
3423 "E"));
3424 }
3425
TEST_P(PerfettoApiTest,LegacyCategoryGroupEnabledState)3426 TEST_P(PerfettoApiTest, LegacyCategoryGroupEnabledState) {
3427 bool foo_status;
3428 bool bar_status;
3429 bool dynamic_status;
3430 TRACE_EVENT_CATEGORY_GROUP_ENABLED("foo", &foo_status);
3431 TRACE_EVENT_CATEGORY_GROUP_ENABLED("bar", &bar_status);
3432 TRACE_EVENT_CATEGORY_GROUP_ENABLED("dynamic", &dynamic_status);
3433 EXPECT_FALSE(foo_status);
3434 EXPECT_FALSE(bar_status);
3435 EXPECT_FALSE(dynamic_status);
3436
3437 const uint8_t* foo_enabled =
3438 TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("foo");
3439 const uint8_t* bar_enabled =
3440 TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("bar");
3441 EXPECT_FALSE(*foo_enabled);
3442 EXPECT_FALSE(*bar_enabled);
3443
3444 // The category group enabled pointer can also be retrieved with a
3445 // runtime-computed category name.
3446 std::string computed_cat("cat");
3447 const uint8_t* computed_enabled =
3448 TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(computed_cat.c_str());
3449 EXPECT_FALSE(*computed_enabled);
3450
3451 // The enabled pointers can be converted back to category names.
3452 EXPECT_EQ("foo", TRACE_EVENT_API_GET_CATEGORY_GROUP_NAME(foo_enabled));
3453 EXPECT_EQ("bar", TRACE_EVENT_API_GET_CATEGORY_GROUP_NAME(bar_enabled));
3454 EXPECT_EQ("cat", TRACE_EVENT_API_GET_CATEGORY_GROUP_NAME(computed_enabled));
3455
3456 auto* tracing_session = NewTraceWithCategories({"foo", "dynamic", "cat"});
3457 tracing_session->get()->StartBlocking();
3458 TRACE_EVENT_CATEGORY_GROUP_ENABLED("foo", &foo_status);
3459 TRACE_EVENT_CATEGORY_GROUP_ENABLED("bar", &bar_status);
3460 TRACE_EVENT_CATEGORY_GROUP_ENABLED("dynamic", &dynamic_status);
3461 EXPECT_TRUE(foo_status);
3462 EXPECT_FALSE(bar_status);
3463 EXPECT_TRUE(dynamic_status);
3464
3465 EXPECT_TRUE(*foo_enabled);
3466 EXPECT_FALSE(*bar_enabled);
3467 EXPECT_TRUE(*computed_enabled);
3468
3469 tracing_session->get()->StopBlocking();
3470 TRACE_EVENT_CATEGORY_GROUP_ENABLED("foo", &foo_status);
3471 TRACE_EVENT_CATEGORY_GROUP_ENABLED("bar", &bar_status);
3472 TRACE_EVENT_CATEGORY_GROUP_ENABLED("dynamic", &dynamic_status);
3473 EXPECT_FALSE(foo_status);
3474 EXPECT_FALSE(bar_status);
3475 EXPECT_FALSE(dynamic_status);
3476 EXPECT_FALSE(*foo_enabled);
3477 EXPECT_FALSE(*bar_enabled);
3478 EXPECT_FALSE(*computed_enabled);
3479 }
3480
TEST_P(PerfettoApiTest,CategoryEnabledState)3481 TEST_P(PerfettoApiTest, CategoryEnabledState) {
3482 perfetto::DynamicCategory dynamic{"dynamic"};
3483 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("foo"));
3484 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("bar"));
3485 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("red,green,blue,foo"));
3486 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("dynamic"));
3487 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("dynamic_2"));
3488 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED(dynamic));
3489
3490 auto* tracing_session = NewTraceWithCategories({"foo", "dynamic"});
3491 tracing_session->get()->StartBlocking();
3492 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED("foo"));
3493 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("bar"));
3494 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED("red,green,blue,foo"));
3495 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED("dynamic"));
3496 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("dynamic_2"));
3497 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED(dynamic));
3498
3499 tracing_session->get()->StopBlocking();
3500 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("foo"));
3501 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("bar"));
3502 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("red,green,blue,foo"));
3503 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("dynamic"));
3504 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED("dynamic_2"));
3505 EXPECT_FALSE(TRACE_EVENT_CATEGORY_ENABLED(dynamic));
3506 }
3507
3508 class TestInterceptor : public perfetto::Interceptor<TestInterceptor> {
3509 public:
3510 static TestInterceptor* instance;
3511
3512 struct ThreadLocalState : public perfetto::InterceptorBase::ThreadLocalState {
ThreadLocalState__anone89577de0111::TestInterceptor::ThreadLocalState3513 ThreadLocalState(ThreadLocalStateArgs& args) {
3514 // Test accessing instance state from the TLS constructor.
3515 if (auto self = args.GetInterceptorLocked()) {
3516 self->tls_initialized = true;
3517 }
3518 }
3519
3520 std::map<uint64_t, std::string> event_names;
3521 };
3522
TestInterceptor(const std::string & constructor_arg)3523 TestInterceptor(const std::string& constructor_arg) {
3524 EXPECT_EQ(constructor_arg, "Constructor argument");
3525 // Note: some tests in this suite register multiple track event data
3526 // sources. We only track data for the first in this test.
3527 if (!instance)
3528 instance = this;
3529 }
3530
~TestInterceptor()3531 ~TestInterceptor() override {
3532 if (instance != this)
3533 return;
3534 instance = nullptr;
3535 EXPECT_TRUE(setup_called);
3536 EXPECT_TRUE(start_called);
3537 EXPECT_TRUE(stop_called);
3538 EXPECT_TRUE(tls_initialized);
3539 }
3540
OnSetup(const SetupArgs &)3541 void OnSetup(const SetupArgs&) override {
3542 EXPECT_FALSE(setup_called);
3543 EXPECT_FALSE(start_called);
3544 EXPECT_FALSE(stop_called);
3545 setup_called = true;
3546 }
3547
OnStart(const StartArgs &)3548 void OnStart(const StartArgs&) override {
3549 EXPECT_TRUE(setup_called);
3550 EXPECT_FALSE(start_called);
3551 EXPECT_FALSE(stop_called);
3552 start_called = true;
3553 }
3554
OnStop(const StopArgs &)3555 void OnStop(const StopArgs&) override {
3556 EXPECT_TRUE(setup_called);
3557 EXPECT_TRUE(start_called);
3558 EXPECT_FALSE(stop_called);
3559 stop_called = true;
3560 }
3561
OnTracePacket(InterceptorContext context)3562 static void OnTracePacket(InterceptorContext context) {
3563 perfetto::protos::pbzero::TracePacket::Decoder packet(
3564 context.packet_data.data, context.packet_data.size);
3565 EXPECT_TRUE(packet.trusted_packet_sequence_id() > 0);
3566 {
3567 auto self = context.GetInterceptorLocked();
3568 ASSERT_TRUE(self);
3569 EXPECT_TRUE(self->setup_called);
3570 EXPECT_TRUE(self->start_called);
3571 EXPECT_FALSE(self->stop_called);
3572 EXPECT_TRUE(self->tls_initialized);
3573 }
3574
3575 auto& tls = context.GetThreadLocalState();
3576 if (packet.sequence_flags() &
3577 perfetto::protos::pbzero::TracePacket::SEQ_INCREMENTAL_STATE_CLEARED) {
3578 tls.event_names.clear();
3579 }
3580 if (packet.has_interned_data()) {
3581 perfetto::protos::pbzero::InternedData::Decoder interned_data(
3582 packet.interned_data());
3583 for (auto it = interned_data.event_names(); it; it++) {
3584 perfetto::protos::pbzero::EventName::Decoder entry(*it);
3585 tls.event_names[entry.iid()] = entry.name().ToStdString();
3586 }
3587 }
3588 if (packet.has_track_event()) {
3589 perfetto::protos::pbzero::TrackEvent::Decoder track_event(
3590 packet.track_event());
3591 uint64_t name_iid = track_event.name_iid();
3592 auto self = context.GetInterceptorLocked();
3593 self->events.push_back(tls.event_names[name_iid].c_str());
3594 }
3595 }
3596
3597 bool setup_called = false;
3598 bool start_called = false;
3599 bool stop_called = false;
3600 bool tls_initialized = false;
3601 std::vector<std::string> events;
3602 };
3603
3604 TestInterceptor* TestInterceptor::instance;
3605
TEST_P(PerfettoApiTest,TracePacketInterception)3606 TEST_P(PerfettoApiTest, TracePacketInterception) {
3607 perfetto::InterceptorDescriptor desc;
3608 desc.set_name("test_interceptor");
3609 TestInterceptor::Register(desc, std::string("Constructor argument"));
3610
3611 perfetto::TraceConfig cfg;
3612 cfg.set_duration_ms(500);
3613 cfg.add_buffers()->set_size_kb(1024);
3614 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3615 ds_cfg->set_name("track_event");
3616 ds_cfg->mutable_interceptor_config()->set_name("test_interceptor");
3617
3618 auto* tracing_session = NewTrace(cfg);
3619 tracing_session->get()->StartBlocking();
3620 EXPECT_EQ(0u, TestInterceptor::instance->events.size());
3621
3622 // The interceptor should see an event immediately without any explicit
3623 // flushing.
3624 TRACE_EVENT_BEGIN("foo", "Hip");
3625 EXPECT_THAT(TestInterceptor::instance->events, ElementsAre("Hip"));
3626
3627 // Emit another event with the same title to test interning.
3628 TRACE_EVENT_BEGIN("foo", "Hip");
3629 EXPECT_THAT(TestInterceptor::instance->events, ElementsAre("Hip", "Hip"));
3630
3631 // Emit an event from another thread. It should still reach the same
3632 // interceptor instance.
3633 std::thread thread([] { TRACE_EVENT_BEGIN("foo", "Hooray"); });
3634 thread.join();
3635 EXPECT_THAT(TestInterceptor::instance->events,
3636 ElementsAre("Hip", "Hip", "Hooray"));
3637
3638 // Emit a packet that spans multiple segments and must be stitched together.
3639 TestInterceptor::instance->events.clear();
3640 static char long_title[8192];
3641 memset(long_title, 'a', sizeof(long_title) - 1);
3642 long_title[sizeof(long_title) - 1] = 0;
3643 TRACE_EVENT_BEGIN("foo", long_title);
3644 EXPECT_THAT(TestInterceptor::instance->events, ElementsAre(long_title));
3645
3646 tracing_session->get()->StopBlocking();
3647 }
3648
EmitConsoleEvents()3649 void EmitConsoleEvents() {
3650 TRACE_EVENT_INSTANT("foo", "Instant event");
3651 TRACE_EVENT("foo", "Scoped event");
3652 TRACE_EVENT_BEGIN("foo", "Nested event");
3653 TRACE_EVENT_INSTANT("foo", "Instant event");
3654 TRACE_EVENT_INSTANT("foo", "Annotated event", "foo", 1, "bar", "hello");
3655 TRACE_EVENT_END("foo");
3656 uint64_t async_id = 4004;
3657 auto track = perfetto::Track(async_id, perfetto::ThreadTrack::Current());
3658 perfetto::TrackEvent::SetTrackDescriptor(
3659 track, [](perfetto::protos::pbzero::TrackDescriptor* desc) {
3660 desc->set_name("AsyncTrack");
3661 });
3662 TRACE_EVENT_BEGIN("test", "AsyncEvent", track);
3663
3664 std::thread thread([&] {
3665 TRACE_EVENT("foo", "EventFromAnotherThread");
3666 TRACE_EVENT_INSTANT("foo", "Instant event");
3667 TRACE_EVENT_END("test", track);
3668 });
3669 thread.join();
3670
3671 TRACE_EVENT_INSTANT(
3672 "foo", "More annotations", "dict",
3673 [](perfetto::TracedValue context) {
3674 auto dict = std::move(context).WriteDictionary();
3675 dict.Add("key", 123);
3676 },
3677 "array",
3678 [](perfetto::TracedValue context) {
3679 auto array = std::move(context).WriteArray();
3680 array.Append("first");
3681 array.Append("second");
3682 });
3683 }
3684
TEST_P(PerfettoApiTest,ConsoleInterceptorPrint)3685 TEST_P(PerfettoApiTest, ConsoleInterceptorPrint) {
3686 perfetto::ConsoleInterceptor::Register();
3687
3688 perfetto::TraceConfig cfg;
3689 cfg.set_duration_ms(500);
3690 cfg.add_buffers()->set_size_kb(1024);
3691 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3692 ds_cfg->set_name("track_event");
3693 ds_cfg->mutable_interceptor_config()->set_name("console");
3694
3695 auto* tracing_session = NewTrace(cfg);
3696 tracing_session->get()->StartBlocking();
3697 EmitConsoleEvents();
3698 tracing_session->get()->StopBlocking();
3699 }
3700
TEST_P(PerfettoApiTest,ConsoleInterceptorVerify)3701 TEST_P(PerfettoApiTest, ConsoleInterceptorVerify) {
3702 perfetto::ConsoleInterceptor::Register();
3703 auto temp_file = perfetto::test::CreateTempFile();
3704 perfetto::ConsoleInterceptor::SetOutputFdForTesting(temp_file.fd);
3705
3706 perfetto::TraceConfig cfg;
3707 cfg.set_duration_ms(500);
3708 cfg.add_buffers()->set_size_kb(1024);
3709 auto* ds_cfg = cfg.add_data_sources()->mutable_config();
3710 ds_cfg->set_name("track_event");
3711 ds_cfg->mutable_interceptor_config()->set_name("console");
3712
3713 auto* tracing_session = NewTrace(cfg);
3714 tracing_session->get()->StartBlocking();
3715 EmitConsoleEvents();
3716 tracing_session->get()->StopBlocking();
3717 perfetto::ConsoleInterceptor::SetOutputFdForTesting(0);
3718
3719 std::vector<std::string> lines;
3720 FILE* f = fdopen(temp_file.fd, "r");
3721 fseek(f, 0u, SEEK_SET);
3722 std::array<char, 128> line{};
3723 while (fgets(line.data(), line.size(), f)) {
3724 // Ignore timestamps and process/thread ids.
3725 std::string s(line.data() + 28);
3726 // Filter out durations.
3727 s = std::regex_replace(s, std::regex(" [+][0-9]*ms"), "");
3728 lines.push_back(std::move(s));
3729 }
3730 fclose(f);
3731 EXPECT_EQ(0, remove(temp_file.path.c_str()));
3732
3733 // clang-format off
3734 std::vector<std::string> golden_lines = {
3735 "foo Instant event\n",
3736 "foo Scoped event {\n",
3737 "foo - Nested event {\n",
3738 "foo - - Instant event\n",
3739 "foo - - Annotated event(foo:1, bar:hello)\n",
3740 "foo - } Nested event\n",
3741 "test AsyncEvent {\n",
3742 "foo EventFromAnotherThread {\n",
3743 "foo - Instant event\n",
3744 "test } AsyncEvent\n",
3745 "foo } EventFromAnotherThread\n",
3746 "foo - More annotations(dict:{key:123}, array:[first, second])\n",
3747 "foo } Scoped event\n",
3748 };
3749 // clang-format on
3750 EXPECT_THAT(lines, ContainerEq(golden_lines));
3751 }
3752
TEST_P(PerfettoApiTest,TrackEventObserver)3753 TEST_P(PerfettoApiTest, TrackEventObserver) {
3754 class Observer : public perfetto::TrackEventSessionObserver {
3755 public:
3756 ~Observer() override = default;
3757
3758 void OnSetup(const perfetto::DataSourceBase::SetupArgs&) {
3759 // Since other tests here register multiple track event data sources,
3760 // ignore all but the first notifications.
3761 if (setup_called)
3762 return;
3763 setup_called = true;
3764 if (unsubscribe_at_setup)
3765 perfetto::TrackEvent::RemoveSessionObserver(this);
3766 // This event isn't recorded in the trace because tracing isn't active yet
3767 // when OnSetup is called.
3768 TRACE_EVENT_INSTANT("foo", "OnSetup");
3769 // However the active tracing categories have already been updated at this
3770 // point.
3771 EXPECT_TRUE(perfetto::TrackEvent::IsEnabled());
3772 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED("foo"));
3773 }
3774
3775 void OnStart(const perfetto::DataSourceBase::StartArgs&) {
3776 if (start_called)
3777 return;
3778 start_called = true;
3779 EXPECT_TRUE(perfetto::TrackEvent::IsEnabled());
3780 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED("foo"));
3781 TRACE_EVENT_INSTANT("foo", "OnStart");
3782 }
3783
3784 void OnStop(const perfetto::DataSourceBase::StopArgs&) {
3785 if (stop_called)
3786 return;
3787 stop_called = true;
3788 EXPECT_TRUE(perfetto::TrackEvent::IsEnabled());
3789 EXPECT_TRUE(TRACE_EVENT_CATEGORY_ENABLED("foo"));
3790 TRACE_EVENT_INSTANT("foo", "OnStop");
3791 perfetto::TrackEvent::Flush();
3792 }
3793
3794 bool setup_called{};
3795 bool start_called{};
3796 bool stop_called{};
3797 bool unsubscribe_at_setup{};
3798 };
3799
3800 EXPECT_FALSE(perfetto::TrackEvent::IsEnabled());
3801 {
3802 Observer observer;
3803 perfetto::TrackEvent::AddSessionObserver(&observer);
3804
3805 auto* tracing_session = NewTraceWithCategories({"foo"});
3806 tracing_session->get()->StartBlocking();
3807 EXPECT_TRUE(observer.setup_called);
3808 EXPECT_TRUE(observer.start_called);
3809 tracing_session->get()->StopBlocking();
3810 EXPECT_TRUE(observer.stop_called);
3811 perfetto::TrackEvent::RemoveSessionObserver(&observer);
3812 auto slices = ReadSlicesFromTrace(tracing_session->get());
3813 EXPECT_THAT(slices, ElementsAre("I:foo.OnStart", "I:foo.OnStop"));
3814 }
3815
3816 // No notifications after removing observer.
3817 {
3818 Observer observer;
3819 perfetto::TrackEvent::AddSessionObserver(&observer);
3820 perfetto::TrackEvent::RemoveSessionObserver(&observer);
3821 auto* tracing_session = NewTraceWithCategories({"foo"});
3822 tracing_session->get()->StartBlocking();
3823 EXPECT_FALSE(observer.setup_called);
3824 EXPECT_FALSE(observer.start_called);
3825 tracing_session->get()->StopBlocking();
3826 EXPECT_FALSE(observer.stop_called);
3827 }
3828
3829 // Removing observer in a callback.
3830 {
3831 Observer observer;
3832 observer.unsubscribe_at_setup = true;
3833 perfetto::TrackEvent::AddSessionObserver(&observer);
3834 auto* tracing_session = NewTraceWithCategories({"foo"});
3835 tracing_session->get()->StartBlocking();
3836 EXPECT_TRUE(observer.setup_called);
3837 EXPECT_FALSE(observer.start_called);
3838 tracing_session->get()->StopBlocking();
3839 EXPECT_FALSE(observer.stop_called);
3840 perfetto::TrackEvent::RemoveSessionObserver(&observer);
3841 }
3842
3843 // Multiple observers.
3844 {
3845 Observer observer1;
3846 Observer observer2;
3847 perfetto::TrackEvent::AddSessionObserver(&observer1);
3848 perfetto::TrackEvent::AddSessionObserver(&observer2);
3849 auto* tracing_session = NewTraceWithCategories({"foo"});
3850 tracing_session->get()->StartBlocking();
3851 tracing_session->get()->StopBlocking();
3852 perfetto::TrackEvent::RemoveSessionObserver(&observer1);
3853 perfetto::TrackEvent::RemoveSessionObserver(&observer2);
3854 auto slices = ReadSlicesFromTrace(tracing_session->get());
3855 EXPECT_THAT(slices, ElementsAre("I:foo.OnStart", "I:foo.OnStart",
3856 "I:foo.OnStop", "I:foo.OnStop"));
3857 }
3858
3859 // Multiple observers with one being removed midway.
3860 {
3861 Observer observer1;
3862 Observer observer2;
3863 perfetto::TrackEvent::AddSessionObserver(&observer1);
3864 perfetto::TrackEvent::AddSessionObserver(&observer2);
3865 auto* tracing_session = NewTraceWithCategories({"foo"});
3866 tracing_session->get()->StartBlocking();
3867 perfetto::TrackEvent::RemoveSessionObserver(&observer1);
3868 tracing_session->get()->StopBlocking();
3869 perfetto::TrackEvent::RemoveSessionObserver(&observer2);
3870 auto slices = ReadSlicesFromTrace(tracing_session->get());
3871 EXPECT_THAT(slices,
3872 ElementsAre("I:foo.OnStart", "I:foo.OnStart", "I:foo.OnStop"));
3873 }
3874 EXPECT_FALSE(perfetto::TrackEvent::IsEnabled());
3875 }
3876
3877 #if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_CLANG)
3878 struct __attribute__((capability("mutex"))) MockMutex {
Lock__anone89577de0111::MockMutex3879 void Lock() __attribute__((acquire_capability())) {}
Unlock__anone89577de0111::MockMutex3880 void Unlock() __attribute__((release_capability())) {}
3881 };
3882
3883 struct AnnotatedObject {
3884 MockMutex mutex;
3885 int value __attribute__((guarded_by(mutex))) = {};
3886 };
3887
TEST_P(PerfettoApiTest,ThreadSafetyAnnotation)3888 TEST_P(PerfettoApiTest, ThreadSafetyAnnotation) {
3889 AnnotatedObject obj;
3890
3891 // Access to the locked field is only allowed while holding the mutex.
3892 obj.mutex.Lock();
3893 obj.value = 1;
3894 obj.mutex.Unlock();
3895
3896 auto* tracing_session = NewTraceWithCategories({"cat"});
3897 tracing_session->get()->StartBlocking();
3898
3899 // It should be possible to trace the field while holding the lock.
3900 obj.mutex.Lock();
3901 TRACE_EVENT_INSTANT("cat", "Instant", "value", obj.value);
3902 TRACE_EVENT_INSTANT1("cat", "InstantLegacy", 0, "value", obj.value);
3903 { TRACE_EVENT("cat", "Scoped", "value", obj.value); }
3904 { TRACE_EVENT1("cat", "ScopedLegacy", "value", obj.value); }
3905 obj.mutex.Unlock();
3906
3907 perfetto::TrackEvent::Flush();
3908 tracing_session->get()->StopBlocking();
3909 auto slices = ReadSlicesFromTrace(tracing_session->get());
3910 EXPECT_THAT(slices, ElementsAre("I:cat.Instant(value=(int)1)",
3911 "[track=0]I:cat.InstantLegacy(value=(int)1)",
3912 "B:cat.Scoped(value=(int)1)", "E",
3913 "B:cat.ScopedLegacy(value=(int)1)", "E"));
3914 }
3915 #endif // PERFETTO_BUILDFLAG(PERFETTO_COMPILER_CLANG)
3916
TEST_P(PerfettoApiTest,Counters)3917 TEST_P(PerfettoApiTest, Counters) {
3918 auto* tracing_session = NewTraceWithCategories({"cat"});
3919 tracing_session->get()->StartBlocking();
3920
3921 // Describe a counter track.
3922 perfetto::CounterTrack fps_track = perfetto::CounterTrack("Framerate", "fps");
3923
3924 // Emit an integer sample.
3925 TRACE_COUNTER("cat", fps_track, 120);
3926
3927 // Global tracks can be constructed at build time.
3928 constexpr auto goats_track =
3929 perfetto::CounterTrack::Global("Goats teleported", "goats x 1000")
3930 .set_unit_multiplier(1000);
3931 static_assert(goats_track.uuid == 0x6072fc234f82df11,
3932 "Counter track uuid mismatch");
3933
3934 // Emit some floating point samples.
3935 TRACE_COUNTER("cat", goats_track, 0.25);
3936 TRACE_COUNTER("cat", goats_track, 0.5);
3937 TRACE_COUNTER("cat", goats_track, 0.75);
3938
3939 // Emit a sample using an inline track name.
3940 TRACE_COUNTER("cat", "Voltage", 220);
3941
3942 // Emit sample with a custom timestamp.
3943 TRACE_COUNTER("cat",
3944 perfetto::CounterTrack("Power", "GW").set_category("dmc"),
3945 MyTimestamp(1985u), 1.21f);
3946 perfetto::TrackEvent::Flush();
3947
3948 tracing_session->get()->StopBlocking();
3949 std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
3950
3951 perfetto::protos::gen::Trace trace;
3952 ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
3953 std::map<uint64_t, std::string> counter_names;
3954 std::vector<std::string> counter_samples;
3955 for (const auto& packet : trace.packet()) {
3956 if (packet.has_track_event()) {
3957 auto event = packet.track_event();
3958 EXPECT_EQ(perfetto::protos::gen::TrackEvent_Type_TYPE_COUNTER,
3959 event.type());
3960 std::stringstream sample;
3961 std::string counter_name = counter_names[event.track_uuid()];
3962 sample << counter_name << " = ";
3963 if (event.has_counter_value()) {
3964 sample << event.counter_value();
3965 } else if (event.has_double_counter_value()) {
3966 sample << event.double_counter_value();
3967 }
3968 if (counter_name == "Power") {
3969 EXPECT_EQ(1985u, packet.timestamp());
3970 }
3971 counter_samples.push_back(sample.str());
3972 }
3973
3974 if (!packet.has_track_descriptor() ||
3975 !packet.track_descriptor().has_counter()) {
3976 continue;
3977 }
3978 auto desc = packet.track_descriptor();
3979 counter_names[desc.uuid()] = desc.name();
3980 if (desc.name() == "Framerate") {
3981 EXPECT_EQ("fps", desc.counter().unit_name());
3982 } else if (desc.name() == "Goats teleported") {
3983 EXPECT_EQ("goats x 1000", desc.counter().unit_name());
3984 EXPECT_EQ(1000, desc.counter().unit_multiplier());
3985 } else if (desc.name() == "Power") {
3986 EXPECT_EQ("GW", desc.counter().unit_name());
3987 EXPECT_EQ("dmc", desc.counter().categories()[0]);
3988 }
3989 }
3990 EXPECT_EQ(4u, counter_names.size());
3991 EXPECT_THAT(counter_samples,
3992 ElementsAre("Framerate = 120", "Goats teleported = 0.25",
3993 "Goats teleported = 0.5", "Goats teleported = 0.75",
3994 "Voltage = 220", "Power = 1.21"));
3995 }
3996
3997 struct BackendTypeAsString {
operator ()__anone89577de0111::BackendTypeAsString3998 std::string operator()(
3999 const ::testing::TestParamInfo<perfetto::BackendType>& info) const {
4000 switch (info.param) {
4001 case perfetto::kInProcessBackend:
4002 return "InProc";
4003 case perfetto::kSystemBackend:
4004 return "System";
4005 case perfetto::kCustomBackend:
4006 return "Custom";
4007 case perfetto::kUnspecifiedBackend:
4008 return "Unspec";
4009 }
4010 return nullptr;
4011 }
4012 };
4013
4014 INSTANTIATE_TEST_SUITE_P(PerfettoApiTest,
4015 PerfettoApiTest,
4016 ::testing::Values(perfetto::kInProcessBackend,
4017 perfetto::kSystemBackend),
4018 BackendTypeAsString());
4019
4020 } // namespace
4021
4022 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(MockDataSource);
4023 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(MockDataSource2);
4024 PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(TestIncrementalDataSource,
4025 TestIncrementalDataSourceTraits);
4026
4027 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(MockDataSource);
4028 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(MockDataSource2);
4029 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(TestIncrementalDataSource,
4030 TestIncrementalDataSourceTraits);
4031