Extract :host_tracer_utils library

PiperOrigin-RevId: 282582745
Change-Id: I8866d4ff7c43376cdfaaea7b93e6f6cf5452f7ee
diff --git a/tensorflow/core/profiler/internal/cpu/BUILD b/tensorflow/core/profiler/internal/cpu/BUILD
index 5d7f7d6..93fc8e0 100644
--- a/tensorflow/core/profiler/internal/cpu/BUILD
+++ b/tensorflow/core/profiler/internal/cpu/BUILD
@@ -6,19 +6,32 @@
 )
 
 cc_library(
-    name = "host_tracer",
-    srcs = ["host_tracer.cc"],
+    name = "host_tracer_utils",
+    srcs = ["host_tracer_utils.cc"],
+    hdrs = ["host_tracer_utils.h"],
+    visibility = ["//tensorflow/core/profiler:friends"],
     deps = [
-        "//tensorflow/core:core_cpu_lib",
         "//tensorflow/core:lib",
-        "//tensorflow/core:lib_internal",
-        "//tensorflow/core:protos_all_cc",
         "//tensorflow/core/profiler/internal:parse_annotation",
-        "//tensorflow/core/profiler/internal:profiler_interface",
         "//tensorflow/core/profiler/internal:traceme_recorder",
         "//tensorflow/core/profiler/protobuf:xplane_proto_cc",
         "//tensorflow/core/profiler/utils:xplane_builder",
         "@com_google_absl//absl/container:flat_hash_map",
+    ],
+)
+
+cc_library(
+    name = "host_tracer",
+    srcs = ["host_tracer.cc"],
+    deps = [
+        ":host_tracer_utils",
+        "//tensorflow/core:core_cpu_lib",
+        "//tensorflow/core:lib",
+        "//tensorflow/core:lib_internal",
+        "//tensorflow/core:protos_all_cc",
+        "//tensorflow/core/profiler/internal:profiler_interface",
+        "//tensorflow/core/profiler/internal:traceme_recorder",
+        "//tensorflow/core/profiler/protobuf:xplane_proto_cc",
         "@com_google_absl//absl/strings",
     ],
     alwayslink = True,
diff --git a/tensorflow/core/profiler/internal/cpu/host_tracer.cc b/tensorflow/core/profiler/internal/cpu/host_tracer.cc
index 829efb9..9b32ce8 100644
--- a/tensorflow/core/profiler/internal/cpu/host_tracer.cc
+++ b/tensorflow/core/profiler/internal/cpu/host_tracer.cc
@@ -15,22 +15,19 @@
 #include <utility>
 #include <vector>
 
-#include "absl/container/flat_hash_map.h"
 #include "absl/strings/str_split.h"
 #include "tensorflow/core/common_runtime/step_stats_collector.h"
 #include "tensorflow/core/lib/core/status.h"
 #include "tensorflow/core/platform/env_time.h"
-#include "tensorflow/core/profiler/internal/parse_annotation.h"
+#include "tensorflow/core/profiler/internal/cpu/host_tracer_utils.h"
 #include "tensorflow/core/profiler/internal/profiler_interface.h"
 #include "tensorflow/core/profiler/internal/traceme_recorder.h"
 #include "tensorflow/core/profiler/protobuf/xplane.pb.h"
-#include "tensorflow/core/profiler/utils/xplane_builder.h"
 #include "tensorflow/core/protobuf/config.pb.h"
 #include "tensorflow/core/util/env_var.h"
 
 namespace tensorflow {
 namespace profiler {
-namespace cpu {
 namespace {
 
 // Controls TraceMeRecorder and converts TraceMeRecorder::Events into
@@ -57,10 +54,6 @@
   DeviceType GetDeviceType() override { return DeviceType::kCpu; }
 
  private:
-  // Combine events created by TraceMe::ActivityStart and TraceMe::ActivityEnd,
-  // which can be paired up by their activity_id.
-  void MakeCompleteEvents();
-
   // Level of host tracing.
   const int host_trace_level_;
 
@@ -100,49 +93,11 @@
   return Status::OK();
 }
 
-void HostTracer::MakeCompleteEvents() {
-  // Track events create by ActivityStart and copy their data to events created
-  // by ActivityEnd. TraceME records events in its destructor, so this results
-  // in complete events sorted by their end_time in the thread they ended.
-  // Within the same thread, the record created by ActivityStart must appear
-  // before the record created by ActivityEnd. Cross-thread events must be
-  // processed in a separate pass. A single map can be used because the
-  // activity_id is globally unique.
-  absl::flat_hash_map<uint64, TraceMeRecorder::Event*> start_events;
-  std::vector<TraceMeRecorder::Event*> end_events;
-  for (auto& thread : events_) {
-    for (auto& event : thread.events) {
-      if (event.start_time && !event.end_time) {  // ActivityStart
-        start_events.emplace(event.activity_id, &event);
-      } else if (!event.start_time && event.end_time) {  // ActivityEnd
-        auto iter = start_events.find(event.activity_id);
-        if (iter != start_events.end()) {  // same thread
-          auto* start_event = iter->second;
-          event.name = std::move(start_event->name);
-          event.start_time = start_event->start_time;
-          start_events.erase(iter);
-        } else {  // cross-thread
-          end_events.push_back(&event);
-        }
-      }
-    }
-  }
-  for (auto* event : end_events) {  // cross-thread
-    auto iter = start_events.find(event->activity_id);
-    if (iter != start_events.end()) {
-      auto* start_event = iter->second;
-      event->name = std::move(start_event->name);
-      event->start_time = start_event->start_time;
-      start_events.erase(iter);
-    }
-  }
-}
-
 Status HostTracer::CollectData(RunMetadata* run_metadata) {
   if (recording_) {
     return errors::Internal("TraceMeRecorder not stopped");
   }
-  MakeCompleteEvents();
+  MakeCompleteEvents(&events_);
   StepStatsCollector step_stats_collector(run_metadata->mutable_step_stats());
 
   constexpr char kUserMetadataMarker = '#';
@@ -183,43 +138,9 @@
   if (recording_) {
     return errors::Internal("TraceMeRecorder not stopped");
   }
-  MakeCompleteEvents();
-  XPlaneBuilder xplane(space->add_planes());
-  xplane.SetName("Host Threads");
-  absl::flat_hash_map<string, XEventMetadata*> xevent_metadata_by_name;
-  absl::flat_hash_map<string, XStatMetadata*> xstat_metadata_by_name;
-  for (const auto& thread : events_) {
-    XLineBuilder xline = xplane.AddLine();
-    xline.SetId(thread.thread.tid);
-    xline.SetName(thread.thread.name);
-    xline.SetTimestampNs(start_timestamp_ns_);
-    xline.ReserveEvents(thread.events.size());
-    for (const auto& event : thread.events) {
-      if (event.start_time && event.end_time) {
-        Annotation annotation = ParseAnnotation(event.name);
-        XEventMetadata*& xevent_metadata =
-            xevent_metadata_by_name[annotation.name];
-        if (xevent_metadata == nullptr) {
-          xevent_metadata =
-              xplane.GetOrCreateEventMetadata(xevent_metadata_by_name.size());
-          xevent_metadata->set_name(string(annotation.name));
-        }
-        XEventBuilder xevent = xline.AddEvent(*xevent_metadata);
-        xevent.SetTimestampNs(event.start_time);
-        xevent.SetEndTimestampNs(event.end_time);
-        xevent.ReserveStats(annotation.metadata.size());
-        for (const auto& metadata : annotation.metadata) {
-          XStatMetadata*& xstat_metadata = xstat_metadata_by_name[metadata.key];
-          if (xstat_metadata == nullptr) {
-            xstat_metadata =
-                xplane.GetOrCreateStatMetadata(xstat_metadata_by_name.size());
-            xstat_metadata->set_name(string(metadata.key));
-          }
-          xevent.ParseAndAddStatValue(*xstat_metadata, metadata.value);
-        }
-      }
-    }
-  }
+  MakeCompleteEvents(&events_);
+  ConvertCompleteEventsToXPlane(start_timestamp_ns_, events_,
+                                space->add_planes());
   events_.clear();
   return Status::OK();
 }
@@ -242,6 +163,5 @@
   return 0;
 }();
 
-}  // namespace cpu
 }  // namespace profiler
 }  // namespace tensorflow
diff --git a/tensorflow/core/profiler/internal/cpu/host_tracer_test.cc b/tensorflow/core/profiler/internal/cpu/host_tracer_test.cc
index c88d7fa..7623a4e 100644
--- a/tensorflow/core/profiler/internal/cpu/host_tracer_test.cc
+++ b/tensorflow/core/profiler/internal/cpu/host_tracer_test.cc
@@ -28,7 +28,6 @@
 
 namespace tensorflow {
 namespace profiler {
-namespace cpu {
 
 std::unique_ptr<ProfilerInterface> CreateHostTracer(
     const ProfilerOptions& options);
@@ -169,6 +168,5 @@
 }
 
 }  // namespace
-}  // namespace cpu
 }  // namespace profiler
 }  // namespace tensorflow
diff --git a/tensorflow/core/profiler/internal/cpu/host_tracer_utils.cc b/tensorflow/core/profiler/internal/cpu/host_tracer_utils.cc
new file mode 100644
index 0000000..099cd1a
--- /dev/null
+++ b/tensorflow/core/profiler/internal/cpu/host_tracer_utils.cc
@@ -0,0 +1,109 @@
+/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+
+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.
+==============================================================================*/
+#include "tensorflow/core/profiler/internal/cpu/host_tracer_utils.h"
+
+#include <utility>
+#include <vector>
+
+#include "absl/container/flat_hash_map.h"
+#include "tensorflow/core/profiler/internal/parse_annotation.h"
+#include "tensorflow/core/profiler/internal/traceme_recorder.h"
+#include "tensorflow/core/profiler/protobuf/xplane.pb.h"
+#include "tensorflow/core/profiler/utils/xplane_builder.h"
+
+namespace tensorflow {
+namespace profiler {
+
+void MakeCompleteEvents(TraceMeRecorder::Events* events) {
+  // Track events created by ActivityStart and copy their data to events created
+  // by ActivityEnd. TraceMe records events in its destructor, so this results
+  // in complete events sorted by their end_time in the thread they ended.
+  // Within the same thread, the record created by ActivityStart must appear
+  // before the record created by ActivityEnd. Cross-thread events must be
+  // processed in a separate pass. A single map can be used because the
+  // activity_id is globally unique.
+  absl::flat_hash_map<uint64, TraceMeRecorder::Event*> start_events;
+  std::vector<TraceMeRecorder::Event*> end_events;
+  for (auto& thread : *events) {
+    for (auto& event : thread.events) {
+      if (event.start_time && !event.end_time) {  // ActivityStart
+        start_events.emplace(event.activity_id, &event);
+      } else if (!event.start_time && event.end_time) {  // ActivityEnd
+        auto iter = start_events.find(event.activity_id);
+        if (iter != start_events.end()) {  // same thread
+          auto* start_event = iter->second;
+          event.name = std::move(start_event->name);
+          event.start_time = start_event->start_time;
+          start_events.erase(iter);
+        } else {  // cross-thread
+          end_events.push_back(&event);
+        }
+      }
+    }
+  }
+  for (auto* event : end_events) {  // cross-thread
+    auto iter = start_events.find(event->activity_id);
+    if (iter != start_events.end()) {
+      auto* start_event = iter->second;
+      event->name = std::move(start_event->name);
+      event->start_time = start_event->start_time;
+      start_events.erase(iter);
+    }
+  }
+}
+
+void ConvertCompleteEventsToXPlane(uint64 start_timestamp_ns,
+                                   const TraceMeRecorder::Events& events,
+                                   XPlane* raw_plane) {
+  XPlaneBuilder xplane(raw_plane);
+  xplane.SetName("Host Threads");
+  absl::flat_hash_map<string, XEventMetadata*> xevent_metadata_by_name;
+  absl::flat_hash_map<string, XStatMetadata*> xstat_metadata_by_name;
+  for (const auto& thread : events) {
+    XLineBuilder xline = xplane.AddLine();
+    xline.SetId(thread.thread.tid);
+    xline.SetName(thread.thread.name);
+    xline.SetTimestampNs(start_timestamp_ns);
+    xline.ReserveEvents(thread.events.size());
+    for (const auto& event : thread.events) {
+      if (event.start_time && event.end_time) {
+        Annotation annotation = ParseAnnotation(event.name);
+        XEventMetadata*& xevent_metadata =
+            xevent_metadata_by_name[annotation.name];
+        if (xevent_metadata == nullptr) {
+          xevent_metadata =
+              xplane.GetOrCreateEventMetadata(xevent_metadata_by_name.size());
+          xevent_metadata->set_name(string(annotation.name));
+        }
+        XEventBuilder xevent = xline.AddEvent(*xevent_metadata);
+        xevent.SetTimestampNs(event.start_time);
+        xevent.SetEndTimestampNs(event.end_time);
+        xevent.ReserveStats(annotation.metadata.size());
+        for (const auto& metadata : annotation.metadata) {
+          XStatMetadata*& xstat_metadata = xstat_metadata_by_name[metadata.key];
+          if (xstat_metadata == nullptr) {
+            xstat_metadata =
+                xplane.GetOrCreateStatMetadata(xstat_metadata_by_name.size());
+            xstat_metadata->set_name(string(metadata.key));
+          }
+          xevent.ParseAndAddStatValue(*xstat_metadata, metadata.value);
+        }
+      }
+    }
+  }
+}
+
+}  // namespace profiler
+}  // namespace tensorflow
diff --git a/tensorflow/core/profiler/internal/cpu/host_tracer_utils.h b/tensorflow/core/profiler/internal/cpu/host_tracer_utils.h
new file mode 100644
index 0000000..e422760
--- /dev/null
+++ b/tensorflow/core/profiler/internal/cpu/host_tracer_utils.h
@@ -0,0 +1,37 @@
+/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+
+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 TENSORFLOW_CORE_PROFILER_INTERNAL_CPU_HOST_TRACER_UTILS_H_
+#define TENSORFLOW_CORE_PROFILER_INTERNAL_CPU_HOST_TRACER_UTILS_H_
+
+#include "tensorflow/core/platform/types.h"
+#include "tensorflow/core/profiler/internal/traceme_recorder.h"
+#include "tensorflow/core/profiler/protobuf/xplane.pb.h"
+
+namespace tensorflow {
+namespace profiler {
+
+// Combine events created by TraceMe::ActivityStart and TraceMe::ActivityEnd,
+// which can be paired up by their activity_id.
+void MakeCompleteEvents(TraceMeRecorder::Events* events);
+
+// Convert complete events to XPlane format.
+void ConvertCompleteEventsToXPlane(uint64 start_timestamp_ns,
+                                   const TraceMeRecorder::Events& events,
+                                   XPlane* raw_plane);
+
+}  // namespace profiler
+}  // namespace tensorflow
+
+#endif  // TENSORFLOW_CORE_PROFILER_INTERNAL_CPU_HOST_TRACER_UTILS_H_