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