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 "tensorflow/core/lib/strings/stringprintf.h"
22 #include "tensorflow/core/platform/env.h"
23 #include "tensorflow/core/platform/regexp.h"
24
25 namespace tensorflow {
26 namespace tfprof {
27
Show(const string & prefix,const Options & opts)28 const GraphNodeProto& TFShow::Show(const string& prefix, const Options& opts) {
29 if (opts.output_type == kOutput[0]) {
30 Timeline timeline(opts.step, opts.output_options.at(kTimelineOpts[0]));
31 return ShowInternal(opts, &timeline)->proto();
32 } else {
33 const ShowNode* ret = ShowInternal(opts, nullptr);
34 if (opts.output_type == kOutput[1]) {
35 printf("%s", (prefix + ret->formatted_str).c_str());
36 fflush(stdout);
37 } else if (opts.output_type == kOutput[2]) {
38 Status s = WriteStringToFile(Env::Default(),
39 opts.output_options.at(kFileOpts[0]),
40 prefix + ret->formatted_str);
41 if (!s.ok()) {
42 fprintf(stderr, "%s\n", s.ToString().c_str());
43 }
44 } else if (opts.output_type == kOutput[3] ||
45 opts.output_type == kOutput[4]) {
46 } else {
47 fprintf(stderr, "Unknown output type: %s\n", opts.output_type.c_str());
48 }
49 return ret->proto();
50 }
51 }
52
LookUpCheckPoint(const string & name,std::unique_ptr<TFProfTensor> * tensor)53 bool TFShow::LookUpCheckPoint(const string& name,
54 std::unique_ptr<TFProfTensor>* tensor) {
55 if (name == kTFProfRoot || !ckpt_reader_ || !tensor) {
56 return false;
57 }
58 std::unique_ptr<Tensor> out_tensor;
59 TF_Status* status = TF_NewStatus();
60 ckpt_reader_->GetTensor(name, &out_tensor, status);
61 if (TF_GetCode(status) != TF_OK) {
62 fprintf(stderr, "%s\n", TF_Message(status));
63 TF_DeleteStatus(status);
64 return false;
65 }
66 tensor->reset(new TFProfTensor(std::move(out_tensor)));
67 TF_DeleteStatus(status);
68 return true;
69 }
70
ShouldShow(const ShowNode * node,const Options & opts,int depth) const71 bool TFShow::ShouldShow(const ShowNode* node, const Options& opts,
72 int depth) const {
73 // Always show kTFProfRoot.
74 if (node->name() == kTFProfRoot) return true;
75
76 if (node->proto().total_requested_bytes() < opts.min_bytes ||
77 node->proto().total_peak_bytes() < opts.min_peak_bytes ||
78 node->proto().total_residual_bytes() < opts.min_residual_bytes ||
79 node->proto().total_output_bytes() < opts.min_output_bytes ||
80 node->proto().total_exec_micros() < opts.min_micros ||
81 node->proto().total_accelerator_exec_micros() <
82 opts.min_accelerator_micros ||
83 node->proto().total_cpu_exec_micros() < opts.min_cpu_micros ||
84 node->proto().parameters() < opts.min_params ||
85 node->proto().float_ops() < opts.min_float_ops ||
86 node->proto().run_count() < opts.min_occurrence ||
87 depth > opts.max_depth || !ShouldShowIfExtra(node, opts, depth)) {
88 return false;
89 }
90
91 bool show = false;
92 if (opts.show_name_regexes.size() == 1 && opts.show_name_regexes[0] == ".*") {
93 show = true;
94 } else {
95 for (const string& regex : opts.show_name_regexes) {
96 if (RE2::FullMatch(node->name(), regex)) {
97 show = true;
98 break;
99 }
100 }
101 }
102 // Don't show if show_name_regexes don't cover it.
103 if (!show) return false;
104 // Don't show if hide_name_regexes cover it.
105 for (const string& regex : opts.hide_name_regexes) {
106 if (RE2::FullMatch(node->name(), regex)) return false;
107 }
108 return true;
109 }
110
ShouldTrim(const ShowNode * node,const std::vector<string> & regexes) const111 bool TFShow::ShouldTrim(const ShowNode* node,
112 const std::vector<string>& regexes) const {
113 for (const string& regex : regexes) {
114 if (RE2::FullMatch(node->name(), regex)) {
115 return true;
116 }
117 }
118 return false;
119 }
120
ReAccount(ShowNode * node,const Options & opts)121 bool TFShow::ReAccount(ShowNode* node, const Options& opts) {
122 node->ReInit(opts.step);
123 if (opts.account_type_regexes.size() == 1 &&
124 opts.account_type_regexes[0] == ".*") {
125 return true;
126 }
127 for (const string& regex : opts.account_type_regexes) {
128 for (const string& type : node->node->op_types()) {
129 if (RE2::FullMatch(type, regex)) {
130 return true;
131 }
132 }
133 }
134 return false;
135 }
136
FormatNodeMemory(ShowNode * node,int64 bytes,int64 total_bytes) const137 string TFShow::FormatNodeMemory(ShowNode* node, int64 bytes,
138 int64 total_bytes) const {
139 string memory = FormatMemory(total_bytes);
140 if (node->account) {
141 memory = FormatMemory(bytes) + "/" + memory;
142 } else {
143 memory = "--/" + memory;
144 }
145 return memory;
146 }
147
FormatNode(ShowNode * node,const Options & opts) const148 string TFShow::FormatNode(ShowNode* node, const Options& opts) const {
149 std::vector<string> info;
150 if (opts.select.find(kShown[2]) != opts.select.end()) {
151 const string shape = FormatShapes(node->node->shape());
152 if (!shape.empty()) {
153 info.push_back(shape);
154 }
155 string params = FormatNumber(node->proto().total_parameters()) + " params";
156 if (node->account) {
157 params = FormatNumber(node->proto().parameters()) + "/" + params;
158 } else {
159 params = "--/" + params;
160 }
161 info.push_back(params);
162 }
163 if (opts.select.find(kShown[3]) != opts.select.end()) {
164 string fops = FormatNumber(node->proto().total_float_ops()) + " flops";
165 if (node->account) {
166 fops = FormatNumber(node->proto().float_ops()) + "/" + fops;
167 } else {
168 fops = "--/" + fops;
169 }
170 info.push_back(fops);
171 }
172 std::vector<string> attrs;
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(str_util::Join(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(str_util::Join(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(strings::Printf("%d:unknown", s.first));
231 } else {
232 shape_vec.push_back(strings::Printf(
233 "%d:%s", s.first, str_util::Join(s.second, "x").c_str()));
234 }
235 }
236 info.push_back(str_util::Join(shape_vec, "|"));
237 }
238
239 return strings::Printf("%s (%s)", node->name().c_str(),
240 str_util::Join(info, ", ").c_str());
241 }
242
FormatLegend(const Options & opts) const243 string TFShow::FormatLegend(const Options& opts) const {
244 std::vector<string> legends;
245 if (opts.select.find(kShown[2]) != opts.select.end()) {
246 legends.push_back("# parameters");
247 }
248 if (opts.select.find(kShown[3]) != opts.select.end()) {
249 legends.push_back("# float_ops");
250 }
251 if (opts.select.find(kShown[0]) != opts.select.end()) {
252 legends.push_back("requested bytes");
253 }
254 if (opts.select.find(kShown[11]) != opts.select.end()) {
255 legends.push_back("peak bytes");
256 }
257 if (opts.select.find(kShown[12]) != opts.select.end()) {
258 legends.push_back("residual bytes");
259 }
260 if (opts.select.find(kShown[13]) != opts.select.end()) {
261 legends.push_back("output bytes");
262 }
263 if (opts.select.find(kShown[1]) != opts.select.end()) {
264 legends.push_back("total execution time");
265 legends.push_back("accelerator execution time");
266 legends.push_back("cpu execution time");
267 }
268 if (opts.select.find(kShown[9]) != opts.select.end() &&
269 opts.select.find(kShown[1]) == opts.select.end()) {
270 legends.push_back("accelerator execution time");
271 }
272 if (opts.select.find(kShown[10]) != opts.select.end() &&
273 opts.select.find(kShown[1]) == opts.select.end()) {
274 legends.push_back("cpu execution time");
275 }
276 if (opts.select.find(kShown[5]) != opts.select.end()) {
277 legends.push_back("assigned devices");
278 }
279 if (opts.select.find(kShown[6]) != opts.select.end()) {
280 legends.push_back("op types");
281 }
282 if (opts.select.find(kShown[7]) != opts.select.end()) {
283 legends.push_back("op count (run|defined)");
284 }
285 if (opts.select.find(kShown[8]) != opts.select.end()) {
286 legends.push_back("input shapes");
287 }
288 return strings::Printf("node name | %s\n",
289 str_util::Join(legends, " | ").c_str());
290 }
291
292 } // namespace tfprof
293 } // namespace tensorflow
294