123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- // Copyright (c) 2020 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/trace_event/typed_macros.h"
- #include "base/location.h"
- #include "base/synchronization/waitable_event.h"
- #include "base/test/trace_test_utils.h"
- #include "base/trace_event/interned_args_helper.h"
- #include "base/trace_event/trace_log.h"
- #include "base/trace_event/typed_macros_embedder_support.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h"
- #include "third_party/perfetto/include/perfetto/tracing/track_event_interned_data_index.h"
- #include "third_party/perfetto/protos/perfetto/trace/interned_data/interned_data.pb.h"
- #include "third_party/perfetto/protos/perfetto/trace/trace.pb.h"
- #include "third_party/perfetto/protos/perfetto/trace/track_event/log_message.pbzero.h"
- #include "third_party/perfetto/protos/perfetto/trace/track_event/source_location.pb.h"
- #include "third_party/perfetto/protos/perfetto/trace/track_event/source_location.pbzero.h"
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- #include "base/tracing/perfetto_platform.h"
- #endif
- namespace base {
- namespace trace_event {
- namespace {
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- std::unique_ptr<perfetto::TracingSession> g_tracing_session;
- #else
- constexpr const char kRecordAllCategoryFilter[] = "*";
- #endif
- void EnableTrace() {
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- g_tracing_session = perfetto::Tracing::NewTrace();
- g_tracing_session->Setup(test::TracingEnvironment::GetDefaultTraceConfig());
- g_tracing_session->StartBlocking();
- #else // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
- TraceLog::RECORDING_MODE);
- #endif // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- }
- #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- void CancelTraceAsync(WaitableEvent* flush_complete_event) {
- TraceLog::GetInstance()->CancelTracing(base::BindRepeating(
- [](WaitableEvent* complete_event,
- const scoped_refptr<base::RefCountedString>&, bool has_more_events) {
- if (!has_more_events)
- complete_event->Signal();
- },
- base::Unretained(flush_complete_event)));
- }
- #endif // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- void CancelTrace() {
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- g_tracing_session.reset();
- #else // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- WaitableEvent flush_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
- WaitableEvent::InitialState::NOT_SIGNALED);
- CancelTraceAsync(&flush_complete_event);
- flush_complete_event.Wait();
- #endif
- }
- struct TestTrackEvent;
- struct TestTracePacket;
- TestTrackEvent* g_test_track_event;
- TestTracePacket* g_test_trace_packet;
- struct TestTrackEvent : public TrackEventHandle::CompletionListener {
- public:
- TestTrackEvent() {
- CHECK_EQ(g_test_track_event, nullptr)
- << "Another instance of TestTrackEvent is already active";
- g_test_track_event = this;
- }
- ~TestTrackEvent() override { g_test_track_event = nullptr; }
- void OnTrackEventCompleted() override {
- EXPECT_FALSE(event_completed);
- event_completed = true;
- }
- protozero::HeapBuffered<perfetto::protos::pbzero::TrackEvent> event;
- perfetto::internal::TrackEventIncrementalState incremental_state;
- bool prepare_called = false;
- bool event_completed = false;
- };
- struct TestTracePacket : public TracePacketHandle::CompletionListener {
- public:
- TestTracePacket() {
- CHECK_EQ(g_test_trace_packet, nullptr)
- << "Another instance of TestTracePacket is already active";
- g_test_trace_packet = this;
- }
- ~TestTracePacket() override { g_test_trace_packet = nullptr; }
- void OnTracePacketCompleted() override {
- EXPECT_FALSE(packet_completed);
- packet_completed = true;
- }
- protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket> packet;
- bool prepare_called = false;
- bool packet_completed = false;
- bool emit_empty_called = false;
- };
- TrackEventHandle PrepareTrackEvent(TraceEvent*) {
- CHECK_NE(g_test_track_event, nullptr) << "TestTrackEvent not set yet";
- g_test_track_event->prepare_called = true;
- return TrackEventHandle(g_test_track_event->event.get(),
- &g_test_track_event->incremental_state,
- g_test_track_event);
- }
- TracePacketHandle PrepareTracePacket() {
- CHECK_NE(g_test_track_event, nullptr) << "TestTracePacket not set yet";
- g_test_trace_packet->prepare_called = true;
- return TracePacketHandle(TracePacketHandle::PerfettoPacketHandle(
- g_test_trace_packet->packet.get()),
- g_test_trace_packet);
- }
- void EmitEmptyPacket() {
- CHECK_NE(g_test_track_event, nullptr) << "TestTracePacket not set yet";
- g_test_trace_packet->emit_empty_called = true;
- }
- class TypedTraceEventTest : public testing::Test {
- public:
- TypedTraceEventTest() {
- perfetto::internal::TrackRegistry::InitializeInstance();
- EnableTypedTraceEvents(&PrepareTrackEvent, &PrepareTracePacket,
- &EmitEmptyPacket);
- }
- ~TypedTraceEventTest() override { ResetTypedTraceEventsForTesting(); }
- void FlushTrace() {
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- perfetto::TrackEvent::Flush();
- g_tracing_session->StopBlocking();
- std::vector<char> serialized_data = g_tracing_session->ReadTraceBlocking();
- perfetto::protos::Trace trace;
- EXPECT_TRUE(
- trace.ParseFromArray(serialized_data.data(), serialized_data.size()));
- for (const auto& packet : trace.packet()) {
- if (packet.has_track_event()) {
- std::string serialized_event = packet.track_event().SerializeAsString();
- event_.prepare_called = true;
- event_.event->AppendRawProtoBytes(serialized_event.data(),
- serialized_event.size());
- event_.OnTrackEventCompleted();
- std::string serialized_interned_data =
- packet.interned_data().SerializeAsString();
- event_.incremental_state.serialized_interned_data->AppendRawProtoBytes(
- serialized_interned_data.data(), serialized_interned_data.size());
- std::string serialized_packet = packet.SerializeAsString();
- packet_.prepare_called = true;
- packet_.packet->AppendRawProtoBytes(serialized_packet.data(),
- serialized_packet.size());
- packet_.OnTracePacketCompleted();
- break;
- }
- }
- #endif // BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- }
- perfetto::protos::TrackEvent ParseTrackEvent() {
- FlushTrace();
- auto serialized_data = event_.event.SerializeAsArray();
- perfetto::protos::TrackEvent track_event;
- EXPECT_TRUE(track_event.ParseFromArray(serialized_data.data(),
- serialized_data.size()));
- return track_event;
- }
- protected:
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- test::TracingEnvironment tracing_environment_;
- #endif
- TestTrackEvent event_;
- TestTracePacket packet_;
- };
- } // namespace
- TEST_F(TypedTraceEventTest, CallbackExecutedWhenTracingEnabled) {
- EnableTrace();
- TRACE_EVENT("cat", "Name", [&](perfetto::EventContext ctx) {
- #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- EXPECT_EQ(ctx.event(), event_.event.get());
- #endif
- perfetto::protos::pbzero::LogMessage* log = ctx.event()->set_log_message();
- log->set_body_iid(1);
- });
- FlushTrace();
- EXPECT_TRUE(event_.prepare_called);
- EXPECT_FALSE(event_.event.empty());
- EXPECT_TRUE(event_.event_completed);
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, CallbackNotExecutedWhenTracingDisabled) {
- TRACE_EVENT("cat", "Name", [this](perfetto::EventContext ctx) {
- EXPECT_EQ(ctx.event(), event_.event.get());
- perfetto::protos::pbzero::LogMessage* log = ctx.event()->set_log_message();
- log->set_body_iid(1);
- });
- EXPECT_FALSE(event_.prepare_called);
- EXPECT_TRUE(event_.event.empty());
- EXPECT_FALSE(event_.event_completed);
- }
- TEST_F(TypedTraceEventTest, DescriptorPacketWrittenForEventWithTrack) {
- EnableTrace();
- TRACE_EVENT("cat", "Name", perfetto::Track(1234));
- FlushTrace();
- EXPECT_TRUE(event_.prepare_called);
- EXPECT_FALSE(event_.event.empty());
- EXPECT_TRUE(event_.event_completed);
- EXPECT_TRUE(packet_.prepare_called);
- EXPECT_FALSE(packet_.packet.empty());
- EXPECT_TRUE(packet_.packet_completed);
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, InternedData) {
- EnableTrace();
- const TraceSourceLocation location("TestFunction", "test.cc", 123);
- size_t iid = 0;
- TRACE_EVENT("cat", "Name", [&location, &iid](perfetto::EventContext ctx) {
- auto* log = ctx.event()->set_log_message();
- iid = InternedSourceLocation::Get(&ctx, location);
- EXPECT_NE(0u, iid);
- log->set_body_iid(iid);
- size_t iid2 = InternedSourceLocation::Get(&ctx, location);
- EXPECT_EQ(iid, iid2);
- TraceSourceLocation location2("TestFunction2", "test.cc", 456);
- size_t iid3 = InternedSourceLocation::Get(&ctx, location2);
- EXPECT_NE(0u, iid3);
- EXPECT_NE(iid, iid3);
- // Test getting an interned ID directly from a base::Location object, the
- // only attributes that are compared are function_name, file_name and
- // line_number.
- const void* dummy_pc = &iid;
- base::Location base_location =
- base::Location("TestFunction", "test.cc", 123, dummy_pc);
- TraceSourceLocation location3(base_location);
- size_t iid4 = InternedSourceLocation::Get(&ctx, location3);
- EXPECT_EQ(iid, iid4);
- });
- FlushTrace();
- auto serialized_data =
- event_.incremental_state.serialized_interned_data.SerializeAsArray();
- perfetto::protos::InternedData interned_data;
- EXPECT_TRUE(interned_data.ParseFromArray(serialized_data.data(),
- serialized_data.size()));
- EXPECT_EQ(2, interned_data.source_locations_size());
- auto interned_loc = interned_data.source_locations()[0];
- EXPECT_EQ(iid, interned_loc.iid());
- EXPECT_EQ("TestFunction", interned_loc.function_name());
- EXPECT_EQ("test.cc", interned_loc.file_name());
- interned_loc = interned_data.source_locations()[1];
- EXPECT_EQ("TestFunction2", interned_loc.function_name());
- EXPECT_EQ("test.cc", interned_loc.file_name());
- // Make sure the in-memory interning index persists between trace events by
- // recording another event.
- event_.incremental_state.serialized_interned_data.Reset();
- event_.event_completed = false;
- TRACE_EVENT("cat", "Name", [&location](perfetto::EventContext ctx) {
- auto* log = ctx.event()->set_log_message();
- size_t iid = InternedSourceLocation::Get(&ctx, location);
- EXPECT_NE(0u, iid);
- log->set_body_iid(iid);
- });
- FlushTrace();
- // No new data should have been interned the second time around.
- EXPECT_EQ(
- "",
- event_.incremental_state.serialized_interned_data.SerializeAsString());
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, InstantThreadEvent) {
- EnableTrace();
- TRACE_EVENT_INSTANT("cat", "ThreadEvent", [](perfetto::EventContext) {});
- auto track_event = ParseTrackEvent();
- EXPECT_FALSE(track_event.has_track_uuid());
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, InstantProcessEvent) {
- EnableTrace();
- TRACE_EVENT_INSTANT("cat", "ProcessEvent", perfetto::ProcessTrack::Current(),
- [](perfetto::EventContext) {});
- auto track_event = ParseTrackEvent();
- EXPECT_TRUE(track_event.has_track_uuid());
- EXPECT_EQ(track_event.track_uuid(), perfetto::ProcessTrack::Current().uuid);
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, InstantGlobalEvent) {
- EnableTrace();
- TRACE_EVENT_INSTANT("cat", "GlobalEvent", perfetto::Track::Global(1234),
- [](perfetto::EventContext) {});
- auto track_event = ParseTrackEvent();
- EXPECT_TRUE(track_event.has_track_uuid());
- EXPECT_EQ(track_event.track_uuid(), perfetto::Track::Global(1234).uuid);
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, InstantGlobalDefaultEvent) {
- EnableTrace();
- TRACE_EVENT_INSTANT("cat", "GlobalDefaultEvent", perfetto::Track::Global(0),
- [](perfetto::EventContext) {});
- auto track_event = ParseTrackEvent();
- EXPECT_TRUE(track_event.has_track_uuid());
- EXPECT_EQ(track_event.track_uuid(), perfetto::Track::Global(0).uuid);
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, BeginEventOnDefaultTrackDoesNotWriteTrackUuid) {
- EnableTrace();
- TRACE_EVENT_BEGIN("cat", "Name");
- auto begin_event = ParseTrackEvent();
- EXPECT_FALSE(begin_event.has_track_uuid());
- CancelTrace();
- }
- TEST_F(TypedTraceEventTest, EndEventOnDefaultTrackDoesNotWriteTrackUuid) {
- EnableTrace();
- TRACE_EVENT_END("cat");
- auto end_event = ParseTrackEvent();
- EXPECT_FALSE(end_event.has_track_uuid());
- CancelTrace();
- }
- // In the client library, EmitEmptyPacket() isn't called and the packet
- // disappears from the trace. This functionality is instead tested in Perfetto's
- // API integration tests. We just verify that the macro builds correctly here
- // when building with the client library.
- #if BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
- #define MAYBE_EmptyEvent DISABLED_EmptyEvent
- #else
- #define MAYBE_EmptyEvent EmptyEvent
- #endif
- TEST_F(TypedTraceEventTest, MAYBE_EmptyEvent) {
- EnableTrace();
- EXPECT_FALSE(g_test_trace_packet->emit_empty_called);
- PERFETTO_INTERNAL_ADD_EMPTY_EVENT();
- EXPECT_TRUE(g_test_trace_packet->emit_empty_called);
- CancelTrace();
- }
- } // namespace trace_event
- } // namespace base
|