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