1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/core/profiler/convert/xplane_to_tools_data.h"
17
18 #include <utility>
19 #include <vector>
20
21 #include "absl/strings/str_format.h"
22 #include "absl/strings/string_view.h"
23 #include "tensorflow/core/platform/env.h"
24 #include "tensorflow/core/platform/logging.h"
25 #include "tensorflow/core/platform/protobuf.h"
26 #include "tensorflow/core/profiler/convert/op_stats_to_input_pipeline_analysis.h"
27 #include "tensorflow/core/profiler/convert/op_stats_to_overview_page.h"
28 #include "tensorflow/core/profiler/convert/op_stats_to_pod_viewer.h"
29 #include "tensorflow/core/profiler/convert/op_stats_to_tf_stats.h"
30 #include "tensorflow/core/profiler/convert/xplane_to_memory_profile.h"
31 #include "tensorflow/core/profiler/convert/xplane_to_op_stats.h"
32 #include "tensorflow/core/profiler/convert/xplane_to_tf_data_stats.h"
33 #include "tensorflow/core/profiler/convert/xplane_to_trace_events.h"
34 #include "tensorflow/core/profiler/protobuf/input_pipeline.pb.h"
35 #include "tensorflow/core/profiler/protobuf/kernel_stats.pb.h"
36 #include "tensorflow/core/profiler/protobuf/op_stats.pb.h"
37 #include "tensorflow/core/profiler/protobuf/overview_page.pb.h"
38 #include "tensorflow/core/profiler/protobuf/pod_viewer.pb.h"
39 #include "tensorflow/core/profiler/protobuf/tf_data_stats.pb.h"
40 #include "tensorflow/core/profiler/protobuf/tf_stats.pb.h"
41 #include "tensorflow/core/profiler/protobuf/xplane.pb.h"
42 #include "tensorflow/core/profiler/utils/xplane_schema.h"
43 #include "tensorflow/core/profiler/utils/xplane_utils.h"
44
45 namespace tensorflow {
46 namespace profiler {
47
48 namespace {
49
ConvertXSpaceToTraceEvents(const std::vector<XSpace> & xspaces)50 std::pair<std::string, bool> ConvertXSpaceToTraceEvents(
51 const std::vector<XSpace>& xspaces) {
52 if (xspaces.size() != 1) {
53 LOG(WARNING) << "Trace events tool expects only 1 XSpace path but gets "
54 << xspaces.size();
55 return std::make_pair("", false);
56 }
57
58 std::string content;
59 ConvertXSpaceToTraceEventsString(xspaces[0], &content);
60 return std::make_pair(content, true);
61 }
62
ConvertMultiXSpacesToOverviewPage(const std::vector<XSpace> & xspaces)63 std::pair<std::string, bool> ConvertMultiXSpacesToOverviewPage(
64 const std::vector<XSpace>& xspaces) {
65 OpStatsOptions options;
66 options.generate_kernel_stats_db = true;
67 options.generate_op_metrics_db = true;
68 options.generate_step_db = true;
69 OpStats combined_op_stats;
70 Status status = ConvertMultiXSpacesToCombinedOpStats(xspaces, options,
71 &combined_op_stats);
72 if (!status.ok()) {
73 LOG(WARNING) << "Could not generate OpStats for overview page. Error: "
74 << status.error_message();
75 return std::make_pair("", false);
76 }
77 // TODO(profiler): xspace should tell whether this is sampling mode.
78 return std::make_pair(
79 ConvertOpStatsToOverviewPage(combined_op_stats).SerializeAsString(),
80 true);
81 }
82
ConvertMultiXSpacesToInputPipeline(const std::vector<XSpace> & xspaces)83 std::pair<std::string, bool> ConvertMultiXSpacesToInputPipeline(
84 const std::vector<XSpace>& xspaces) {
85 OpStatsOptions options;
86 options.generate_op_metrics_db = true;
87 options.generate_step_db = true;
88 OpStats combined_op_stats;
89 Status status = ConvertMultiXSpacesToCombinedOpStats(xspaces, options,
90 &combined_op_stats);
91 if (!status.ok()) {
92 LOG(WARNING) << "Could not generate OpStats for input pipeline. Error: "
93 << status.error_message();
94 return std::make_pair("", false);
95 }
96 return std::make_pair(ConvertOpStatsToInputPipelineAnalysis(combined_op_stats)
97 .SerializeAsString(),
98 true);
99 }
100
ConvertMultiXSpacesToTfStats(const std::vector<XSpace> & xspaces)101 std::pair<std::string, bool> ConvertMultiXSpacesToTfStats(
102 const std::vector<XSpace>& xspaces) {
103 OpStatsOptions options;
104 options.generate_op_metrics_db = true;
105 options.generate_kernel_stats_db = true;
106 OpStats combined_op_stats;
107 Status status = ConvertMultiXSpacesToCombinedOpStats(xspaces, options,
108 &combined_op_stats);
109 if (!status.ok()) {
110 LOG(WARNING) << "Could not generate OpStats for tensorflow stats. Error: "
111 << status.error_message();
112 return std::make_pair("", false);
113 }
114 return std::make_pair(
115 ConvertOpStatsToTfStats(combined_op_stats).SerializeAsString(), true);
116 }
117
ConvertMultiXSpacesToKernelStats(const std::vector<XSpace> & xspaces)118 std::pair<std::string, bool> ConvertMultiXSpacesToKernelStats(
119 const std::vector<XSpace>& xspaces) {
120 OpStatsOptions options;
121 options.generate_kernel_stats_db = true;
122 OpStats combined_op_stats;
123 Status status = ConvertMultiXSpacesToCombinedOpStats(xspaces, options,
124 &combined_op_stats);
125 if (!status.ok()) {
126 LOG(WARNING) << "Could not generate OpStats for kernel stats. Error: "
127 << status.error_message();
128 return std::make_pair("", false);
129 }
130 return std::make_pair(combined_op_stats.kernel_stats_db().SerializeAsString(),
131 true);
132 }
133
ConvertXSpaceToMemoryProfile(const std::vector<XSpace> & xspaces)134 std::pair<std::string, bool> ConvertXSpaceToMemoryProfile(
135 const std::vector<XSpace>& xspaces) {
136 if (xspaces.size() != 1) {
137 LOG(WARNING) << "Memory profile tool expects only 1 XSpace path but gets "
138 << xspaces.size();
139 return std::make_pair("", false);
140 }
141 std::string json_output;
142 Status status;
143 status = ConvertXSpaceToMemoryProfileJson(xspaces[0], &json_output);
144 if (!status.ok()) {
145 LOG(WARNING) << "Could not generate memory profile. Error: "
146 << status.error_message();
147 return std::make_pair("", false);
148 }
149 return std::make_pair(json_output, true);
150 }
151
ConvertMultiXSpacesToPodViewer(const std::vector<XSpace> & xspaces)152 std::pair<std::string, bool> ConvertMultiXSpacesToPodViewer(
153 const std::vector<XSpace>& xspaces) {
154 OpStatsOptions options;
155 options.generate_op_metrics_db = true;
156 options.generate_step_db = true;
157 OpStats combined_op_stats;
158 Status status = ConvertMultiXSpacesToCombinedOpStats(xspaces, options,
159 &combined_op_stats);
160 if (!status.ok()) {
161 LOG(WARNING) << "Could not generate OpStats for pod_viewer. Error: "
162 << status.error_message();
163 return std::make_pair("", false);
164 }
165
166 std::string json_output;
167 protobuf::util::JsonPrintOptions opts;
168 opts.always_print_primitive_fields = true;
169 auto encode_status = protobuf::util::MessageToJsonString(
170 ConvertOpStatsToPodViewer(combined_op_stats), &json_output, opts);
171 if (!encode_status.ok()) {
172 LOG(WARNING) << "Could not convert pod viewer proto to json. Error: "
173 << encode_status.message();
174 return std::make_pair("", false);
175 }
176 return std::make_pair(json_output, true);
177 }
178
ConvertMultiXSpacesToTfDataBottleneckAnalysis(const std::vector<XSpace> & xspaces,const std::vector<std::string> & filenames)179 std::pair<std::string, bool> ConvertMultiXSpacesToTfDataBottleneckAnalysis(
180 const std::vector<XSpace>& xspaces,
181 const std::vector<std::string>& filenames) {
182 CombinedTfDataStats combined_tf_data_stats;
183 CombinedTfDataStatsBuilder builder(&combined_tf_data_stats);
184
185 std::vector<XSpace> mutable_xspaces = xspaces;
186
187 for (int idx = 0; idx < mutable_xspaces.size(); ++idx) {
188 XPlane* host_plane =
189 FindMutablePlaneWithName(&mutable_xspaces[idx], kHostThreadsPlaneName);
190 if (host_plane == nullptr) {
191 LOG(WARNING) << "Could not find host XPlane for tf data stats: ";
192 return std::make_pair("", false);
193 }
194 absl::string_view host_name = mutable_xspaces[idx].hostnames_size()
195 ? mutable_xspaces[idx].hostnames(0)
196 : filenames[idx];
197 builder.Add(host_name, host_plane);
198 }
199 builder.Finalize();
200 return std::make_pair(combined_tf_data_stats.SerializeAsString(), true);
201 }
202
203 } // namespace
204
ConvertMultiXSpacesToToolData(const std::vector<XSpace> & xspaces,const std::vector<std::string> & filenames,const absl::string_view tool_name)205 std::pair<std::string, bool> ConvertMultiXSpacesToToolData(
206 const std::vector<XSpace>& xspaces,
207 const std::vector<std::string>& filenames,
208 const absl::string_view tool_name) {
209 if (tool_name == "trace_viewer") {
210 return ConvertXSpaceToTraceEvents(xspaces);
211 } else if (tool_name == "overview_page") {
212 return ConvertMultiXSpacesToOverviewPage(xspaces);
213 } else if (tool_name == "input_pipeline_analyzer") {
214 return ConvertMultiXSpacesToInputPipeline(xspaces);
215 } else if (tool_name == "tensorflow_stats") {
216 return ConvertMultiXSpacesToTfStats(xspaces);
217 } else if (tool_name == "kernel_stats") {
218 return ConvertMultiXSpacesToKernelStats(xspaces);
219 } else if (tool_name == "memory_profile") {
220 return ConvertXSpaceToMemoryProfile(xspaces);
221 } else if (tool_name == "pod_viewer") {
222 return ConvertMultiXSpacesToPodViewer(xspaces);
223 } else if (tool_name == "tf_data_bottleneck_analysis") {
224 return ConvertMultiXSpacesToTfDataBottleneckAnalysis(xspaces, filenames);
225 } else {
226 LOG(WARNING) << "Can not find tool: " << tool_name << ". Please update to "
227 << "the latest version of Tensorflow.";
228 return std::make_pair("", false);
229 }
230 }
231
232 } // namespace profiler
233 } // namespace tensorflow
234