1 /* Copyright 2016 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/tfprof_options.h"
17
18 #include "absl/strings/str_format.h"
19 #include "absl/strings/str_split.h"
20 #include "tensorflow/core/lib/core/errors.h"
21 #include "tensorflow/core/profiler/tfprof_options.pb.h"
22
23 namespace tensorflow {
24 namespace tfprof {
25 namespace {
KeyValueToStr(const std::map<string,string> & kv_map)26 string KeyValueToStr(const std::map<string, string>& kv_map) {
27 std::vector<string> kv_vec;
28 kv_vec.reserve(kv_map.size());
29 for (const auto& pair : kv_map) {
30 kv_vec.push_back(absl::StrCat(pair.first, "=", pair.second));
31 }
32 return absl::StrJoin(kv_vec, ",");
33 }
34 } // namespace
35
ParseOutput(const string & output_opt,string * output_type,std::map<string,string> * output_options)36 tensorflow::Status ParseOutput(const string& output_opt, string* output_type,
37 std::map<string, string>* output_options) {
38 // The default is to use stdout.
39 if (output_opt.empty()) {
40 *output_type = kOutput[1];
41 return tensorflow::Status::OK();
42 }
43
44 std::set<string> output_types(kOutput,
45 kOutput + sizeof(kOutput) / sizeof(*kOutput));
46 auto opt_split = output_opt.find(':');
47 std::vector<string> kv_split;
48 if (opt_split == output_opt.npos) {
49 if (output_types.find(output_opt) == output_types.end()) {
50 return tensorflow::Status(
51 tensorflow::error::INVALID_ARGUMENT,
52 absl::StrFormat("E.g. Unknown output type: %s, Valid types: %s\n",
53 output_opt, absl::StrJoin(output_types, ",")));
54 }
55 *output_type = output_opt;
56 } else {
57 *output_type = output_opt.substr(0, opt_split);
58 if (output_types.find(*output_type) == output_types.end()) {
59 return tensorflow::Status(
60 tensorflow::error::INVALID_ARGUMENT,
61 absl::StrFormat("E.g. Unknown output type: %s, Valid types: %s\n",
62 *output_type, absl::StrJoin(output_types, ",")));
63 }
64 kv_split = absl::StrSplit(output_opt.substr(opt_split + 1), ",",
65 absl::SkipEmpty());
66 }
67
68 std::set<string> valid_options;
69 std::set<string> required_options;
70 if (*output_type == kOutput[0]) {
71 valid_options.insert(
72 kTimelineOpts,
73 kTimelineOpts + sizeof(kTimelineOpts) / sizeof(*kTimelineOpts));
74 required_options.insert(
75 kTimelineRequiredOpts,
76 kTimelineRequiredOpts +
77 sizeof(kTimelineRequiredOpts) / sizeof(*kTimelineRequiredOpts));
78 } else if (*output_type == kOutput[2]) {
79 valid_options.insert(kFileOpts,
80 kFileOpts + sizeof(kFileOpts) / sizeof(*kFileOpts));
81 required_options.insert(kFileRequiredOpts,
82 kFileRequiredOpts + sizeof(kFileRequiredOpts) /
83 sizeof(*kFileRequiredOpts));
84 } else if (*output_type == kOutput[3]) {
85 valid_options.insert(kPprofOpts,
86 kPprofOpts + sizeof(kPprofOpts) / sizeof(*kPprofOpts));
87 required_options.insert(
88 kPprofRequiredOpts,
89 kPprofRequiredOpts +
90 sizeof(kPprofRequiredOpts) / sizeof(*kPprofRequiredOpts));
91 }
92
93 for (const string& kv_str : kv_split) {
94 const std::vector<string> kv =
95 absl::StrSplit(kv_str, "=", absl::SkipEmpty());
96 if (kv.size() < 2) {
97 return tensorflow::Status(
98 tensorflow::error::INVALID_ARGUMENT,
99 "Visualize format: -output timeline:key=value,key=value,...");
100 }
101 if (valid_options.find(kv[0]) == valid_options.end()) {
102 return tensorflow::Status(
103 tensorflow::error::INVALID_ARGUMENT,
104 absl::StrFormat("Unrecognized options %s for output_type: %s\n",
105 kv[0], *output_type));
106 }
107 const std::vector<string> kv_without_key(kv.begin() + 1, kv.end());
108 (*output_options)[kv[0]] = absl::StrJoin(kv_without_key, "=");
109 }
110
111 for (const string& opt : required_options) {
112 if (output_options->find(opt) == output_options->end()) {
113 return tensorflow::Status(
114 tensorflow::error::INVALID_ARGUMENT,
115 absl::StrFormat("Missing required output_options for %s\n"
116 "E.g. -output %s:%s=...\n",
117 *output_type, *output_type, opt));
118 }
119 }
120 return tensorflow::Status::OK();
121 }
122
FromProtoStr(const string & opts_proto_str,Options * opts)123 tensorflow::Status Options::FromProtoStr(const string& opts_proto_str,
124 Options* opts) {
125 OptionsProto opts_pb;
126 if (!opts_pb.ParseFromString(opts_proto_str)) {
127 return tensorflow::Status(
128 tensorflow::error::INTERNAL,
129 absl::StrCat("Failed to parse option string from Python API: ",
130 opts_proto_str));
131 }
132
133 string output_type;
134 std::map<string, string> output_options;
135 tensorflow::Status s =
136 ParseOutput(opts_pb.output(), &output_type, &output_options);
137 if (!s.ok()) return s;
138
139 if (!opts_pb.dump_to_file().empty()) {
140 absl::FPrintF(stderr,
141 "-dump_to_file option is deprecated. "
142 "Please use -output file:outfile=<filename>\n");
143 absl::FPrintF(stderr,
144 "-output %s is overwritten with -output file:outfile=%s\n",
145 opts_pb.output(), opts_pb.dump_to_file());
146 output_type = kOutput[2];
147 output_options.clear();
148 output_options[kFileOpts[0]] = opts_pb.dump_to_file();
149 }
150
151 *opts = Options(
152 opts_pb.max_depth(), opts_pb.min_bytes(), opts_pb.min_peak_bytes(),
153 opts_pb.min_residual_bytes(), opts_pb.min_output_bytes(),
154 opts_pb.min_micros(), opts_pb.min_accelerator_micros(),
155 opts_pb.min_cpu_micros(), opts_pb.min_params(), opts_pb.min_float_ops(),
156 opts_pb.min_occurrence(), opts_pb.step(), opts_pb.order_by(),
157 std::vector<string>(opts_pb.account_type_regexes().begin(),
158 opts_pb.account_type_regexes().end()),
159 std::vector<string>(opts_pb.start_name_regexes().begin(),
160 opts_pb.start_name_regexes().end()),
161 std::vector<string>(opts_pb.trim_name_regexes().begin(),
162 opts_pb.trim_name_regexes().end()),
163 std::vector<string>(opts_pb.show_name_regexes().begin(),
164 opts_pb.show_name_regexes().end()),
165 std::vector<string>(opts_pb.hide_name_regexes().begin(),
166 opts_pb.hide_name_regexes().end()),
167 opts_pb.account_displayed_op_only(),
168 std::vector<string>(opts_pb.select().begin(), opts_pb.select().end()),
169 output_type, output_options);
170 return tensorflow::Status::OK();
171 }
172
ToString() const173 std::string Options::ToString() const {
174 // clang-format off
175 const std::string s = absl::StrFormat(
176 "%-28s%d\n"
177 "%-28s%d\n"
178 "%-28s%d\n"
179 "%-28s%d\n"
180 "%-28s%d\n"
181 "%-28s%d\n"
182 "%-28s%d\n"
183 "%-28s%d\n"
184 "%-28s%d\n"
185 "%-28s%d\n"
186 "%-28s%d\n"
187 "%-28s%d\n"
188 "%-28s%s\n"
189 "%-28s%s\n"
190 "%-28s%s\n"
191 "%-28s%s\n"
192 "%-28s%s\n"
193 "%-28s%s\n"
194 "%-28s%s\n"
195 "%-28s%s\n"
196 "%-28s%s:%s\n",
197 kOptions[0], max_depth,
198 kOptions[1], min_bytes,
199 kOptions[2], min_peak_bytes,
200 kOptions[3], min_residual_bytes,
201 kOptions[4], min_output_bytes,
202 kOptions[5], min_micros,
203 kOptions[6], min_accelerator_micros,
204 kOptions[7], min_cpu_micros,
205 kOptions[8], min_params,
206 kOptions[9], min_float_ops,
207 kOptions[10], min_occurrence,
208 kOptions[11], step,
209 kOptions[12], order_by,
210 kOptions[13], absl::StrJoin(account_type_regexes, ","),
211 kOptions[14], absl::StrJoin(start_name_regexes, ","),
212 kOptions[15], absl::StrJoin(trim_name_regexes, ","),
213 kOptions[16], absl::StrJoin(show_name_regexes, ","),
214 kOptions[17], absl::StrJoin(hide_name_regexes, ","),
215 kOptions[18], (account_displayed_op_only ? "true" : "false"),
216 kOptions[19], absl::StrJoin(select, ","),
217 kOptions[20], output_type, KeyValueToStr(output_options));
218 // clang-format on
219 return s;
220 }
221
222 } // namespace tfprof
223 } // namespace tensorflow
224