[tracing] perfetto::Flow

Add perfetto::Flow and perfetto::TerminatingFlow helpers which can be
passed directly to TRACE_EVENT macros to populate the corresponding
proto fields.

R=eseckler@google.com

Change-Id: I7eaac2fdb0fe01872670f7b6754191adfe0fbd14
diff --git a/BUILD b/BUILD
index 264030b..57cbfbd 100644
--- a/BUILD
+++ b/BUILD
@@ -583,6 +583,7 @@
         "include/perfetto/tracing/tracing_policy.h",
         "include/perfetto/tracing/track.h",
         "include/perfetto/tracing/track_event.h",
+        "include/perfetto/tracing/track_event_args.h",
         "include/perfetto/tracing/track_event_category_registry.h",
         "include/perfetto/tracing/track_event_interned_data_index.h",
         "include/perfetto/tracing/track_event_legacy.h",
diff --git a/include/perfetto/tracing/BUILD.gn b/include/perfetto/tracing/BUILD.gn
index b7a91d0..f73dafd 100644
--- a/include/perfetto/tracing/BUILD.gn
+++ b/include/perfetto/tracing/BUILD.gn
@@ -61,6 +61,7 @@
     "tracing_policy.h",
     "track.h",
     "track_event.h",
+    "track_event_args.h",
     "track_event_category_registry.h",
     "track_event_interned_data_index.h",
     "track_event_legacy.h",
diff --git a/include/perfetto/tracing/internal/write_track_event_args.h b/include/perfetto/tracing/internal/write_track_event_args.h
index f34dc3a..f6e3b7f 100644
--- a/include/perfetto/tracing/internal/write_track_event_args.h
+++ b/include/perfetto/tracing/internal/write_track_event_args.h
@@ -20,6 +20,7 @@
 #include "perfetto/base/compiler.h"
 #include "perfetto/tracing/event_context.h"
 #include "perfetto/tracing/traced_proto.h"
+#include "perfetto/tracing/track_event_args.h"
 
 namespace perfetto {
 namespace internal {
diff --git a/include/perfetto/tracing/track_event_args.h b/include/perfetto/tracing/track_event_args.h
new file mode 100644
index 0000000..8e9ec49
--- /dev/null
+++ b/include/perfetto/tracing/track_event_args.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef INCLUDE_PERFETTO_TRACING_TRACK_EVENT_ARGS_H_
+#define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_ARGS_H_
+
+#include "perfetto/tracing/event_context.h"
+
+#include <functional>
+
+namespace perfetto {
+
+// A helper to add |flow_id| as a non-terminating flow id to TRACE_EVENT
+// inline: TRACE_EVENT(..., perfetto::Flow(42));
+PERFETTO_ALWAYS_INLINE inline std::function<void(EventContext&)> Flow(
+    uint64_t flow_id) {
+  return [flow_id](perfetto::EventContext& ctx) {
+    ctx.event()->add_flow_ids(flow_id);
+  };
+}
+
+PERFETTO_ALWAYS_INLINE inline std::function<void(EventContext&)>
+TerminatingFlow(uint64_t flow_id) {
+  return [flow_id](perfetto::EventContext& ctx) {
+    ctx.event()->add_terminating_flow_ids(flow_id);
+  };
+}
+
+}  // namespace perfetto
+
+#endif  // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_ARGS_H_
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index 68c5e6e..a55e5d5 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -661,6 +661,34 @@
         slice += ")";
       }
 
+      if (track_event.flow_ids_size()) {
+        slice += "(flow_ids=";
+        std::stringstream value;
+        bool first_annotation = true;
+        for (uint64_t id : track_event.flow_ids()) {
+          if (!first_annotation) {
+            value << ",";
+          }
+          first_annotation = false;
+          value << id;
+        }
+        slice += value.str() + ")";
+      }
+
+      if (track_event.terminating_flow_ids_size()) {
+        slice += "(terminating_flow_ids=";
+        std::stringstream value;
+        bool first_annotation = true;
+        for (uint64_t id : track_event.terminating_flow_ids()) {
+          if (!first_annotation) {
+            value << ",";
+          }
+          value << id;
+          first_annotation = false;
+        }
+        slice += value.str() + ")";
+      }
+
       slices.push_back(slice);
     }
     EXPECT_TRUE(incremental_state_was_cleared);
@@ -1860,11 +1888,13 @@
   };
 };
 
-void CheckLogMessagePresent(const std::vector<char>& raw_trace) {
+void CheckTypedArguments(
+    const std::vector<char>& raw_trace,
+    std::function<void(const perfetto::protos::gen::TrackEvent&)> checker) {
   perfetto::protos::gen::Trace parsed_trace;
   ASSERT_TRUE(parsed_trace.ParseFromArray(raw_trace.data(), raw_trace.size()));
 
-  bool found_args = false;
+  bool found_begin_slice = false;
   for (const auto& packet : parsed_trace.packet()) {
     if (!packet.has_track_event())
       continue;
@@ -1874,13 +1904,20 @@
       continue;
     }
 
-    EXPECT_TRUE(track_event.has_log_message());
-    const auto& log = track_event.log_message();
-    EXPECT_EQ(1u, log.source_location_iid());
-    EXPECT_EQ(2u, log.body_iid());
-    found_args = true;
+    checker(track_event);
+    found_begin_slice = true;
   }
-  EXPECT_TRUE(found_args);
+  EXPECT_TRUE(found_begin_slice);
+}
+
+void CheckLogMessagePresent(const std::vector<char>& raw_trace) {
+  CheckTypedArguments(raw_trace,
+                      [](const perfetto::protos::gen::TrackEvent& track_event) {
+                        EXPECT_TRUE(track_event.has_log_message());
+                        const auto& log = track_event.log_message();
+                        EXPECT_EQ(1u, log.source_location_iid());
+                        EXPECT_EQ(2u, log.body_iid());
+                      });
 }
 
 }  // namespace
@@ -2100,6 +2137,66 @@
               ElementsAre("B:foo.E(arg=(string)value)"));
 }
 
+TEST_P(PerfettoApiTest, TrackEventArgs_Flow) {
+  // Create a new trace session.
+  auto* tracing_session = NewTraceWithCategories({"foo"});
+  tracing_session->get()->StartBlocking();
+
+  TRACE_EVENT_BEGIN("foo", "E", perfetto::Flow(42));
+  TRACE_EVENT_END("foo");
+
+  tracing_session->get()->StopBlocking();
+
+  std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
+
+  // Find typed argument.
+  CheckTypedArguments(
+      raw_trace, [](const perfetto::protos::gen::TrackEvent& track_event) {
+        EXPECT_THAT(track_event.flow_ids(), testing::ElementsAre(42));
+      });
+}
+
+TEST_P(PerfettoApiTest, TrackEventArgs_TerminatingFlow) {
+  // Create a new trace session.
+  auto* tracing_session = NewTraceWithCategories({"foo"});
+  tracing_session->get()->StartBlocking();
+
+  TRACE_EVENT_BEGIN("foo", "E", perfetto::TerminatingFlow(42));
+  TRACE_EVENT_END("foo");
+
+  tracing_session->get()->StopBlocking();
+
+  std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
+
+  // Find typed argument.
+  CheckTypedArguments(raw_trace,
+                      [](const perfetto::protos::gen::TrackEvent& track_event) {
+                        EXPECT_THAT(track_event.terminating_flow_ids(),
+                                    testing::ElementsAre(42));
+                      });
+}
+
+TEST_P(PerfettoApiTest, TrackEventArgs_MultipleFlows) {
+  // Create a new trace session.
+  auto* tracing_session = NewTraceWithCategories({"foo"});
+  tracing_session->get()->StartBlocking();
+
+  {
+    TRACE_EVENT("foo", "E1", perfetto::Flow(1), perfetto::Flow(2),
+                perfetto::Flow(3));
+  }
+  { TRACE_EVENT("foo", "E2", perfetto::Flow(1), perfetto::TerminatingFlow(2)); }
+  { TRACE_EVENT("foo", "E3", perfetto::TerminatingFlow(3)); }
+
+  tracing_session->get()->StopBlocking();
+
+  std::vector<char> raw_trace = tracing_session->get()->ReadTraceBlocking();
+  EXPECT_THAT(ReadSlicesFromTrace(raw_trace),
+              ElementsAre("B:foo.E1(flow_ids=1,2,3)", "E",
+                          "B:foo.E2(flow_ids=1)(terminating_flow_ids=2)", "E",
+                          "B:foo.E3(terminating_flow_ids=3)"));
+}
+
 struct InternedLogMessageBody
     : public perfetto::TrackEventInternedDataIndex<
           InternedLogMessageBody,