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/internal/tfprof_show.h"
17
18 #include <memory>
19 #include <set>
20
21 #include "absl/strings/str_format.h"
22 #include "absl/strings/str_join.h"
23 #include "tensorflow/core/platform/env.h"
24 #include "tensorflow/core/platform/regexp.h"
25
26 namespace tensorflow {
27 namespace tfprof {
28
Show(const string & prefix,const Options & opts)29 const GraphNodeProto& TFShow::Show(const string& prefix, const Options& opts) {
30 if (opts.output_type == kOutput[0]) {
31 Timeline timeline(opts.step, opts.output_options.at(kTimelineOpts[0]));
32 return ShowInternal(opts, &timeline)->proto();
33 } else {
34 const ShowNode* ret = ShowInternal(opts, nullptr);
35 if (opts.output_type == kOutput[1]) {
36 absl::PrintF("%s", (prefix + ret->formatted_str));
37 fflush(stdout);
38 } else if (opts.output_type == kOutput[2]) {
39 Status s = WriteStringToFile(Env::Default(),
40 opts.output_options.at(kFileOpts[0]),
41 prefix + ret->formatted_str);
42 if (!s.ok()) {
43 absl::FPrintF(stderr, "%s\n", s.ToString());
44 }
45 } else if (opts.output_type == kOutput[3] ||
46 opts.output_type == kOutput[4]) {
47 } else {
48 absl::FPrintF(stderr, "Unknown output type: %s\n", opts.output_type);
49 }
50 return ret->proto();
51 }
52 }
53
LookUpCheckPoint(const string & name,std::unique_ptr<TFProfTensor> * tensor)54 bool TFShow::LookUpCheckPoint(const string& name,
55 std::unique_ptr<TFProfTensor>* tensor) {
56 if (name == kTFProfRoot || !ckpt_reader_ || !tensor) {
57 return false;
58 }
59 std::unique_ptr<Tensor> out_tensor;
60 TF_Status* status = TF_NewStatus();
61 ckpt_reader_->GetTensor(name, &out_tensor, status);
62 if (TF_GetCode(status) != TF_OK) {
63 absl::FPrintF(stderr, "%s\n", TF_Message(status));
64 TF_DeleteStatus(status);
65 return false;
66 }
67 tensor->reset(new TFProfTensor(std::move(out_tensor)));
68 TF_DeleteStatus(status);
69 return true;
70 }
71
ShouldShow(const ShowNode * node,const Options & opts,int depth) const72 bool TFShow::ShouldShow(const ShowNode* node, const Options& opts,
73 int depth) const {
74 // Always show kTFProfRoot.
75 if (node->name() == kTFProfRoot) return true;
76
77 if (node->proto().total_requested_bytes() < opts.min_bytes ||
78 node->proto().total_peak_bytes() < opts.min_peak_bytes ||
79 node->proto().total_residual_bytes() < opts.min_residual_bytes ||
80 node->proto().total_output_bytes() < opts.min_output_bytes ||
81 node->proto().total_exec_micros() < opts.min_micros ||
82 node->proto().total_accelerator_exec_micros() <
83 opts.min_accelerator_micros ||
84 node->proto().total_cpu_exec_micros() < opts.min_cpu_micros ||
85 node->proto().parameters() < opts.min_params ||
86 node->proto().float_ops() < opts.min_float_ops ||
87 node->proto().run_count() < opts.min_occurrence ||
88 depth > opts.max_depth || !ShouldShowIfExtra(node, opts, depth)) {
89 return false;
90 }
91
92 bool show = false;
93 if (opts.show_name_regexes.size() == 1 && opts.show_name_regexes[0] == ".*") {
94 show = true;
95 } else {
96 for (const string& regex : opts.show_name_regexes) {
97 if (RE2::FullMatch(node->name(), regex)) {
98 show = true;
99 break;
100 }
101 }
102 }
103 // Don't show if show_name_regexes don't cover it.
104 if (!show) return false;
105 // Don't show if hide_name_regexes cover it.
106 for (const string& regex : opts.hide_name_regexes) {
107 if (RE2::FullMatch(node->name(), regex)) return false;
108 }
109 return true;
110 }
111
ShouldTrim(const ShowNode * node,const std::vector<string> & regexes) const112 bool TFShow::ShouldTrim(const ShowNode* node,
113 const std::vector<string>& regexes) const {
114 for (const string& regex : regexes) {
115 if (RE2::FullMatch(node->name(), regex)) {
116 return true;
117 }
118 }
119 return false;
120 }
121
ReAccount(ShowNode * node,const Options & opts)122 bool TFShow::ReAccount(ShowNode* node, const Options& opts) {
123 node->ReInit(opts.step);
124 if (opts.account_type_regexes.size() == 1 &&
125 opts.account_type_regexes[0] == ".*") {
126 return true;
127 }
128 for (const string& regex : opts.account_type_regexes) {
129 for (const string& type : node->node->op_types()) {
130 if (RE2::FullMatch(type, regex)) {
131 return true;
132 }
133 }
134 }
135 return false;
136 }
137
FormatNodeMemory(ShowNode * node,int64_t bytes,int64_t total_bytes) const138 string TFShow::FormatNodeMemory(ShowNode* node, int64_t bytes,
139 int64_t total_bytes) const {
140 string memory = FormatMemory(total_bytes);
141 if (node->account) {
142 memory = FormatMemory(bytes) + "/" + memory;
143 } else {
144 memory = "--/" + memory;
145 }
146 return memory;
147 }
148
FormatNode(ShowNode * node,const Options & opts) const149 string TFShow::FormatNode(ShowNode* node, const Options& opts) const {
150 std::vector<string> info;
151 if (opts.select.find(kShown[2]) != opts.select.end()) {
152 const string shape = FormatShapes(node->node->shape());
153 if (!shape.empty()) {
154 info.push_back(shape);
155 }
156 string params = FormatNumber(node->proto().total_parameters()) + " params";
157 if (node->account) {
158 params = FormatNumber(node->proto().parameters()) + "/" + params;
159 } else {
160 params = "--/" + params;
161 }
162 info.push_back(params);
163 }
164 if (opts.select.find(kShown[3]) != opts.select.end()) {
165 string fops = FormatNumber(node->proto().total_float_ops()) + " flops";
166 if (node->account) {
167 fops = FormatNumber(node->proto().float_ops()) + "/" + fops;
168 } else {
169 fops = "--/" + fops;
170 }
171 info.push_back(fops);
172 }
173 if (opts.select.find(kShown[0]) != opts.select.end()) {
174 info.push_back(FormatNodeMemory(node, node->proto().requested_bytes(),
175 node->proto().total_requested_bytes()));
176 }
177 if (opts.select.find(kShown[11]) != opts.select.end()) {
178 info.push_back(FormatNodeMemory(node, node->proto().peak_bytes(),
179 node->proto().total_peak_bytes()));
180 }
181 if (opts.select.find(kShown[12]) != opts.select.end()) {
182 info.push_back(FormatNodeMemory(node, node->proto().residual_bytes(),
183 node->proto().total_residual_bytes()));
184 }
185 if (opts.select.find(kShown[13]) != opts.select.end()) {
186 info.push_back(FormatNodeMemory(node, node->proto().output_bytes(),
187 node->proto().total_output_bytes()));
188 }
189 if (opts.select.find(kShown[1]) != opts.select.end()) {
190 info.push_back(FormatTotalExecTime(node, opts));
191 info.push_back(FormatAcceleratorExecTime(node, opts));
192 info.push_back(FormatCPUExecTime(node, opts));
193 }
194 if (opts.select.find(kShown[9]) != opts.select.end() &&
195 opts.select.find(kShown[1]) == opts.select.end()) {
196 info.push_back(FormatAcceleratorExecTime(node, opts));
197 }
198 if (opts.select.find(kShown[10]) != opts.select.end() &&
199 opts.select.find(kShown[1]) == opts.select.end()) {
200 info.push_back(FormatCPUExecTime(node, opts));
201 }
202 if (opts.select.find(kShown[5]) != opts.select.end()) {
203 if (node->proto().devices_size() > 0) {
204 info.push_back(absl::StrJoin(node->proto().devices(), "|"));
205 }
206 }
207 if (opts.select.find(kShown[6]) != opts.select.end()) {
208 const std::set<string>& op_types = node->node->op_types();
209 info.push_back(absl::StrJoin(op_types, "|"));
210 }
211 if (opts.select.find(kShown[7]) != opts.select.end()) {
212 string run = FormatNumber(node->proto().total_run_count());
213 if (node->account) {
214 run = FormatNumber(node->proto().run_count()) + "/" + run;
215 } else {
216 run = "--/" + run;
217 }
218 string definition = FormatNumber(node->proto().total_definition_count());
219 if (node->account) {
220 definition = "1/" + definition;
221 } else {
222 definition = "--/" + definition;
223 }
224 info.push_back(run + "|" + definition);
225 }
226 if (opts.select.find(kShown[8]) != opts.select.end()) {
227 std::vector<string> shape_vec;
228 for (const auto& s : node->node->input_shapes()) {
229 if (s.second.empty()) {
230 shape_vec.push_back(absl::StrFormat("%d:unknown", s.first));
231 } else {
232 shape_vec.push_back(
233 absl::StrFormat("%d:%s", s.first, absl::StrJoin(s.second, "x")));
234 }
235 }
236 info.push_back(absl::StrJoin(shape_vec, "|"));
237 }
238
239 return absl::StrFormat("%s (%s)", node->name(), absl::StrJoin(info, ", "));
240 }
241
FormatLegend(const Options & opts) const242 string TFShow::FormatLegend(const Options& opts) const {
243 std::vector<string> legends;
244 if (opts.select.find(kShown[2]) != opts.select.end()) {
245 legends.push_back("# parameters");
246 }
247 if (opts.select.find(kShown[3]) != opts.select.end()) {
248 legends.push_back("# float_ops");
249 }
250 if (opts.select.find(kShown[0]) != opts.select.end()) {
251 legends.push_back("requested bytes");
252 }
253 if (opts.select.find(kShown[11]) != opts.select.end()) {
254 legends.push_back("peak bytes");
255 }
256 if (opts.select.find(kShown[12]) != opts.select.end()) {
257 legends.push_back("residual bytes");
258 }
259 if (opts.select.find(kShown[13]) != opts.select.end()) {
260 legends.push_back("output bytes");
261 }
262 if (opts.select.find(kShown[1]) != opts.select.end()) {
263 legends.push_back("total execution time");
264 legends.push_back("accelerator execution time");
265 legends.push_back("cpu execution time");
266 }
267 if (opts.select.find(kShown[9]) != opts.select.end() &&
268 opts.select.find(kShown[1]) == opts.select.end()) {
269 legends.push_back("accelerator execution time");
270 }
271 if (opts.select.find(kShown[10]) != opts.select.end() &&
272 opts.select.find(kShown[1]) == opts.select.end()) {
273 legends.push_back("cpu execution time");
274 }
275 if (opts.select.find(kShown[5]) != opts.select.end()) {
276 legends.push_back("assigned devices");
277 }
278 if (opts.select.find(kShown[6]) != opts.select.end()) {
279 legends.push_back("op types");
280 }
281 if (opts.select.find(kShown[7]) != opts.select.end()) {
282 legends.push_back("op count (run|defined)");
283 }
284 if (opts.select.find(kShown[8]) != opts.select.end()) {
285 legends.push_back("input shapes");
286 }
287 return absl::StrFormat("node name | %s\n", absl::StrJoin(legends, " | "));
288 }
289
290 } // namespace tfprof
291 } // namespace tensorflow
292