Add StepEvents to StepsDb converter.
PiperOrigin-RevId: 289583730
Change-Id: I3f1ee7750865c8554fb35094ad8d294234af1910
diff --git a/tensorflow/core/profiler/convert/BUILD b/tensorflow/core/profiler/convert/BUILD
index 44f87da..f6f1d58 100644
--- a/tensorflow/core/profiler/convert/BUILD
+++ b/tensorflow/core/profiler/convert/BUILD
@@ -108,6 +108,18 @@
)
cc_library(
+ name = "step_events_to_steps_db",
+ srcs = ["step_events_to_steps_db.cc"],
+ hdrs = ["step_events_to_steps_db.h"],
+ deps = [
+ "//tensorflow/core:lib",
+ "//tensorflow/core:lib_internal",
+ "//tensorflow/core/profiler/protobuf:steps_db_proto_cc",
+ "//tensorflow/core/profiler/utils:event_span",
+ ],
+)
+
+cc_library(
name = "xplane_to_op_stats",
srcs = ["xplane_to_op_stats.cc"],
hdrs = ["xplane_to_op_stats.h"],
diff --git a/tensorflow/core/profiler/convert/step_events_to_steps_db.cc b/tensorflow/core/profiler/convert/step_events_to_steps_db.cc
new file mode 100644
index 0000000..4d48e0b
--- /dev/null
+++ b/tensorflow/core/profiler/convert/step_events_to_steps_db.cc
@@ -0,0 +1,131 @@
+/* Copyright 2020 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/convert/step_events_to_steps_db.h"
+
+#include <sstream>
+
+#include "google/protobuf/any.pb.h"
+#include "tensorflow/core/lib/gtl/map_util.h"
+#include "tensorflow/core/platform/types.h"
+
+namespace tensorflow {
+namespace profiler {
+namespace {
+
+// Converts from StepDetails to StepInfoResult.
+StepInfoResult ConvertStepDetailsToStepInfo(bool has_device, int64 step_num,
+ const StepDetails& step_details) {
+ GenericStepBreakdown generic;
+ Timespan step_time = step_details.StepTime();
+ auto& type_ps = *(generic.mutable_type_ps());
+ uint64 total_event_duration = 0;
+ for (const auto& event : step_details.Events()) {
+ type_ps[event.type] += event.span.duration_ps();
+ total_event_duration += event.span.duration_ps();
+ }
+ if (total_event_duration < step_time.duration_ps()) {
+ // Some time in the step is not associated with any event. Classify them as
+ // "unknown time".
+ type_ps[UNKNOWN_TIME] += step_time.duration_ps() - total_event_duration;
+ }
+ // Determines if this particular step is a well-formed one.
+ bool well_formed_step = has_device ? type_ps.contains(DEVICE_COMPUTE)
+ : type_ps.contains(HOST_COMPUTE);
+ StepInfoResult step_info;
+ step_info.mutable_step_breakdown()->PackFrom(generic);
+ if (well_formed_step) {
+ step_info.set_step_num(step_num);
+ step_info.set_begin_ps(step_time.begin_ps());
+ step_info.set_duration_ps(step_time.duration_ps());
+ } else {
+ // For a non-well-formed step, sets its duration to 0 so that it will be
+ // ignored by the caller of this function.
+ step_info.set_duration_ps(0);
+ }
+ return step_info;
+}
+
+string DebugGenericStepBreakdown(const GenericStepBreakdown& generic) {
+ std::ostringstream out;
+ uint64 total_ps = 0;
+ const auto& type_ps_map = generic.type_ps();
+ for (const auto& type_ps : type_ps_map) {
+ total_ps += type_ps.second;
+ }
+ out << "Total ps = " << total_ps << std::endl;
+ for (int type = LAST_EVENT_TYPE; type >= 0; --type) {
+ const auto* ps = gtl::FindOrNull(type_ps_map, type);
+ if (ps == nullptr) continue;
+ double percent = (*ps * 100.0) / total_ps;
+ auto event_type = static_cast<EventType>(type);
+ out << PrintEventType(event_type) << ": " << percent << "%"
+ << ", ps = " << *ps << std::endl;
+ }
+ return out.str();
+}
+
+string DebugStepInfo(const StepInfoResult& step_info) {
+ std::ostringstream out;
+ out << "step_num=" << step_info.step_num()
+ << ", duration_ps=" << step_info.duration_ps()
+ << ", begin_ps=" << step_info.begin_ps() << std::endl;
+ GenericStepBreakdown generic;
+ if (step_info.step_breakdown().UnpackTo(&generic)) {
+ out << "Generic step breakdown:" << std::endl;
+ out << DebugGenericStepBreakdown(generic) << std::endl;
+ } else {
+ out << step_info.step_breakdown().DebugString() << std::endl;
+ }
+ return out.str();
+}
+
+} // namespace
+
+StepDatabaseResult ConvertStepEventsToStepDb(
+ bool has_device, const StepEvents& overlapped_step_events) {
+ StepDatabaseResult step_db;
+ StepEvents nonoverlapped_step_events =
+ ToNonOverlappedStepEvents(overlapped_step_events);
+ // Gets sorted step numbers.
+ std::vector<int64> step_numbers;
+ step_numbers.reserve(nonoverlapped_step_events.size());
+ for (const auto& step_events : nonoverlapped_step_events) {
+ step_numbers.push_back(step_events.first);
+ }
+ absl::c_sort(step_numbers);
+ for (const auto& step : step_numbers) {
+ StepInfoResult step_info = ConvertStepDetailsToStepInfo(
+ has_device, step, nonoverlapped_step_events[step]);
+ if (step_info.duration_ps() == 0)
+ continue; // Do not include non-well-formed steps.
+ PerCoreStepInfo per_core_step_info;
+ per_core_step_info.set_step_num(step);
+ // When we generated StepEvents, we already put events from all device
+ // cores and cpu threads on this host into a single event stream, therefore
+ // we can't separate them anymore. Simply assigns all events to Core-0.
+ (*per_core_step_info.mutable_step_info_per_core())[0] =
+ std::move(step_info);
+ LOG(INFO) << std::endl
+ << "step_id: " << step << ", step_info:" << std::endl
+ << DebugStepInfo(
+ (*per_core_step_info.mutable_step_info_per_core())[0]);
+ // The remaining fields in PerCoreStepInfo are not filled.
+ *step_db.add_step_sequence() = per_core_step_info;
+ }
+ return step_db;
+}
+
+} // namespace profiler
+} // namespace tensorflow
diff --git a/tensorflow/core/profiler/convert/step_events_to_steps_db.h b/tensorflow/core/profiler/convert/step_events_to_steps_db.h
new file mode 100644
index 0000000..6090cd1
--- /dev/null
+++ b/tensorflow/core/profiler/convert/step_events_to_steps_db.h
@@ -0,0 +1,32 @@
+/* Copyright 2020 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_CONVERT_STEP_EVENTS_TO_STEPS_DB_H_
+#define TENSORFLOW_CORE_PROFILER_CONVERT_STEP_EVENTS_TO_STEPS_DB_H_
+
+#include "tensorflow/core/profiler/protobuf/steps_db.pb.h"
+#include "tensorflow/core/profiler/utils/event_span.h"
+
+namespace tensorflow {
+namespace profiler {
+
+// Converts from overlapped Step-Events to StepDatabaseResult.
+StepDatabaseResult ConvertStepEventsToStepDb(
+ bool has_device, const StepEvents& overlapped_step_events);
+
+} // namespace profiler
+} // namespace tensorflow
+
+#endif // TENSORFLOW_CORE_PROFILER_CONVERT_STEP_EVENTS_TO_STEPS_DB_H_