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_scope.h" 17 18 #include <stdio.h> 19 #include <utility> 20 21 #include "tensorflow/c/c_api.h" 22 #include "tensorflow/core/framework/tensor.h" 23 #include "tensorflow/core/lib/strings/stringprintf.h" 24 #include "tensorflow/core/platform/regexp.h" 25 #include "tensorflow/core/profiler/internal/tfprof_constants.h" 26 #include "tensorflow/core/profiler/internal/tfprof_tensor.h" 27 28 namespace tensorflow { 29 namespace tfprof { 30 ScopeNode* TFScope::CreateParentNode(const string& name) { 31 if (nodes_map_.find(name) != nodes_map_.end()) { 32 return nodes_map_[name].get(); 33 } 34 node_defs_.push_back(std::unique_ptr<NodeDef>(new NodeDef())); 35 node_defs_.back()->set_name(name); 36 node_defs_.back()->set_op(kTFScopeParent); 37 parent_nodes_[name] = std::unique_ptr<TFGraphNode>( 38 new TFGraphNode(node_defs_.back().get(), -1, nullptr)); 39 nodes_map_[name] = 40 std::unique_ptr<ScopeNode>(new ScopeNode(parent_nodes_[name].get())); 41 return nodes_map_[name].get(); 42 } 43 44 void TFScope::AddNode(TFGraphNode* node) { 45 string name = node->name(); 46 if (nodes_map_.find(node->name()) == nodes_map_.end()) { 47 nodes_map_[name] = std::unique_ptr<ScopeNode>(new ScopeNode(node)); 48 } 49 50 auto last_slash = name.find_last_of("/"); 51 while (last_slash != name.npos) { 52 name = name.substr(0, last_slash); 53 if (nodes_map_.find(name) == nodes_map_.end()) { 54 CHECK(CreateParentNode(name)); 55 } 56 last_slash = name.find_last_of("/"); 57 } 58 } 59 60 void TFScope::Build() { 61 if (root_) return; 62 63 std::vector<ScopeNode*> roots; 64 // Found roots, which are nodes without "/". 65 for (auto it = nodes_map_.begin(); it != nodes_map_.end(); it++) { 66 ScopeNode* node = it->second.get(); 67 auto last_slash = node->name().find_last_of("/"); 68 if (last_slash == string::npos) { 69 roots.push_back(node); 70 } else { 71 const string prefix = node->name().substr(0, last_slash); 72 nodes_map_[prefix]->children.push_back(node); 73 } 74 } 75 76 root_ = CreateParentNode(kTFProfRoot); 77 root_->children.assign(roots.begin(), roots.end()); 78 } 79 80 const ShowNode* TFScope::ShowInternal(const Options& opts, Timeline* timeline) { 81 root_->ResetTotalStats(); 82 if (opts.output_type == kOutput[3]) { 83 fprintf(stderr, "Only 'code' view supports pprof output now.\n"); 84 return root_; 85 } 86 87 std::vector<ScopeNode*> roots = Account(root_->children, opts); 88 root_->show_children.clear(); 89 for (ScopeNode* n : roots) { 90 root_->AggregateTotalStats(n); 91 } 92 93 if (opts.start_name_regexes.size() != 1 || 94 opts.start_name_regexes[0] != ".*") { 95 roots = SearchRoot(roots, opts.start_name_regexes); 96 } 97 98 root_->show_children.assign(roots.begin(), roots.end()); 99 ScopeNode* root = PrintScope({root_}, opts, 1, 0)[0]; 100 101 root->formatted_str = FormatLegend(opts) + root->formatted_str; 102 Format(root->show_children, &root->formatted_str, root->mutable_proto()); 103 104 if (timeline) { 105 timeline->GenerateScopeTimeline(root); 106 } 107 return root; 108 } 109 110 void TFScope::Format(const std::vector<ScopeNode*> roots, string* display_str, 111 GraphNodeProto* proto) { 112 for (ScopeNode* node : roots) { 113 display_str->append(node->formatted_str); 114 GraphNodeProto* child = proto->add_children(); 115 child->MergeFrom(node->proto()); 116 Format(node->show_children, display_str, child); 117 } 118 } 119 120 std::vector<ScopeNode*> TFScope::SearchRoot( 121 std::vector<ScopeNode*> roots, const std::vector<string>& regexes) { 122 std::vector<ScopeNode*> res; 123 if (roots.empty()) { 124 return res; 125 } 126 for (ScopeNode* root : roots) { 127 bool match_start_node = false; 128 for (const string& regex : regexes) { 129 if (RE2::FullMatch(root->name(), regex)) { 130 res.push_back(root); 131 match_start_node = true; 132 break; 133 } 134 } 135 if (match_start_node) { 136 // Found a start node at this branch, no need to continue. 137 continue; 138 } 139 std::vector<ScopeNode*> nroots = SearchRoot(root->show_children, regexes); 140 res.insert(res.end(), nroots.begin(), nroots.end()); 141 } 142 return res; 143 } 144 145 std::vector<ScopeNode*> TFScope::PrintScope(const std::vector<ScopeNode*> roots, 146 const Options& opts, int depth, 147 int last_ident) { 148 std::vector<ScopeNode*> show_nodes; 149 150 for (ScopeNode* node : roots) { 151 int ident = last_ident; 152 bool show = ShouldShow(node, opts, depth); 153 if (show) ident += 2; 154 155 std::vector<ScopeNode*> show_cnodes; 156 if (!ShouldTrim(node, opts.trim_name_regexes) && depth <= opts.max_depth) { 157 show_cnodes = PrintScope(node->show_children, opts, depth + 1, ident); 158 } 159 if (show) { 160 node->show_children.clear(); 161 if (opts.account_displayed_op_only) { 162 node->ResetTotalStats(); 163 node->AddSelfToTotalStats(); 164 } 165 166 show_cnodes = SortNodes(show_cnodes, opts); 167 for (ScopeNode* sc : show_cnodes) { 168 node->show_children.push_back(sc); 169 if (opts.account_displayed_op_only) { 170 node->AggregateTotalStats(sc); 171 } 172 } 173 174 node->formatted_str = 175 strings::Printf("%s%s\n", string(last_ident, ' ').c_str(), 176 FormatNode(node, opts).c_str()); 177 178 if (opts.select.find(kShown[4]) != opts.select.end()) { 179 std::unique_ptr<TFProfTensor> tfprof_tensor; 180 if (LookUpCheckPoint(node->name(), &tfprof_tensor)) { 181 string value_str; 182 tfprof_tensor->Display(&value_str, 183 node->mutable_proto()->mutable_tensor_value()); 184 node->formatted_str += value_str; 185 } 186 } 187 show_nodes.push_back(node); 188 } else { 189 show_nodes.insert(show_nodes.end(), show_cnodes.begin(), 190 show_cnodes.end()); 191 } 192 } 193 return show_nodes; 194 } 195 196 std::vector<ScopeNode*> TFScope::Account(const std::vector<ScopeNode*>& roots, 197 const Options& opts) { 198 std::vector<ScopeNode*> act_nodes; 199 200 for (ScopeNode* node : roots) { 201 node->ResetTotalStats(); 202 std::vector<ScopeNode*> act_cnodes = Account(node->children, opts); 203 204 node->account = ReAccount(node, opts); 205 if (node->account || !act_cnodes.empty()) { 206 node->show_children.clear(); 207 node->ResetTotalStats(); 208 node->AddSelfToTotalStats(); 209 for (ScopeNode* c : act_cnodes) { 210 node->AggregateTotalStats(c); 211 node->show_children.push_back(c); 212 } 213 act_nodes.push_back(node); 214 } 215 } 216 return act_nodes; 217 } 218 } // namespace tfprof 219 } // namespace tensorflow 220