| 62 | } |
| 63 | |
| 64 | void PropagatorState::PropagateOutputs(const TaggedNode& tagged_node, |
| 65 | EntryVector* outputs, |
| 66 | TaggedNodeSeq* ready) { |
| 67 | profiler::TraceMe activity( |
| 68 | [&]() { |
| 69 | return strings::StrCat( |
| 70 | "ExecutorPropagateOutputs#", "id=", step_id_, |
| 71 | ",kernel_name=", tagged_node.node_item->kernel->name(), |
| 72 | ",num_output_edges=", tagged_node.node_item->num_output_edges, |
| 73 | ",num_output_control_edges=", |
| 74 | tagged_node.node_item->num_output_control_edges, "#"); |
| 75 | }, |
| 76 | profiler::GetTFTraceMeLevel(/*is_expensive=*/false)); |
| 77 | |
| 78 | const NodeItem* const item = tagged_node.node_item; |
| 79 | FrameState* const input_frame = tagged_node.input_frame; |
| 80 | IterationState* const input_iter = tagged_node.input_iter; |
| 81 | const bool is_dead = tagged_node.is_dead; |
| 82 | |
| 83 | // Propagates outputs along out edges, and puts newly ready nodes |
| 84 | // into the ready queue. |
| 85 | DCHECK(ready->empty()); |
| 86 | bool is_frame_done = false; |
| 87 | FrameState* output_frame = input_frame; |
| 88 | IterationState* output_iter = input_iter; |
| 89 | |
| 90 | if (!item->is_enter_exit_or_next_iter) { |
| 91 | // Fast path for node types that don't need special handling. |
| 92 | // This is the case for most nodes. |
| 93 | DCHECK_EQ(input_frame, output_frame); |
| 94 | FrameState* frame = input_frame; |
| 95 | is_frame_done = frame->ActivateNodesAndAdjustOutstanding( |
| 96 | item, is_dead, output_iter, outputs, ready); |
| 97 | } else if (item->is_enter) { |
| 98 | FindOrCreateChildFrame(input_frame, input_iter, *item, &output_frame); |
| 99 | { |
| 100 | mutex_lock l(output_frame->mu); |
| 101 | output_iter = output_frame->GetIteration(0); |
| 102 | if (item->is_constant_enter) { |
| 103 | // Propagate to all active iterations if this is a loop invariant. |
| 104 | output_frame->AddLoopInv(item, (*outputs)[0], ready); |
| 105 | } else { |
| 106 | int activated = output_frame->ActivateNodesLocked( |
| 107 | item, is_dead, output_iter, outputs, ready); |
| 108 | output_frame->AdjustOutstandingOpsLocked(output_iter, activated, ready); |
| 109 | } |
| 110 | output_frame->num_pending_inputs--; |
| 111 | } |
| 112 | is_frame_done = input_frame->DecrementOutstandingOps(input_iter, ready); |
| 113 | } else if (item->is_exit) { |
| 114 | if (is_dead) { |
| 115 | mutex_lock l(input_frame->mu); |
| 116 | // Stop and remember this node if it is a dead exit. |
| 117 | if (input_iter->iter_num == input_frame->iteration_count) { |
| 118 | input_frame->dead_exits.push_back(item); |
| 119 | } |
| 120 | is_frame_done = |
| 121 | input_frame->DecrementOutstandingOpsLocked(input_iter, ready); |
no test coverage detected