| 1161 | |
| 1162 | template <class PropagatorStateType> |
| 1163 | Status ExecutorState<PropagatorStateType>::ProcessOutputs( |
| 1164 | const NodeItem& item, OpKernelContext* ctx, Entry* outputs, |
| 1165 | NodeExecStatsInterface* stats) { |
| 1166 | Status s = ctx->status(); |
| 1167 | if (!s.ok()) { |
| 1168 | s = AttachDef(s, item.kernel->def()); |
| 1169 | // TODO(misard) Replace with a finer-grain enabling flag once we |
| 1170 | // add better optional debugging support. |
| 1171 | if (vlog_ && VLOG_IS_ON(1)) { |
| 1172 | LOG(WARNING) << this << " Compute status: " << s; |
| 1173 | } |
| 1174 | if (s.code() == error::RESOURCE_EXHAUSTED) { |
| 1175 | if (stats_collector_) { |
| 1176 | string err = stats_collector_->ReportAllocsOnResourceExhausted( |
| 1177 | s.error_message()); |
| 1178 | s = Status(s.code(), strings::StrCat(s.error_message(), err)); |
| 1179 | } else { |
| 1180 | s = Status( |
| 1181 | s.code(), |
| 1182 | strings::StrCat( |
| 1183 | s.error_message(), |
| 1184 | "\nHint: If you want to see a list of allocated tensors when " |
| 1185 | "OOM happens, add report_tensor_allocations_upon_oom " |
| 1186 | "to RunOptions for current allocation info.\n")); |
| 1187 | } |
| 1188 | } |
| 1189 | return s; |
| 1190 | } |
| 1191 | |
| 1192 | for (int i = 0; i < item.num_outputs; ++i) { |
| 1193 | const TensorValue val = ctx->release_output(i); |
| 1194 | Entry* out = &outputs[i]; |
| 1195 | DCHECK(out->state == Entry::State::NO_VALUE); |
| 1196 | |
| 1197 | if (val.tensor == nullptr) { |
| 1198 | // Unless it's a Switch or a Recv, or the executor has marked the output |
| 1199 | // as not required, the node must produce a tensor value at i-th output. |
| 1200 | if (!(item.is_recv_or_switch || |
| 1201 | (item.outputs_required && !item.outputs_required[i])) && |
| 1202 | !item.is_fuse_recv_op && !item.is_run_graph_op) { |
| 1203 | s.Update(errors::Internal("Missing ", i, "-th output from ", |
| 1204 | FormatNodeDefForError(item.kernel->def()))); |
| 1205 | } |
| 1206 | } else { |
| 1207 | // Set the allocator attributes of the output entry. |
| 1208 | out->alloc_attr = ctx->output_alloc_attr(i); |
| 1209 | |
| 1210 | // Sanity check of output tensor types. We need to inspect this safely as |
| 1211 | // we are in the tensor buffer. |
| 1212 | DataType dtype = val.dtype_safe(); |
| 1213 | if (dtype == item.output_type(i)) { |
| 1214 | if (stats && val.tensor->IsInitialized()) { |
| 1215 | nodestats::SetOutput(stats, i, val.tensor); |
| 1216 | } |
| 1217 | if (val.is_ref()) { |
| 1218 | out->state = Entry::State::HAS_REF_TENSOR; |
| 1219 | out->ref_tensor.tensor = val.tensor; |
| 1220 | out->ref_tensor.mu = val.mutex_if_ref; |
nothing calls this directly
no test coverage detected