Merge "shared_lib: Fix PERFETTO_TE_SCOPED macro captures" into main
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index e4b6b0c..22ebb8c 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -42,16 +42,6 @@
#define PERFETTO_UNUSED
#endif
-#if defined(__clang__)
-#define PERFETTO_ALWAYS_INLINE __attribute__((__always_inline__))
-#define PERFETTO_NO_INLINE __attribute__((__noinline__))
-#else
-// GCC is too pedantic and often fails with the error:
-// "always_inline function might not be inlinable"
-#define PERFETTO_ALWAYS_INLINE
-#define PERFETTO_NO_INLINE
-#endif
-
#if defined(__GNUC__) || defined(__clang__)
#define PERFETTO_NORETURN __attribute__((__noreturn__))
#else
diff --git a/include/perfetto/public/compiler.h b/include/perfetto/public/compiler.h
index 3e38853..fba7204 100644
--- a/include/perfetto/public/compiler.h
+++ b/include/perfetto/public/compiler.h
@@ -51,4 +51,14 @@
#define PERFETTO_NULL NULL
#endif
+#if defined(__clang__)
+#define PERFETTO_ALWAYS_INLINE __attribute__((__always_inline__))
+#define PERFETTO_NO_INLINE __attribute__((__noinline__))
+#else
+// GCC is too pedantic and often fails with the error:
+// "always_inline function might not be inlinable"
+#define PERFETTO_ALWAYS_INLINE
+#define PERFETTO_NO_INLINE
+#endif
+
#endif // INCLUDE_PERFETTO_PUBLIC_COMPILER_H_
diff --git a/include/perfetto/public/te_macros.h b/include/perfetto/public/te_macros.h
index 2b27b7a..52f99fa 100644
--- a/include/perfetto/public/te_macros.h
+++ b/include/perfetto/public/te_macros.h
@@ -64,6 +64,19 @@
PERFETTO_NULL) \
}
+// Implementation of the PERFETTO_TE macro. If `CAT` is enabled, emits the
+// tracing event specified by the params.
+//
+// Uses `?:` instead of `if` because this might be used as an expression, where
+// statements are not allowed.
+#define PERFETTO_I_TE_IMPL(CAT, ...) \
+ ((PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( \
+ (CAT).enabled, PERFETTO_MEMORY_ORDER_RELAXED))) \
+ ? (PerfettoTeHlCall((CAT).impl, \
+ PERFETTO_I_TE_HL_MACRO_PARAMS(__VA_ARGS__)), \
+ 0) \
+ : 0)
+
#ifndef __cplusplus
#define PERFETTO_I_TE_COMPOUND_LITERAL_ADDR(STRUCT, ...) \
&(struct STRUCT)__VA_ARGS__
@@ -312,14 +325,10 @@
// PERFETTO_TE(PERFETTO_TE_DYNAMIC_CATEGORY, PERFETTO_TE_INSTANT("instant"),
// PERFETTO_TE_DYNAMIC_CATEGORY_STRING("category"));
//
-#define PERFETTO_TE(CAT, ...) \
- do { \
- if (PERFETTO_UNLIKELY(PERFETTO_ATOMIC_LOAD_EXPLICIT( \
- (CAT).enabled, PERFETTO_MEMORY_ORDER_RELAXED))) { \
- PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS(__VA_ARGS__); \
- PerfettoTeHlCall((CAT).impl, \
- PERFETTO_I_TE_HL_MACRO_PARAMS(__VA_ARGS__)); \
- } \
+#define PERFETTO_TE(CAT, ...) \
+ do { \
+ PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS(__VA_ARGS__); \
+ (void)PERFETTO_I_TE_IMPL(CAT, __VA_ARGS__); \
} while (0)
#ifdef __cplusplus
@@ -333,6 +342,29 @@
#define PERFETTO_TE_SLICE(NAME) \
{ NAME, PERFETTO_TE_TYPE_SLICE_BEGIN }
+namespace perfetto::internal {
+template <typename F>
+class TeCleanup {
+ public:
+ explicit TeCleanup(F&& f) PERFETTO_ALWAYS_INLINE : f_(std::forward<F>(f)) {}
+
+ ~TeCleanup() PERFETTO_ALWAYS_INLINE { f_(); }
+
+ private:
+ TeCleanup(const TeCleanup&) = delete;
+ TeCleanup(TeCleanup&&) = delete;
+ TeCleanup& operator=(const TeCleanup&) = delete;
+ TeCleanup& operator=(TeCleanup&&) = delete;
+ F f_;
+};
+
+template <typename F>
+TeCleanup<F> MakeTeCleanup(F&& f) {
+ return TeCleanup<F>(std::forward<F>(f));
+}
+
+} // namespace perfetto::internal
+
// ------------------------
// PERFETTO_TE_SCOPED macro
// ------------------------
@@ -363,17 +395,13 @@
// PERFETTO_TE_SCOPED(category, PERFETTO_TE_SLICE("name"),
// PERFETTO_TE_ARG_UINT64("count", 42));
//
-#define PERFETTO_TE_SCOPED(CAT, ...) \
- class PERFETTO_I_TE_UID(PerfettoTeEvent) { \
- struct Internal { \
- Internal() { \
- PERFETTO_TE(CAT, __VA_ARGS__); \
- } \
- ~Internal() { \
- PERFETTO_TE(CAT, PERFETTO_TE_SLICE_END()); \
- } \
- } field; \
- } PERFETTO_I_TE_UID(perfetto_te_event)
+#define PERFETTO_TE_SCOPED(CAT, ...) \
+ auto PERFETTO_I_TE_UID(perfetto_i_te_cleanup) = \
+ (PERFETTO_I_TE_IMPL(CAT, __VA_ARGS__), \
+ perfetto::internal::MakeTeCleanup([&] { \
+ PERFETTO_I_TE_STATIC_ASSERT_NUM_PARAMS(__VA_ARGS__); \
+ PERFETTO_TE(CAT, PERFETTO_TE_SLICE_END()); \
+ }))
#endif // __cplusplus
diff --git a/src/shared_lib/test/api_integrationtest.cc b/src/shared_lib/test/api_integrationtest.cc
index e669cd5..975f001 100644
--- a/src/shared_lib/test/api_integrationtest.cc
+++ b/src/shared_lib/test/api_integrationtest.cc
@@ -1651,6 +1651,29 @@
}
}
+TEST_F(SharedLibTrackEventTest, ScopedDisabled) {
+ TracingSession tracing_session = TracingSession::Builder()
+ .set_data_source_name("track_event")
+ .add_disabled_category("cat1")
+ .Build();
+ // Check that the PERFETTO_TE_SCOPED macro does not have any effect if the
+ // category is disabled.
+ { PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE("slice")); }
+
+ tracing_session.StopBlocking();
+ std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ auto trace_view = FieldView(data);
+ auto it = trace_view.begin();
+ for (; it != trace_view.end(); it++) {
+ struct PerfettoPbDecoderField trace_field = *it;
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ ASSERT_EQ(track_event.size(), 0u);
+ }
+}
+
TEST_F(SharedLibTrackEventTest, ScopedSingleLine) {
TracingSession tracing_session = TracingSession::Builder()
.set_data_source_name("track_event")
@@ -1676,4 +1699,172 @@
}
}
+TEST_F(SharedLibTrackEventTest, ScopedCapture) {
+ TracingSession tracing_session = TracingSession::Builder()
+ .set_data_source_name("track_event")
+ .add_enabled_category("*")
+ .Build();
+
+ // Check that the PERFETTO_TE_SCOPED macro can capture variables.
+ uint64_t value = 42;
+ {
+ PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE("slice"),
+ PERFETTO_TE_ARG_UINT64("arg_name", value));
+ }
+
+ tracing_session.StopBlocking();
+ std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ auto trace_view = FieldView(data);
+ auto it = trace_view.begin();
+ for (; it != trace_view.end(); it++) {
+ struct PerfettoPbDecoderField trace_field = *it;
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ if (track_event.size() == 0) {
+ continue;
+ }
+
+ ASSERT_THAT(track_event,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_TrackEvent_type_field_number,
+ ElementsAre(VarIntField(
+ perfetto_protos_TrackEvent_TYPE_SLICE_BEGIN)))));
+ IdFieldView name_iid_fields(
+ track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number);
+ ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_)));
+ uint64_t name_iid = name_iid_fields.front().value.integer64;
+ IdFieldView debug_annot_fields(
+ track_event.front(),
+ perfetto_protos_TrackEvent_debug_annotations_field_number);
+ ASSERT_THAT(
+ debug_annot_fields,
+ ElementsAre(MsgField(UnorderedElementsAre(
+ PbField(perfetto_protos_DebugAnnotation_name_iid_field_number,
+ VarIntField(_)),
+ PbField(perfetto_protos_DebugAnnotation_uint_value_field_number,
+ VarIntField(42))))));
+ uint64_t arg_name_iid =
+ IdFieldView(debug_annot_fields.front(),
+ perfetto_protos_DebugAnnotation_name_iid_field_number)
+ .front()
+ .value.integer64;
+ EXPECT_THAT(
+ trace_field,
+ AllFieldsWithId(
+ perfetto_protos_TracePacket_interned_data_field_number,
+ ElementsAre(AllOf(
+ AllFieldsWithId(
+ perfetto_protos_InternedData_event_names_field_number,
+ ElementsAre(MsgField(UnorderedElementsAre(
+ PbField(perfetto_protos_EventName_iid_field_number,
+ VarIntField(name_iid)),
+ PbField(perfetto_protos_EventName_name_field_number,
+ StringField("slice")))))),
+ AllFieldsWithId(
+ perfetto_protos_InternedData_debug_annotation_names_field_number,
+ ElementsAre(MsgField(UnorderedElementsAre(
+ PbField(
+ perfetto_protos_DebugAnnotationName_iid_field_number,
+ VarIntField(arg_name_iid)),
+ PbField(
+ perfetto_protos_DebugAnnotationName_name_field_number,
+ StringField("arg_name"))))))))));
+ it++;
+ break;
+ }
+ ASSERT_NE(it, trace_view.end());
+ for (; it != trace_view.end(); it++) {
+ struct PerfettoPbDecoderField trace_field = *it;
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ if (track_event.size() == 0) {
+ continue;
+ }
+ ASSERT_THAT(track_event,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_TrackEvent_type_field_number,
+ ElementsAre(VarIntField(
+ perfetto_protos_TrackEvent_TYPE_SLICE_END)))));
+ IdFieldView debug_annot_fields(
+ track_event.front(),
+ perfetto_protos_TrackEvent_debug_annotations_field_number);
+ ASSERT_THAT(debug_annot_fields, ElementsAre());
+ it++;
+ break;
+ }
+}
+
+TEST_F(SharedLibTrackEventTest, ScopedFunc) {
+ TracingSession tracing_session = TracingSession::Builder()
+ .set_data_source_name("track_event")
+ .add_enabled_category("*")
+ .Build();
+
+ // Check that using __func__ works as expected.
+ { PERFETTO_TE_SCOPED(cat1, PERFETTO_TE_SLICE(__func__)); }
+
+ tracing_session.StopBlocking();
+ std::vector<uint8_t> data = tracing_session.ReadBlocking();
+ auto trace_view = FieldView(data);
+ auto it = trace_view.begin();
+ for (; it != trace_view.end(); it++) {
+ struct PerfettoPbDecoderField trace_field = *it;
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ if (track_event.size() == 0) {
+ continue;
+ }
+
+ ASSERT_THAT(track_event,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_TrackEvent_type_field_number,
+ ElementsAre(VarIntField(
+ perfetto_protos_TrackEvent_TYPE_SLICE_BEGIN)))));
+ IdFieldView name_iid_fields(
+ track_event.front(), perfetto_protos_TrackEvent_name_iid_field_number);
+ ASSERT_THAT(name_iid_fields, ElementsAre(VarIntField(_)));
+ uint64_t name_iid = name_iid_fields.front().value.integer64;
+ EXPECT_THAT(trace_field,
+ AllFieldsWithId(
+ perfetto_protos_TracePacket_interned_data_field_number,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_InternedData_event_names_field_number,
+ ElementsAre(MsgField(UnorderedElementsAre(
+ PbField(perfetto_protos_EventName_iid_field_number,
+ VarIntField(name_iid)),
+ PbField(perfetto_protos_EventName_name_field_number,
+ StringField(__func__)))))))));
+ it++;
+ break;
+ }
+ ASSERT_NE(it, trace_view.end());
+ for (; it != trace_view.end(); it++) {
+ struct PerfettoPbDecoderField trace_field = *it;
+ ASSERT_THAT(trace_field, PbField(perfetto_protos_Trace_packet_field_number,
+ MsgField(_)));
+ IdFieldView track_event(
+ trace_field, perfetto_protos_TracePacket_track_event_field_number);
+ if (track_event.size() == 0) {
+ continue;
+ }
+ ASSERT_THAT(track_event,
+ ElementsAre(AllFieldsWithId(
+ perfetto_protos_TrackEvent_type_field_number,
+ ElementsAre(VarIntField(
+ perfetto_protos_TrackEvent_TYPE_SLICE_END)))));
+ IdFieldView debug_annot_fields(
+ track_event.front(),
+ perfetto_protos_TrackEvent_debug_annotations_field_number);
+ ASSERT_THAT(debug_annot_fields, ElementsAre());
+ it++;
+ break;
+ }
+}
+
} // namespace