tensorflow/compiler/jit/deadness_analysis.cc
// We populate the nodes along a special topological order where nodes having
// the same root frame are placed adjacent to each other.  This grouping enables
// processing the graph per root frame at a time and guarantees that when a root
// frame is being processed, nodes in the downstream frames have not yet been
// processed.  This property is important because we need to process an entire
// frame to know whether the optimistic mode converges or not.  In other words,
// nodes in the downstream frames shall not be populated until all of its
// upstream frames are populated.  In effect, this order enables processing each
// (nested) tf.while one-by-one, as each (nested) tf.while creates a unique
// (root) frame.  Note that we don't separate while loops belonging to the same
// nested while, as there is no clean cut for separating them in the topological
// order.
We populate the nodes along a special topological order where nodes having
the same root frame are placed adjacent to each other.  This grouping enables
processing the graph per root frame at a time and guarantees that when a root
frame is being processed, nodes in the downstream frames have not yet been
processed.  This property is important because we need to process an entire
frame to know whether the optimistic mode converges or not.  In other words,
nodes in the downstream frames shall not be populated until all of its
upstream frames are populated.  In effect, this order enables processing each
(nested) tf.while one-by-one, as each (nested) tf.while creates a unique
(root) frame.  Note that we don't separate while loops belonging to the same
nested while, as there is no clean cut for separating them in the topological
order.
We populate the nodes along a special topological order where nodes having the same root frame are placed adjacent to each other . This grouping enables processing the graph per root frame at a time and guarantees that when a root frame is being processed nodes in the downstream frames have not yet been processed . This property is important because we need to process an entire frame to know whether the optimistic mode converges or not . In other words nodes in the downstream frames shall not be populated until all of its upstream frames are populated . In effect this order enables processing each ( nested ) tf . while one - by - one as each ( nested ) tf . while creates a unique ( root ) frame . Note that we don ' t separate while loops belonging to the same nested while as there is no clean cut for separating them in the topological order .
Status DeadnessAnalysisImpl::Populate(bool enable_optimistic) {
  std::vector<string> unreachable_nodes;
  TF_RETURN_IF_ERROR(
      BuildControlFlowInfo(&graph_, &control_flow_info_, &unreachable_nodes));
  if (!unreachable_nodes.empty()) {
    if (unreachable_nodes.size() > 5) {
      unreachable_nodes.erase(unreachable_nodes.begin() + 5,
                              unreachable_nodes.end());
    }
    return errors::InvalidArgument(
        "Found unreachable nodes, most likely source and sink nodes not "
        "connected: ",
        absl::StrJoin(unreachable_nodes, ", "));
  }
  std::vector<Node*> topo;
  TF_RETURN_IF_ERROR(GetFrameBasedTopologicalOrder(&topo));
  size_t frame_start = 0;
  while (frame_start < topo.size()) {
    absl::string_view cur_frame_name;
    TF_RETURN_IF_ERROR(
        GetRootFrame(topo[frame_start], control_flow_info_, &cur_frame_name));
    size_t frame_end = frame_start;
    for (size_t i = frame_start + 1; i < topo.size(); ++i) {
      absl::string_view i_frame_name;
      TF_RETURN_IF_ERROR(
          GetRootFrame(topo[i], control_flow_info_, &i_frame_name));
      if (i_frame_name == cur_frame_name) {
        frame_end = i;
      } else {
        break;
      }
    }
    absl::Span<Node*> sub_topo(topo.data() + frame_start,
                               frame_end - frame_start + 1);
    frame_start = frame_end + 1;
    bool success = false;
    if (enable_optimistic && !cur_frame_name.empty()) {
      TF_RETURN_IF_ERROR(
          PopulateFrame(sub_topo, true, &success));
    }
    if (!success) {
      TF_RETURN_IF_ERROR(
          PopulateFrame(sub_topo, false, nullptr));
    }
    VLOG(2) << "Done populating frame " << cur_frame_name << " using the "
            << (success ? "optimistic" : "pessimistic") << " mode.";
  }
  return Status::OK();
}
Status DeadnessAnalysisImpl :: Populate ( bool enable_optimistic ) { std :: vector < string > unreachable_nodes ; TF_RETURN_IF_ERROR ( BuildControlFlowInfo ( & graph_ , & control_flow_info_ , & unreachable_nodes ) ) ; if ( ! unreachable_nodes . empty ( ) ) { if ( unreachable_nodes . size ( ) > 5 ) { unreachable_nodes . erase ( unreachable_nodes . begin ( ) + 5 , unreachable_nodes . end ( ) ) ; } return errors :: InvalidArgument ( " " " " , absl :: StrJoin ( unreachable_nodes , " " ) ) ; } std :: vector < Node * > topo ; TF_RETURN_IF_ERROR ( GetFrameBasedTopologicalOrder ( & topo ) ) ; size_t frame_start = 0 ; while ( frame_start < topo . size ( ) ) { absl :: string_view cur_frame_name ; TF_RETURN_IF_ERROR ( GetRootFrame ( topo [ frame_start ] , control_flow_info_ , & cur_frame_name ) ) ; size_t frame_end = frame_start ; for ( size_t i = frame_start + 1 ; i < topo . size ( ) ; ++ i ) { absl :: string_view i_frame_name ; TF_RETURN_IF_ERROR ( GetRootFrame ( topo [ i ] , control_flow_info_ , & i_frame_name ) ) ; if ( i_frame_name == cur_frame_name ) { frame_end = i ; } else { break ; } } absl :: Span < Node * > sub_topo ( topo . data ( ) + frame_start , frame_end - frame_start + 1 ) ; frame_start = frame_end + 1 ; bool success = false ; if ( enable_optimistic && ! cur_frame_name . empty ( ) ) { TF_RETURN_IF_ERROR ( PopulateFrame ( sub_topo , true , & success ) ) ; } if ( ! success ) { TF_RETURN_IF_ERROR ( PopulateFrame ( sub_topo , false , nullptr ) ) ; } VLOG ( 2 ) << " " << cur_frame_name << " " << ( success ? " " : " " ) << " " ; } return Status :: OK ( ) ; }
We populate the nodes along a special topological order where nodes having
the same root frame are placed adjacent to each other.
We populate the nodes along a special topological order where nodes having the same root frame are placed adjacent to each other .
// Compute the loop structure of the graph. // Do some opportunistic error checking: // Batching nodes who have the same root frame. /*length=*/ // First, try the optimistic mode. /*use_optimistic_mode=*/ // The optimistic mode does not converge.  Let's fall back to the // pessimistic mode. /*use_optimistic_mode=*/