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 "tensorflow/core/platform/env.h"
22 #include "tensorflow/core/platform/logging.h"
23 #include "tensorflow/core/platform/protobuf.h"
24 #include "tensorflow/core/profiler/convert/op_stats_to_input_pipeline_analysis.h"
25 #include "tensorflow/core/profiler/convert/op_stats_to_overview_page.h"
26 #include "tensorflow/core/profiler/convert/op_stats_to_pod_viewer.h"
27 #include "tensorflow/core/profiler/convert/op_stats_to_tf_stats.h"
28 #include "tensorflow/core/profiler/convert/xplane_to_memory_profile.h"
29 #include "tensorflow/core/profiler/convert/xplane_to_op_stats.h"
30 #include "tensorflow/core/profiler/convert/xplane_to_tf_data_stats.h"
31 #include "tensorflow/core/profiler/convert/xplane_to_trace_events.h"
32 #include "tensorflow/core/profiler/protobuf/input_pipeline.pb.h"
33 #include "tensorflow/core/profiler/protobuf/kernel_stats.pb.h"
34 #include "tensorflow/core/profiler/protobuf/op_stats.pb.h"
35 #include "tensorflow/core/profiler/protobuf/overview_page.pb.h"
36 #include "tensorflow/core/profiler/protobuf/pod_viewer.pb.h"
37 #include "tensorflow/core/profiler/protobuf/tf_data_stats.pb.h"
38 #include "tensorflow/core/profiler/protobuf/tf_stats.pb.h"
39 #include "tensorflow/core/profiler/protobuf/xplane.pb.h"
40 #include "tensorflow/core/profiler/utils/xplane_schema.h"
41 #include "tensorflow/core/profiler/utils/xplane_utils.h"
42 
43 namespace tensorflow {
44 namespace profiler {
45 
46 namespace {
47 
ConvertXSpaceToTraceEvents(const std::vector<std::string> & xspace_paths)48 std::pair<std::string, bool> ConvertXSpaceToTraceEvents(
49     const std::vector<std::string>& xspace_paths) {
50   if (xspace_paths.size() != 1) {
51     LOG(WARNING) << "Trace events tool expects only 1 XSpace path but gets "
52                  << xspace_paths.size();
53     return std::make_pair("", false);
54   }
55 
56   XSpace xspace;
57   Status status = ReadBinaryProto(Env::Default(), xspace_paths[0], &xspace);
58   if (!status.ok()) {
59     LOG(WARNING) << "Could not read XSpace for trace events: "
60                  << xspace_paths[0];
61     return std::make_pair("", false);
62   }
63   std::string content;
64   ConvertXSpaceToTraceEventsString(xspace, &content);
65   return std::make_pair(content, true);
66 }
67 
ConvertMultiXSpacesToOverviewPage(const std::vector<std::string> & xspace_paths)68 std::pair<std::string, bool> ConvertMultiXSpacesToOverviewPage(
69     const std::vector<std::string>& xspace_paths) {
70   OpStatsOptions options;
71   options.generate_kernel_stats_db = true;
72   options.generate_op_metrics_db = true;
73   options.generate_step_db = true;
74   OpStats combined_op_stats;
75   Status status = ConvertMultiXSpacesToCombinedOpStats(xspace_paths, options,
76                                                        &combined_op_stats);
77   if (!status.ok()) {
78     LOG(WARNING) << "Could not generate OpStats for overview page. Error: "
79                  << status.error_message();
80     return std::make_pair("", false);
81   }
82   // TODO(profiler): xspace should tell whether this is sampling mode.
83   return std::make_pair(
84       ConvertOpStatsToOverviewPage(combined_op_stats).SerializeAsString(),
85       true);
86 }
87 
ConvertMultiXSpacesToInputPipeline(const std::vector<std::string> & xspace_paths)88 std::pair<std::string, bool> ConvertMultiXSpacesToInputPipeline(
89     const std::vector<std::string>& xspace_paths) {
90   OpStatsOptions options;
91   options.generate_op_metrics_db = true;
92   options.generate_step_db = true;
93   OpStats combined_op_stats;
94   Status status = ConvertMultiXSpacesToCombinedOpStats(xspace_paths, options,
95                                                        &combined_op_stats);
96   if (!status.ok()) {
97     LOG(WARNING) << "Could not generate OpStats for input pipeline. Error: "
98                  << status.error_message();
99     return std::make_pair("", false);
100   }
101   return std::make_pair(ConvertOpStatsToInputPipelineAnalysis(combined_op_stats)
102                             .SerializeAsString(),
103                         true);
104 }
105 
ConvertMultiXSpacesToTfStats(const std::vector<std::string> & xspace_paths)106 std::pair<std::string, bool> ConvertMultiXSpacesToTfStats(
107     const std::vector<std::string>& xspace_paths) {
108   OpStatsOptions options;
109   options.generate_op_metrics_db = true;
110   options.generate_kernel_stats_db = true;
111   OpStats combined_op_stats;
112   Status status = ConvertMultiXSpacesToCombinedOpStats(xspace_paths, options,
113                                                        &combined_op_stats);
114   if (!status.ok()) {
115     LOG(WARNING) << "Could not generate OpStats for tensorflow stats. Error: "
116                  << status.error_message();
117     return std::make_pair("", false);
118   }
119   return std::make_pair(
120       ConvertOpStatsToTfStats(combined_op_stats).SerializeAsString(), true);
121 }
122 
ConvertMultiXSpacesToKernelStats(const std::vector<std::string> & xspace_paths)123 std::pair<std::string, bool> ConvertMultiXSpacesToKernelStats(
124     const std::vector<std::string>& xspace_paths) {
125   OpStatsOptions options;
126   options.generate_kernel_stats_db = true;
127   OpStats combined_op_stats;
128   Status status = ConvertMultiXSpacesToCombinedOpStats(xspace_paths, options,
129                                                        &combined_op_stats);
130   if (!status.ok()) {
131     LOG(WARNING) << "Could not generate OpStats for kernel stats. Error: "
132                  << status.error_message();
133     return std::make_pair("", false);
134   }
135   return std::make_pair(combined_op_stats.kernel_stats_db().SerializeAsString(),
136                         true);
137 }
138 
ConvertXSpaceToMemoryProfile(const std::vector<std::string> & xspace_paths)139 std::pair<std::string, bool> ConvertXSpaceToMemoryProfile(
140     const std::vector<std::string>& xspace_paths) {
141   if (xspace_paths.size() != 1) {
142     LOG(WARNING) << "Memory profile tool expects only 1 XSpace path but gets "
143                  << xspace_paths.size();
144     return std::make_pair("", false);
145   }
146   XSpace xspace;
147   Status status = ReadBinaryProto(Env::Default(), xspace_paths[0], &xspace);
148   if (!status.ok()) {
149     LOG(WARNING) << "Could not read XSpace for memory profile: "
150                  << xspace_paths[0];
151     return std::make_pair("", false);
152   }
153   std::string json_output;
154   status = ConvertXSpaceToMemoryProfileJson(xspace, &json_output);
155   if (!status.ok()) {
156     LOG(WARNING) << "Could not generate memory profile. Error: "
157                  << status.error_message();
158     return std::make_pair("", false);
159   }
160   return std::make_pair(json_output, true);
161 }
162 
ConvertMultiXSpacesToPodViewer(const std::vector<std::string> & xspace_paths)163 std::pair<std::string, bool> ConvertMultiXSpacesToPodViewer(
164     const std::vector<std::string>& xspace_paths) {
165   OpStatsOptions options;
166   options.generate_op_metrics_db = true;
167   options.generate_step_db = true;
168   OpStats combined_op_stats;
169   Status status = ConvertMultiXSpacesToCombinedOpStats(xspace_paths, options,
170                                                        &combined_op_stats);
171   if (!status.ok()) {
172     LOG(WARNING) << "Could not generate OpStats for pod_viewer. Error: "
173                  << status.error_message();
174     return std::make_pair("", false);
175   }
176 
177   std::string json_output;
178   protobuf::util::JsonPrintOptions opts;
179   opts.always_print_primitive_fields = true;
180   auto encode_status = protobuf::util::MessageToJsonString(
181       ConvertOpStatsToPodViewer(combined_op_stats), &json_output, opts);
182   if (!encode_status.ok()) {
183     LOG(WARNING) << "Could not convert pod viewer proto to json. Error: "
184                  << encode_status.message();
185     return std::make_pair("", false);
186   }
187   return std::make_pair(json_output, true);
188 }
189 
ConvertMultiXSpacesToTfDataBottleneckAnalysis(const std::vector<std::string> & xspace_paths)190 std::pair<std::string, bool> ConvertMultiXSpacesToTfDataBottleneckAnalysis(
191     const std::vector<std::string>& xspace_paths) {
192   CombinedTfDataStats combined_tf_data_stats;
193   CombinedTfDataStatsBuilder builder(&combined_tf_data_stats);
194   for (const std::string& xspace_path : xspace_paths) {
195     XSpace xspace;
196     Status status = ReadBinaryProto(Env::Default(), xspace_path, &xspace);
197     if (!status.ok()) {
198       LOG(WARNING) << "Could not read XSpace for tf data stats: "
199                    << xspace_path;
200       return std::make_pair("", false);
201     }
202     XPlane* host_plane =
203         FindMutablePlaneWithName(&xspace, kHostThreadsPlaneName);
204     if (host_plane == nullptr) {
205       LOG(WARNING) << "Could not find host XPlane for tf data stats: "
206                    << xspace_path;
207       return std::make_pair("", false);
208     }
209     absl::string_view host_name =
210         xspace.hostnames_size() ? xspace.hostnames(0) : xspace_path;
211     builder.Add(host_name, host_plane);
212   }
213   builder.Finalize();
214   return std::make_pair(combined_tf_data_stats.SerializeAsString(), true);
215 }
216 
217 }  // namespace
218 
ConvertMultiXSpacesToToolData(const std::vector<std::string> & xspace_paths,const absl::string_view tool_name)219 std::pair<std::string, bool> ConvertMultiXSpacesToToolData(
220     const std::vector<std::string>& xspace_paths,
221     const absl::string_view tool_name) {
222   if (tool_name == "trace_viewer") {
223     return ConvertXSpaceToTraceEvents(xspace_paths);
224   } else if (tool_name == "overview_page") {
225     return ConvertMultiXSpacesToOverviewPage(xspace_paths);
226   } else if (tool_name == "input_pipeline_analyzer") {
227     return ConvertMultiXSpacesToInputPipeline(xspace_paths);
228   } else if (tool_name == "tensorflow_stats") {
229     return ConvertMultiXSpacesToTfStats(xspace_paths);
230   } else if (tool_name == "kernel_stats") {
231     return ConvertMultiXSpacesToKernelStats(xspace_paths);
232   } else if (tool_name == "memory_profile") {
233     return ConvertXSpaceToMemoryProfile(xspace_paths);
234   } else if (tool_name == "pod_viewer") {
235     return ConvertMultiXSpacesToPodViewer(xspace_paths);
236   } else if (tool_name == "tf_data_bottleneck_analysis") {
237     return ConvertMultiXSpacesToTfDataBottleneckAnalysis(xspace_paths);
238   } else {
239     LOG(WARNING) << "Can not find tool: " << tool_name << ". Please update to "
240                  << "the latest version of Tensorflow.";
241     return std::make_pair("", false);
242   }
243 }
244 
245 }  // namespace profiler
246 }  // namespace tensorflow
247