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 { |
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 | |
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 OkStatus(); |
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 OkStatus(); |
121 | } |
122 | |
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 OkStatus(); |
171 | } |
172 | |
173 | 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 | |