diff options
author | Derek Murray <mrry@google.com> | 2018-09-21 14:46:25 -0700 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2018-09-21 14:52:33 -0700 |
commit | 75138a1204c7aab340d159f5a6b85a55eb33c1e4 (patch) | |
tree | bb749a4ad2a8c4284069c632eece3575cef19441 /tensorflow/core/common_runtime | |
parent | e3108ea446b8b07d6a4aaca9667aff6ff5151a51 (diff) |
Executor: Move `GetNodeAttr()` off the critical path for loop execution.
In `ExecutorState::PropagateOutputs()`, each time a loop enter node is
processed, the node's attrs are consulted to determine if it is a
"constant" or "non-constant" enter node. This entails a call to the
protobuf library, followed by multiple string comparisons to find the
attribute in the Node's NodeDef's attr map. The value of this property
never changes after the executor is first constructed, so in this
change we move it to a cached field on the `NodeItem` struct, and use
that value.
PiperOrigin-RevId: 214047449
Diffstat (limited to 'tensorflow/core/common_runtime')
-rw-r--r-- | tensorflow/core/common_runtime/executor.cc | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/tensorflow/core/common_runtime/executor.cc b/tensorflow/core/common_runtime/executor.cc index 98719542c0..7cef34ac52 100644 --- a/tensorflow/core/common_runtime/executor.cc +++ b/tensorflow/core/common_runtime/executor.cc @@ -143,6 +143,8 @@ struct NodeItem { bool kernel_is_async : 1; // True iff kernel->AsAsync() != nullptr bool is_merge : 1; // True iff IsMerge(node) bool is_enter : 1; // True iff IsEnter(node) + bool is_constant_enter : 1; // True iff IsEnter(node) and + // node->GetAttr("is_constant") == true. bool is_exit : 1; // True iff IsExit(node) bool is_control_trigger : 1; // True iff IsControlTrigger(node) bool is_sink : 1; // True iff IsSink(node) @@ -626,6 +628,14 @@ Status ExecutorImpl::Initialize() { item->kernel_is_async = (item->kernel->AsAsync() != nullptr); item->is_merge = IsMerge(n); item->is_enter = IsEnter(n); + if (item->is_enter) { + bool is_constant_enter; + TF_RETURN_IF_ERROR( + GetNodeAttr(n->attrs(), "is_constant", &is_constant_enter)); + item->is_constant_enter = is_constant_enter; + } else { + item->is_constant_enter = false; + } item->is_exit = IsExit(n); item->is_control_trigger = IsControlTrigger(n); item->is_sink = IsSink(n); @@ -1988,15 +1998,12 @@ void ExecutorState::PropagateOutputs(const TaggedNode& tagged_node, is_frame_done = input_frame->DecrementOutstandingOpsLocked( &impl_->gview_, input_iter, ready); } else if (item->is_enter) { - bool is_constant; - const Status s = GetNodeAttr(node->attrs(), "is_constant", &is_constant); - DCHECK(s.ok()) << s; FindOrCreateChildFrame(input_frame, input_iter, node, &output_frame); output_iter = 0; { const NodeItem* item = impl_->gview_.node(node->id()); mutex_lock l(output_frame->mu); - if (is_constant) { + if (item->is_constant_enter) { // Propagate to all active iterations if this is a loop invariant. output_frame->AddLoopInv(item, (*outputs)[0], ready); } else { |