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 // This checker checks the most expensive operations.
16 #ifndef TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_
17 #define TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_
18 
19 #include "absl/strings/str_format.h"
20 #include "absl/strings/str_join.h"
21 #include "tensorflow/core/profiler/internal/advisor/checker.h"
22 
23 namespace tensorflow {
24 namespace tfprof {
25 
26 class ExpensiveOperationChecker : public Checker {
27  public:
name()28   string name() const override { return kCheckers[2]; }
29 
30  private:
Check(const AdvisorOptionsProto::CheckerOption & options,const TFStats * stats)31   AdviceProto::Checker Check(const AdvisorOptionsProto::CheckerOption& options,
32                              const TFStats* stats) override {
33     if (!stats) {
34       absl::FPrintF(
35           stderr, "Missing profiles (e.g. graph, run_meta). Skip %s\n", name());
36       return reports_;
37     }
38     if (stats->steps().empty()) {
39       absl::FPrintF(stderr, "Missing RunMetadata info. Skip %s\n", name());
40     }
41     CheckOpView(stats);
42     CheckScopeView(stats);
43     CheckCodeView(stats);
44     return reports_;
45   }
46 
CheckOpView(const TFStats * stats)47   void CheckOpView(const TFStats* stats) {
48     if (stats->steps().empty()) {
49       absl::FPrintF(stderr, "Missing run_meta for %s\n", name());
50       return;
51     }
52     Options opts(3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, "micros", {".*"}, {".*"},
53                  {}, {".*"}, {}, false, {"micros", "occurrence"}, "none", {});
54     const MultiGraphNodeProto root = stats->ShowMultiGraphNode("op", opts);
55     if (root.children_size() == 0) {
56       return;
57     }
58     const MultiGraphNodeProto* node = &root;
59     std::vector<string> outputs;
60     for (int i = 0; i < 3 && node->children_size() > 0; ++i) {
61       node = &node->children(0);
62       outputs.push_back(absl::StrFormat(
63           "top %d operation type: %s, "
64           "cpu: %s, accelerator: %s, total: %s (%.2f%%)",
65           i + 1, node->name(), FormatTime(node->cpu_exec_micros()),
66           FormatTime(node->accelerator_exec_micros()),
67           FormatTime(node->exec_micros()),
68           100.0 * node->exec_micros() / (root.total_exec_micros() + 1e-10)));
69     }
70     reports_.add_reports(absl::StrJoin(outputs, "\n"));
71   }
72 
CheckCodeView(const TFStats * stats)73   void CheckCodeView(const TFStats* stats) {
74     if (!stats->has_code_traces()) {
75       absl::FPrintF(stderr, "Missing op_log (code traces) for %s\n", name());
76       return;
77     }
78     Options opts(100, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, "micros", {".*"},
79                  {".*"}, {}, {".*"}, {}, false, {"micros"}, "none", {});
80     const MultiGraphNodeProto root = stats->ShowMultiGraphNode("code", opts);
81     const MultiGraphNodeProto* node = &root;
82     // A trick here is: Usually, codes in library file are usually referenced
83     // only once, while user's own code are referenced multiple times.
84     while (node->children_size() == 1) {
85       node = &node->children(0);
86     }
87     if (node->children_size() == 0) {
88       return;
89     }
90 
91     std::vector<string> outputs;
92     CodeViewHelper(node, 0, &outputs);
93     reports_.add_reports(absl::StrJoin(outputs, "\n"));
94   }
95 
CheckScopeView(const TFStats * stats)96   void CheckScopeView(const TFStats* stats) {
97     Options opts(100, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, -1, "micros", {".*"},
98                  {".*"}, {}, {".*"}, {}, false, {"micros"}, "none", {});
99     const GraphNodeProto root = stats->ShowGraphNode("scope", opts);
100     if (root.children_size() == 0) {
101       return;
102     }
103     std::vector<string> outputs;
104     for (int i = 0; i < 3 && i < root.children_size(); ++i) {
105       const GraphNodeProto& node = root.children(i);
106       outputs.push_back(absl::StrFormat(
107           "top %d graph node: %s, cpu: %s, accelerator: %s, total: %s", i + 1,
108           node.name(), FormatTime(node.cpu_exec_micros()),
109           FormatTime(node.accelerator_exec_micros()),
110           FormatTime(node.exec_micros())));
111     }
112     reports_.add_reports(absl::StrJoin(outputs, "\n"));
113   }
114 
CodeViewHelper(const MultiGraphNodeProto * node,int depth,std::vector<string> * outputs)115   void CodeViewHelper(const MultiGraphNodeProto* node, int depth,
116                       std::vector<string>* outputs) {
117     if (node->children_size() <= 1 || depth > 3) {
118       return;
119     }
120     for (int j = 0; j < 3 && j < node->children_size(); ++j) {
121       const MultiGraphNodeProto* c = &node->children(j);
122       if (c->total_exec_micros() < 1000) {
123         continue;
124       }
125       outputs->push_back(
126           absl::StrFormat("%s%s, cpu: %s, accelerator: %s, total: %s",
127                           std::string(depth * 2, ' '), c->name(),
128                           FormatTime(c->total_cpu_exec_micros()),
129                           FormatTime(c->total_accelerator_exec_micros()),
130                           FormatTime(c->total_exec_micros())));
131       CodeViewHelper(c, depth + 1, outputs);
132     }
133   }
134 
135   AdviceProto::Checker reports_;
136 };
137 
138 }  // namespace tfprof
139 }  // namespace tensorflow
140 
141 #endif  // TENSORFLOW_CORE_PROFILER_INTERNAL_ADVISOR_EXPENSIVE_OPERATION_CHECKER_H_
142