| 99 | GraphRunner::~GraphRunner() {} |
| 100 | |
| 101 | Status GraphRunner::Run(Graph* graph, FunctionLibraryRuntime* function_library, |
| 102 | const NamedTensorList& inputs, |
| 103 | const std::vector<string>& output_names, |
| 104 | std::vector<Tensor>* outputs) { |
| 105 | if (device_ == nullptr) { |
| 106 | return errors::NotFound("Cannot find a device for GraphRunner."); |
| 107 | } |
| 108 | |
| 109 | if (function_library && function_library->device() && |
| 110 | function_library->device()->device_type() != device_->device_type()) { |
| 111 | // Mismatch between function_library's device_type and device_'s |
| 112 | // device_type. |
| 113 | // TODO(matthewmurray) Can we create a new FunctionLibraryRuntime that is |
| 114 | // identical to function_library except that it uses the given 'device_'? |
| 115 | VLOG(1) << "Cannot run on: " << device_->device_type() |
| 116 | << " with a function library for a " |
| 117 | << function_library->device()->device_type() << " device."; |
| 118 | function_library = nullptr; |
| 119 | } |
| 120 | |
| 121 | // TODO(vrv): Instead of copying the entire graph, consider modifying |
| 122 | // the existing graph, and then removing those removed edges. |
| 123 | // prior to returning. |
| 124 | std::unique_ptr<Graph> graph_to_run(new Graph(graph->op_registry())); |
| 125 | CopyGraph(*graph, graph_to_run.get()); |
| 126 | |
| 127 | SimpleRendezvous* rendez = new SimpleRendezvous; |
| 128 | core::ScopedUnref rendez_unref(rendez); |
| 129 | |
| 130 | // Extract the input names and keys, and feed in the inputs. |
| 131 | std::vector<string> input_names; |
| 132 | for (const auto& in : inputs) { |
| 133 | const string& tensor_name = in.first; |
| 134 | input_names.emplace_back(tensor_name); |
| 135 | string full_key = Rendezvous::CreateKey("/device:CPU:0", 1, "/device:CPU:1", |
| 136 | tensor_name, FrameAndIter(0, 0)); |
| 137 | Rendezvous::ParsedKey parsed; |
| 138 | TF_RETURN_IF_ERROR(Rendezvous::ParseKey(full_key, &parsed)); |
| 139 | TF_RETURN_IF_ERROR(rendez->Send(parsed, Rendezvous::Args(), in.second, |
| 140 | false /* is_dead */)); |
| 141 | } |
| 142 | |
| 143 | // Call RewriteGraphForExecution |
| 144 | subgraph::RewriteGraphMetadata metadata; |
| 145 | TF_RETURN_IF_ERROR(subgraph::RewriteGraphForExecution( |
| 146 | graph_to_run.get(), input_names, output_names, {} /* target nodes */, |
| 147 | device_->attributes(), false /* use_function_convention */, &metadata)); |
| 148 | |
| 149 | // Create the local executor and the Rendezvous for fetching back the |
| 150 | // constants. |
| 151 | |
| 152 | // Run operators on the local thread. We should not need concurrency here; we |
| 153 | // should not be running expensive operators. |
| 154 | auto runner = [](Executor::Args::Closure c) { c(); }; |
| 155 | auto cost_runner = [](Executor::Args::Closure c, int64 cost) { c(); }; |
| 156 | |
| 157 | LocalExecutorParams params; |
| 158 | // The ownership of the output tensors are bound to this device's lifetime. |
nothing calls this directly
no test coverage detected