This function hashes a subgraph (rooted at node) by traversing all possible dependency paths from that node.
| 198 | // This function hashes a subgraph (rooted at node) by traversing all possible |
| 199 | // dependency paths from that node. |
| 200 | uint64 HashSubgraphImpl(const grappler::GraphView& g, const NodeDef* node, |
| 201 | std::vector<std::string>* visited, |
| 202 | absl::flat_hash_map<std::string, uint64>* cache) { |
| 203 | uint64 input_hash = 0; |
| 204 | uint64 control_dep_hash = 0; |
| 205 | |
| 206 | std::string canonical_node_name = absl::StrCat("node-", node->name()); |
| 207 | auto it = cache->find(canonical_node_name); |
| 208 | if (it != cache->end()) { |
| 209 | return it->second; |
| 210 | } |
| 211 | |
| 212 | uint64 op_hash = Hash64(node->op()); |
| 213 | |
| 214 | // Checks to make sure we won't get stuck in an infinite loop (especially in |
| 215 | // loops with control dependencies). |
| 216 | for (const std::string& visited_node_name : *visited) { |
| 217 | if (visited_node_name == canonical_node_name) { |
| 218 | uint64 final_hash = |
| 219 | Hash64Combine(DefaultDependencyLoopNodeHash(), op_hash); |
| 220 | (*cache)[canonical_node_name] = final_hash; |
| 221 | return final_hash; |
| 222 | } |
| 223 | } |
| 224 | visited->push_back(canonical_node_name); |
| 225 | |
| 226 | for (int i = 0; i < node->input_size(); ++i) { |
| 227 | DCHECK_GT(node->input(i).length(), 0); |
| 228 | if (node->input(i)[0] == '^') { |
| 229 | // TODO(frankchn): Investigate if control dependencies are necessary |
| 230 | // inputs to the hash. |
| 231 | // Control dependency node names start with '^', and order of appearance |
| 232 | // for the control dependencies does not matter. |
| 233 | control_dep_hash = Hash64CombineUnordered( |
| 234 | control_dep_hash, |
| 235 | HashSubgraphImpl(g, g.GetNode(node->input(i).substr(1)), visited, |
| 236 | cache)); |
| 237 | } else { |
| 238 | // The output port is significant and is optionally delimited by a ':' |
| 239 | // for non-zero ports. |
| 240 | std::pair<std::string, std::string> node_spec = |
| 241 | absl::StrSplit(node->input(i), absl::MaxSplits(':', 1)); |
| 242 | uint64 child_node_hash = |
| 243 | HashSubgraphImpl(g, g.GetNode(node_spec.first), visited, cache); |
| 244 | uint64 child_port_hash = Hash64(node_spec.second); |
| 245 | input_hash = Hash64Combine( |
| 246 | input_hash, Hash64Combine(child_node_hash, child_port_hash)); |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | uint64 attr_hash = 0; |
| 251 | for (const auto& attr : node->attr()) { |
| 252 | attr_hash = Hash64CombineUnordered( |
| 253 | attr_hash, HashAttr(g.graph()->library(), attr.first, attr.second, |
| 254 | visited, cache)); |
| 255 | } |
| 256 | |
| 257 | uint64 device_hash = Hash64(node->device()); |
no test coverage detected