Commit 1c8ae5cc authored by Stephen Nusko's avatar Stephen Nusko Committed by Commit Bot

Add TRACE_EVENT and TRACE_EVENT_INSTANT for typed events.

While I was developing TRACE_EVENT_BEGIN and TRACE_EVENT_END these
macros were added to the perfetto client library. Add mirrors of them in
Chromium so we have access as well.

TRACE_EVENT will allow people to conveniently emit trace events tied to
a scope and TRACE_EVENT_INSTANT for things that have no duration.

Change-Id: I474901a0ca53521b00199e32da5e21143d6781c0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1935113
Commit-Queue: Stephen Nusko <nuskos@chromium.org>
Reviewed-by: default avatarSami Kyöstilä <skyostil@chromium.org>
Reviewed-by: default avatarEric Seckler <eseckler@chromium.org>
Auto-Submit: Stephen Nusko <nuskos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#719250}
parent c857609e
...@@ -47,4 +47,16 @@ constexpr char kTraceEventEndName[] = ""; ...@@ -47,4 +47,16 @@ constexpr char kTraceEventEndName[] = "";
TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, category, \ TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, category, \
kTraceEventEndName, ##__VA_ARGS__) kTraceEventEndName, ##__VA_ARGS__)
// Begin a thread-scoped slice which gets automatically closed when going out
// of scope.
#define TRACE_EVENT(category, name, ...) \
TRACING_INTERNAL_SCOPED_ADD_TRACE_EVENT(category, name, ##__VA_ARGS__)
// Emit a thread-scoped slice which has zero duration.
// TODO(nuskos): Add support for process-wide and global instant events when
// perfetto does.
#define TRACE_EVENT_INSTANT(category, name, ...) \
TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_INSTANT, category, name, \
##__VA_ARGS__)
#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_MACROS_H_ #endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_MACROS_H_
...@@ -28,7 +28,8 @@ base::Optional<base::trace_event::TraceEvent> CreateTraceEvent( ...@@ -28,7 +28,8 @@ base::Optional<base::trace_event::TraceEvent> CreateTraceEvent(
char phase, char phase,
const unsigned char* category_group_enabled, const unsigned char* category_group_enabled,
const char* name) { const char* name) {
DCHECK(phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_END); DCHECK(phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_END ||
phase == TRACE_EVENT_PHASE_INSTANT);
DCHECK(category_group_enabled); DCHECK(category_group_enabled);
const int thread_id = static_cast<int>(base::PlatformThread::CurrentId()); const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
auto* trace_log = base::trace_event::TraceLog::GetInstance(); auto* trace_log = base::trace_event::TraceLog::GetInstance();
......
...@@ -42,8 +42,12 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent( ...@@ -42,8 +42,12 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
} // namespace internal } // namespace internal
} // namespace tracing } // namespace tracing
// Should not be called directly. Used by macros in // These macros should not be called directly. They are intended to be used by
// //services/tracing/perfetto/macros.h. // macros in //services/tracing/perfetto/macros.h only.
#define TRACING_INTERNAL_CONCAT(a, b) a##b
#define TRACING_INTERNAL_UID(prefix) TRACING_INTERNAL_CONCAT(prefix, __LINE__)
#define TRACING_INTERNAL_ADD_TRACE_EVENT(phase, category, name, ...) \ #define TRACING_INTERNAL_ADD_TRACE_EVENT(phase, category, name, ...) \
do { \ do { \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
...@@ -54,4 +58,28 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent( ...@@ -54,4 +58,28 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
} \ } \
} while (false) } while (false)
#define TRACING_INTERNAL_SCOPED_ADD_TRACE_EVENT(category, name, ...) \
struct { \
struct ScopedTraceEvent { \
~ScopedTraceEvent() { \
/* TODO(nuskos): Remove the empty string passed as the |name| */ \
/* field. As described in macros.h we shouldn't need it in our */ \
/* end state */ \
TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, category, "", \
[](perfetto::EventContext) {}); \
} \
/* The variable |x| is an implementation detail. It allows the */ \
/* anonymous struct to use aggregate initialization to invoke the */ \
/* lambda to emit the begin event with the proper reference capture */ \
/* for any TrackEventArgumentFunction in |__VA_ARGS__|. This is */ \
/* required so that the scoped event is exactly ONE line and can't */ \
/* escape the scope if used in a single line if statement. */ \
int x; \
} event; \
} TRACING_INTERNAL_UID(scoped_event){[&]() { \
TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_BEGIN, category, name, \
##__VA_ARGS__); \
return 0; \
}()};
#endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_MACROS_INTERNAL_H_ #endif // SERVICES_TRACING_PUBLIC_CPP_PERFETTO_MACROS_INTERNAL_H_
...@@ -1421,6 +1421,95 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnBeginAndEnd) { ...@@ -1421,6 +1421,95 @@ TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnBeginAndEnd) {
EXPECT_EQ(e_packet->track_event().log_message().body_iid(), 84u); EXPECT_EQ(e_packet->track_event().log_message().body_iid(), 84u);
} }
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnInstant) {
CreateTraceEventDataSource();
TRACE_EVENT_INSTANT("browser", "bar", [&](perfetto::EventContext ctx) {
ctx.event()->set_log_message()->set_body_iid(42);
});
EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 2u);
auto* td_packet = producer_client()->GetFinalizedPacket();
ExpectThreadDescriptor(td_packet);
auto* e_packet = producer_client()->GetFinalizedPacket(1);
ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/1u,
TRACE_EVENT_PHASE_INSTANT);
ExpectEventCategories(e_packet, {{1u, "browser"}});
ExpectEventNames(e_packet, {{1u, "bar"}});
ASSERT_TRUE(e_packet->track_event().has_log_message());
EXPECT_EQ(e_packet->track_event().log_message().body_iid(), 42u);
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScoped) {
CreateTraceEventDataSource();
// Use a if statement with no brackets to ensure that the Scoped TRACE_EVENT
// macro properly emits the end event when leaving the single expression
// associated with the if(true) statement.
if (true)
TRACE_EVENT("browser", "bar", [&](perfetto::EventContext ctx) {
ctx.event()->set_log_message()->set_body_iid(42);
});
EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 3u);
auto* td_packet = producer_client()->GetFinalizedPacket();
ExpectThreadDescriptor(td_packet);
auto* e_packet = producer_client()->GetFinalizedPacket(1);
ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/1u,
TRACE_EVENT_PHASE_BEGIN);
ExpectEventCategories(e_packet, {{1u, "browser"}});
ExpectEventNames(e_packet, {{1u, "bar"}});
ASSERT_TRUE(e_packet->track_event().has_log_message());
EXPECT_EQ(e_packet->track_event().log_message().body_iid(), 42u);
e_packet = producer_client()->GetFinalizedPacket(2);
ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/2u,
TRACE_EVENT_PHASE_END);
ExpectEventNames(e_packet, {{2u, kTraceEventEndName}});
EXPECT_FALSE(e_packet->track_event().has_log_message());
}
TEST_F(TraceEventDataSourceTest, TypedArgumentsTracingOnScopedCapture) {
CreateTraceEventDataSource();
bool called = false;
{
TRACE_EVENT("browser", "bar", [&](perfetto::EventContext ctx) {
called = true;
ctx.event()->set_log_message()->set_body_iid(42);
});
}
EXPECT_EQ(producer_client()->GetFinalizedPacketCount(), 3u);
auto* td_packet = producer_client()->GetFinalizedPacket();
ExpectThreadDescriptor(td_packet);
auto* e_packet = producer_client()->GetFinalizedPacket(1);
ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/1u,
TRACE_EVENT_PHASE_BEGIN);
ExpectEventCategories(e_packet, {{1u, "browser"}});
ExpectEventNames(e_packet, {{1u, "bar"}});
ASSERT_TRUE(e_packet->track_event().has_log_message());
EXPECT_EQ(e_packet->track_event().log_message().body_iid(), 42u);
e_packet = producer_client()->GetFinalizedPacket(2);
ExpectTraceEvent(e_packet, /*category_iid=*/1u, /*name_iid=*/2u,
TRACE_EVENT_PHASE_END);
ExpectEventNames(e_packet, {{2u, kTraceEventEndName}});
EXPECT_FALSE(e_packet->track_event().has_log_message());
EXPECT_TRUE(called);
}
// TODO(eseckler): Add startup tracing unittests. // TODO(eseckler): Add startup tracing unittests.
} // namespace } // namespace
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment