• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2017 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/rpc/client/dump_tpu_profile.h"
17 
18 #include <cstdio>
19 #include <ctime>
20 #include <vector>
21 
22 #include "tensorflow/core/lib/core/errors.h"
23 #include "tensorflow/core/lib/io/compression.h"
24 #include "tensorflow/core/lib/io/path.h"
25 #include "tensorflow/core/lib/strings/str_util.h"
26 #include "tensorflow/core/lib/strings/strcat.h"
27 #include "tensorflow/core/platform/env.h"
28 #include "tensorflow/core/platform/protobuf.h"
29 // Windows.h #defines ERROR, but it is also used in
30 // tensorflow/core/util/event.proto
31 #undef ERROR
32 #include "tensorflow/core/profiler/op_profile.pb.h"
33 #include "tensorflow/core/profiler/rpc/client/trace_events_to_json.h"
34 #include "tensorflow/core/profiler/trace_events.pb.h"
35 #include "tensorflow/core/util/events_writer.h"
36 
37 namespace tensorflow {
38 
39 namespace profiler {
40 namespace client {
41 namespace {
42 
43 using ::tensorflow::io::JoinPath;
44 using ::tensorflow::protobuf::util::JsonOptions;
45 using ::tensorflow::protobuf::util::MessageToJsonString;
46 using ::tensorflow::str_util::EndsWith;
47 using ::tensorflow::strings::StrCat;
48 
49 constexpr char kGraphRunPrefix[] = "tpu_profiler.hlo_graph.";
50 constexpr char kJsonOpProfileFileName[] = "op_profile.json";
51 constexpr char kJsonTraceFileName[] = "trace.json.gz";
52 constexpr char kProfilePluginDirectory[] = "plugins/profile/";
53 constexpr char kProtoTraceFileName[] = "trace";
54 
55 constexpr char kFlatProfilerFileName[] = "flat_profiler.pb";
56 constexpr char kTfStatsHelperSuffix[] = "tf_stats_helper_result";
57 
WriteGzippedDataToFile(const string & filename,const string & data)58 Status WriteGzippedDataToFile(const string& filename, const string& data) {
59   std::unique_ptr<WritableFile> file;
60   TF_RETURN_IF_ERROR(Env::Default()->NewWritableFile(filename, &file));
61   io::ZlibCompressionOptions options = io::ZlibCompressionOptions::GZIP();
62   io::ZlibOutputBuffer buffer(file.get(), options.input_buffer_size,
63                               options.output_buffer_size, options);
64   TF_RETURN_IF_ERROR(buffer.Init());
65   TF_RETURN_IF_ERROR(buffer.Append(data));
66   TF_RETURN_IF_ERROR(buffer.Close());
67   TF_RETURN_IF_ERROR(file->Close());
68   return Status::OK();
69 }
70 
DumpTraceToLogDirectory(StringPiece run_dir,const string & host_prefix,const string & encoded_trace,std::ostream * os)71 Status DumpTraceToLogDirectory(StringPiece run_dir, const string& host_prefix,
72                                const string& encoded_trace, std::ostream* os) {
73   string proto_path =
74       JoinPath(run_dir, StrCat(host_prefix, kProtoTraceFileName));
75   TF_RETURN_IF_ERROR(
76       WriteStringToFile(Env::Default(), proto_path, encoded_trace));
77   LOG(INFO) << "Dumped raw-proto trace data to " << proto_path;
78 
79   string json_path = JoinPath(run_dir, StrCat(host_prefix, kJsonTraceFileName));
80   Trace trace;
81   trace.ParseFromString(encoded_trace);
82   if (os) {
83     *os << "Trace contains " << trace.trace_events_size() << " events."
84         << std::endl;
85   }
86   TF_RETURN_IF_ERROR(
87       WriteGzippedDataToFile(json_path, TraceEventsToJson(trace)));
88   if (os) {
89     *os << "Dumped JSON trace data to " << json_path << std::endl;
90   }
91   return Status::OK();
92 }
93 
DumpOpProfileToLogDirectory(StringPiece run_dir,const string & host_prefix,const op_profile::Profile & profile,std::ostream * os)94 Status DumpOpProfileToLogDirectory(StringPiece run_dir,
95                                    const string& host_prefix,
96                                    const op_profile::Profile& profile,
97                                    std::ostream* os) {
98   string path = JoinPath(run_dir, StrCat(host_prefix, kJsonOpProfileFileName));
99   string json;
100   JsonOptions options;
101   options.always_print_primitive_fields = true;
102   auto status = MessageToJsonString(profile, &json, options);
103   if (!status.ok()) {
104     return errors::Internal(
105         "Failed to convert op profile to json. Skipping... ",
106         string(status.error_message()));
107   }
108   TF_RETURN_IF_ERROR(WriteStringToFile(Env::Default(), path, json));
109   if (os) {
110     *os << "Dumped json op profile data to " << path << std::endl;
111   }
112   return Status::OK();
113 }
114 
DumpToolDataToLogDirectory(StringPiece run_dir,const string & host_prefix,const ProfileToolData & tool,std::ostream * os)115 Status DumpToolDataToLogDirectory(StringPiece run_dir,
116                                   const string& host_prefix,
117                                   const ProfileToolData& tool,
118                                   std::ostream* os) {
119   // Don't save the intermediate results for combining the per host tool data.
120   if (EndsWith(tool.name(), kFlatProfilerFileName) ||
121       EndsWith(tool.name(), kTfStatsHelperSuffix))
122     return Status::OK();
123   string path = JoinPath(run_dir, StrCat(host_prefix, tool.name()));
124   TF_RETURN_IF_ERROR(WriteStringToFile(Env::Default(), path, tool.data()));
125   if (os) {
126     *os << "Dumped tool data for " << tool.name() << " to " << path
127         << std::endl;
128   }
129   return Status::OK();
130 }
131 
132 }  // namespace
133 
WriteTensorboardTPUProfile(const string & logdir,const string & run,const string & host,const ProfileResponse & response,std::ostream * os)134 Status WriteTensorboardTPUProfile(const string& logdir, const string& run,
135                                   const string& host,
136                                   const ProfileResponse& response,
137                                   std::ostream* os) {
138   // Dumps profile data to <logdir>/plugins/profile/<run>/.
139   string host_prefix = host.empty() ? "" : StrCat(host, ".");
140   string profile_run_dir = JoinPath(logdir, kProfilePluginDirectory, run);
141   *os << "Creating directory: " << profile_run_dir;
142   TF_RETURN_IF_ERROR(Env::Default()->RecursivelyCreateDir(profile_run_dir));
143 
144   // Ignore computation_graph for now.
145   if (!response.encoded_trace().empty()) {
146     LOG(INFO) << "Converting trace events to TraceViewer JSON.";
147     TF_RETURN_IF_ERROR(DumpTraceToLogDirectory(profile_run_dir, host_prefix,
148                                                response.encoded_trace(), os));
149   }
150   if (response.has_op_profile() && (response.op_profile().has_by_program() ||
151                                     response.op_profile().has_by_category())) {
152     TF_RETURN_IF_ERROR(DumpOpProfileToLogDirectory(profile_run_dir, host_prefix,
153                                                    response.op_profile(), os));
154   }
155   for (const auto& tool_data : response.tool_data()) {
156     TF_RETURN_IF_ERROR(DumpToolDataToLogDirectory(profile_run_dir, host_prefix,
157                                                   tool_data, os));
158   }
159 
160   return Status::OK();
161 }
162 
163 }  // namespace client
164 }  // namespace profiler
165 }  // namespace tensorflow
166