• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #ifndef TENSORFLOW_LITE_CORE_SUBGRAPH_H_
16 #define TENSORFLOW_LITE_CORE_SUBGRAPH_H_
17 
18 #include <stdarg.h>
19 #include <stddef.h>
20 
21 #include <cstdint>
22 #include <cstdlib>
23 #include <map>
24 #include <memory>
25 #include <utility>
26 #include <vector>
27 
28 #include "tensorflow/lite/allocation.h"
29 #include "tensorflow/lite/c/common.h"
30 #include "tensorflow/lite/core/api/error_reporter.h"
31 #include "tensorflow/lite/core/api/profiler.h"
32 #include "tensorflow/lite/core/macros.h"
33 #include "tensorflow/lite/experimental/resource/resource_base.h"
34 #include "tensorflow/lite/memory_planner.h"
35 #include "tensorflow/lite/util.h"
36 
37 namespace tflite {
38 namespace delegates {
39 namespace test_utils {
40 class TestDelegate;  // Class for friend declarations.
41 }  // namespace test_utils
42 }  // namespace delegates
43 
44 class Subgraph {
45  public:
46   friend class Interpreter;
47 
48   Subgraph(ErrorReporter* error_reporter,
49            TfLiteExternalContext** external_contexts,
50            std::vector<std::unique_ptr<Subgraph>>* subgraphs,
51            resource::ResourceMap* resources);
52 
53   Subgraph(const Subgraph&) = delete;
54 
55   // Subgraphs should be movable but not copyable.
56   Subgraph(Subgraph&&) = default;
57   Subgraph& operator=(const Subgraph&) = delete;
58   virtual ~Subgraph();
59 
60   // Provide a list of tensor indexes that are inputs to the model.
61   // Each index is bound check and this modifies the consistent_ flag of the
62   // interpreter.
63   TfLiteStatus SetInputs(std::vector<int> inputs);
64 
65   // Provide a list of tensor indexes that are outputs to the model
66   // Each index is bound check and this modifies the consistent_ flag of the
67   // interpreter.
68   TfLiteStatus SetOutputs(std::vector<int> outputs);
69 
70   // Provide a list of tensor indexes that are variable tensors.
71   // Each index is bound check and this modifies the consistent_ flag of the
72   // interpreter.
73   TfLiteStatus SetVariables(std::vector<int> variables);
74 
75   // Ensure the internal node storage memory allocates at least `count`
76   // spots for node. NOTE, this doesn't actually add operators. This is an
77   // efficiency optimization that is subject to change.
78   void ReserveNodes(int count);
79 
80   // Adds a node with the given parameters and returns the index of the new
81   // node in `node_index` (optionally). Interpreter will take ownership of
82   // `builtin_data` and destroy it with `free`. Ownership of 'init_data'
83   // remains with the caller.
84   TfLiteStatus AddNodeWithParameters(const std::vector<int>& inputs,
85                                      const std::vector<int>& outputs,
86                                      const std::vector<int>& intermediates,
87                                      const char* init_data,
88                                      size_t init_data_size, void* builtin_data,
89                                      const TfLiteRegistration* registration,
90                                      int* node_index = nullptr);
91 
92   // Adds `tensors_to_add` tensors, preserving pre-existing Tensor entries.
93   // The value pointed to by `first_new_tensor_index` will be set to the
94   // index of the first new tensor if `first_new_tensor_index` is non-null.
95   TfLiteStatus AddTensors(int tensors_to_add,
96                           int* first_new_tensor_index = nullptr);
97 
98   // Set description of inputs/outputs/data/fptrs for node `node_index`.
99   // This variant assumes an external buffer has been allocated of size
100   // bytes. The lifetime of buffer must be ensured to be greater or equal
101   // to Interpreter. `quantization` ownership is passed to the subgraph.
102   inline TfLiteStatus SetTensorParametersReadOnly(
103       int tensor_index, TfLiteType type, const char* name,
104       const std::vector<int>& dims, TfLiteQuantization quantization,
105       const char* buffer, size_t bytes, const Allocation* allocation = nullptr,
106       TfLiteSparsity* sparsity = nullptr) {
107     return SetTensorParametersReadOnly(tensor_index, type, name, dims.size(),
108                                        dims.data(), quantization, buffer, bytes,
109                                        allocation, sparsity);
110   }
111   TfLiteStatus SetTensorParametersReadOnly(
112       int tensor_index, TfLiteType type, const char* name, const size_t rank,
113       const int* dims, TfLiteQuantization quantization, const char* buffer,
114       size_t bytes, const Allocation* allocation = nullptr,
115       TfLiteSparsity* sparsity = nullptr);
116 
117   // Set description of inputs/outputs/data/fptrs for node `node_index`.
118   // This variant assumes an external buffer has been allocated of size
119   // bytes. The lifetime of buffer must be ensured to be greater or equal
120   // to Interpreter. `quantization` ownership is passed to the subgraph.
121   inline TfLiteStatus SetTensorParametersReadWrite(
122       int tensor_index, TfLiteType type, const char* name,
123       const std::vector<int>& dims, TfLiteQuantization quantization,
124       bool is_variable = false, const std::vector<int>& dims_signature = {}) {
125     if (dims_signature.empty()) {
126       return SetTensorParametersReadWrite(tensor_index, type, name, dims.size(),
127                                           dims.data(), quantization,
128                                           is_variable);
129     }
130     return SetTensorParametersReadWrite(
131         tensor_index, type, name, dims.size(), dims.data(), quantization,
132         is_variable, dims_signature.size(), dims_signature.data());
133   }
134   TfLiteStatus SetTensorParametersReadWrite(
135       int tensor_index, TfLiteType type, const char* name, const size_t rank,
136       const int* dims, TfLiteQuantization quantization,
137       bool is_variable = false, const size_t rank_dims_signature = 0,
138       const int* dims_signature = nullptr);
139 
140   // WARNING: Experimental interface, subject to change
141   // Overrides execution plan. This bounds checks indices sent in.
142   TfLiteStatus SetExecutionPlan(const std::vector<int>& new_plan);
143 
144   // Get a mutable tensor data structure.
145   // TODO(aselle): Create a safe ArrayHandle interface to avoid exposing this
146   // read/write access to structure
tensor(int tensor_index)147   TfLiteTensor* tensor(int tensor_index) {
148     if (tensor_index < 0 ||
149         static_cast<size_t>(tensor_index) >= context_.tensors_size) {
150       return nullptr;
151     }
152     return &context_.tensors[tensor_index];
153   }
154 
155   // Get an immutable tensor data structure.
tensor(int tensor_index)156   const TfLiteTensor* tensor(int tensor_index) const {
157     if (tensor_index < 0 ||
158         static_cast<size_t>(tensor_index) >= context_.tensors_size) {
159       return nullptr;
160     }
161     return &context_.tensors[tensor_index];
162   }
163 
164   // Read only access to list of inputs.
inputs()165   std::vector<int>& inputs() { return inputs_; }
166 
167   // Read only access to list of inputs.
inputs()168   const std::vector<int>& inputs() const { return inputs_; }
169 
170   // Read only access to list of outputs.
outputs()171   std::vector<int>& outputs() { return outputs_; }
172 
173   // Read only access to list of outputs.
outputs()174   const std::vector<int>& outputs() const { return outputs_; }
175 
176   // Read only access to list of variable tensors.
variables()177   std::vector<int>& variables() { return variables_; }
178 
179   // Read only access to list of variable tensors.
variables()180   const std::vector<int>& variables() const { return variables_; }
181 
182   // WARNING: Experimental interface, subject to change.
183   // TODO(ycling): Move this function to an external context interface.
resources()184   resource::ResourceMap& resources() { return *resources_; }
185 
tensors_size()186   size_t tensors_size() const { return tensors_.size(); }
187 
188   // Return the number of ops in the model.
nodes_size()189   size_t nodes_size() const { return nodes_and_registration_.size(); }
190 
191   // Return vector of node indices in the order of execution.
execution_plan()192   std::vector<int>& execution_plan() { return execution_plan_; }
193 
194   // Return read-only vector of node indices in the order of execution.
execution_plan()195   const std::vector<int>& execution_plan() const { return execution_plan_; }
196 
197   const std::vector<std::pair<TfLiteNode, TfLiteRegistration>>&
nodes_and_registration()198   nodes_and_registration() const {
199     return nodes_and_registration_;
200   }
201 
202   // Get a pointer to an operation and registration data structure if in bounds.
node_and_registration(int node_index)203   const std::pair<TfLiteNode, TfLiteRegistration>* node_and_registration(
204       int node_index) const {
205     if (node_index < 0 || static_cast<size_t>(node_index) >= nodes_size())
206       return nullptr;
207     return &nodes_and_registration_[node_index];
208   }
209 
210   // Change the dimensionality of a given tensor. Note, this is only acceptable
211   // for tensor indices that are inputs.
212   // Returns status of failure or success.
213   // TODO(aselle): Consider implementing ArraySlice equivalent to make this
214   //   more adept at accepting data without an extra copy. Use absl::ArraySlice
215   //   if our partners determine that dependency is acceptable.
216   TfLiteStatus ResizeInputTensor(int tensor_index,
217                                  const std::vector<int>& dims);
218 
219   // WARNING: Experimental interface, subject to change
220   // Change the dimensionality of a given tensor. This is only acceptable for
221   // tensor indices that are inputs or variables. Only unknown dimensions can be
222   // resized with this function. Unknown dimensions are indicated as `-1` in the
223   // `dims_signature` attribute of a `TfLiteTensor`. Returns status of failure
224   // or success.
225   TfLiteStatus ResizeInputTensorStrict(int tensor_index,
226                                        const std::vector<int>& dims);
227 
228   // This releases memory held by non-persistent tensors. It does NOT re-perform
229   // memory planning.
230   // AllocateTensors needs to be called before next invocation.
231   TfLiteStatus ReleaseNonPersistentMemory();
232 
233   // Update allocations for all tensors. This will redim dependent tensors using
234   // the input tensor dimensionality as given. This is relatively expensive.
235   // If you know that your sizes are not changing, you need not call this.
236   // Returns status of success or failure.
237   TfLiteStatus AllocateTensors();
238 
239   // Invoke the subgraph (run the whole graph in dependency order).
240   //
241   // NOTE: It is possible that the interpreter is not in a ready state
242   // to evaluate (i.e. if a ResizeTensor() has been performed without an
243   // AllocateTensors().
244   // Returns status of success or failure.
245   TfLiteStatus Invoke();
246 
247   // Entry point for C node plugin API to report an error.
248   void ReportError(const char* format, ...);
249 
250   // Return the subgraph specific context.
context()251   TfLiteContext* context() { return &context_; }
252 
253   // Set the value of an external context.
254   void SetExternalContext(TfLiteExternalContextType type,
255                           TfLiteExternalContext* ctx);
256   // Get the half precision flag.
257   // WARNING: This is an experimental API and subject to change.
GetAllowFp16PrecisionForFp32()258   bool GetAllowFp16PrecisionForFp32() const {
259     return context_.allow_fp32_relax_to_fp16;
260   }
261 
262   // Sets the cancellation function pointer in order to cancel a request in the
263   // middle of a call to Invoke(). The interpreter queries this function during
264   // inference, between op invocations; when it returns true, the interpreter
265   // will abort execution and return `kTfLiteError`. The `data` parameter
266   // contains any data used by the cancellation function, and if non-null,
267   // remains owned by the caller.
268   // WARNING: This is an experimental API and subject to change.
269   void SetCancellationFunction(void* data, bool (*check_cancelled_func)(void*));
270 
271   // Ensure the data in `tensor.data` is readable. In case delegate is used,
272   // it might require to copy the data from delegate buffer to raw memory.
273   // WARNING: This is an experimental API and subject to change.
274   // TODO(b/119495520): make this private when refactoring complete.
EnsureTensorDataIsReadable(int tensor_index)275   TfLiteStatus EnsureTensorDataIsReadable(int tensor_index) {
276     TfLiteTensor* t = &tensors_[tensor_index];
277     TF_LITE_ENSURE(&context_, t != nullptr);
278     if (t->data_is_stale) {
279       TF_LITE_ENSURE(&context_, t->delegate != nullptr);
280       TF_LITE_ENSURE(&context_, t->buffer_handle != kTfLiteNullBufferHandle);
281       TF_LITE_ENSURE(&context_, t->delegate->CopyFromBufferHandle != nullptr);
282       // TODO(b/120420546): we must add a test that exercise this code.
283       TF_LITE_ENSURE_STATUS(t->delegate->CopyFromBufferHandle(
284           &context_, t->delegate, t->buffer_handle, t));
285       t->data_is_stale = false;
286     }
287     return kTfLiteOk;
288   }
289 
290   // The default capacity of `tensors_` vector.
291   static constexpr int kTensorsReservedCapacity = 128;
292   // The capacity headroom of `tensors_` vector before calling ops'
293   // `prepare` and `invoke` function. In these functions, it's guaranteed
294   // allocating up to `kTensorsCapacityHeadroom` more tensors won't invalidate
295   // pointers to existing tensors.
296   static constexpr int kTensorsCapacityHeadroom = 16;
297 
298   // Reset all variable tensors to the default value.
299   // If a variable tensor doesn't have a buffer, reset it to zero.
300   // TODO(b/115961645): Implement - If a variable tensor has a buffer, reset it
301   // to the value of the buffer.
302   // WARNING: This is an experimental API and subject to change.
303   TfLiteStatus ResetVariableTensors();
304 
SetProfiler(Profiler * profiler,int associated_subgraph_idx)305   void SetProfiler(Profiler* profiler, int associated_subgraph_idx) {
306     if (!profiler) {
307       profiler_.reset(nullptr);
308       context_.profiler = nullptr;
309     } else {
310       profiler_.reset(
311           new SubgraphAwareProfiler(profiler, associated_subgraph_idx));
312       context_.profiler = profiler_.get();
313     }
314   }
315 
GetProfiler()316   Profiler* GetProfiler() { return profiler_.get(); }
317 
318   // Returns a pointer to vector of subgraphs.
319   // WARNING: This is an experimental API and subject to change.
GetSubgraphs()320   std::vector<std::unique_ptr<Subgraph>>* GetSubgraphs() { return subgraphs_; }
321 
322   // True if all tensors in the graph has static size after calling
323   // `AllocateTensors` function.
324   // Before `AllocateTensors` is called, this will always return true;
HasDynamicTensors()325   bool HasDynamicTensors() { return has_dynamic_tensors_; }
326 
327   // Assigns (or reassigns) a custom memory allocation for the given tensor.
328   // If AllocateTensors() is called after this, the runtime does not consider
329   // the tensor during internal memory planning and will continue using the
330   // provided allocation for the tensor (assuming it satisfies the expected
331   // tensor byte length).
332   // The runtime does NOT take ownership of the underlying memory.
333   // Note that while this function can be called again to set a new allocation
334   // for the tensor, it can no longer be reset to the TFLite arena memory.
335   //
336   // Parameters should satisfy the following conditions:
337   // 1. tensor->allocation_type == kTfLiteArenaRw or kTfLiteArenaRwPersistent
338   //    In general, this is true for I/O tensors & variable tensors.
339   // 2. allocation->data has the appropriate permissions for runtime access
340   //    (Read-only for inputs, Read-Write for others), and outlives Interpreter.
341   // 3. allocation->bytes >= tensor->bytes.
342   //    This condition is checked again if any tensors are resized.
343   // 4. allocation->data should be aligned to kDefaultTensorAlignment
344   //    defined in lite/util.h. (Currently 64 bytes)
345   //
346   // WARNING: This is an experimental interface that is subject to change.
347   TfLiteStatus SetCustomAllocationForTensor(
348       int tensor_index, const TfLiteCustomAllocation& allocation);
349 
350   void SetName(const char* name);
351   const std::string& GetName() const;
352 
353  private:
354   friend class TestDelegate;
355   // SubgraphAwareProfiler wraps an actual TFLite profiler, such as a
356   // BufferedProfiler instance, and takes care of event profiling/tracing in a
357   // certain subgraph.
358   class SubgraphAwareProfiler : public Profiler {
359    public:
360     // Constructor should be called with the non-nullptr profiler argument.
SubgraphAwareProfiler(Profiler * profiler,int64_t subgraph_index)361     SubgraphAwareProfiler(Profiler* profiler, int64_t subgraph_index)
362         : profiler_(profiler), subgraph_index_(subgraph_index) {}
~SubgraphAwareProfiler()363     ~SubgraphAwareProfiler() override {}
364 
BeginEvent(const char * tag,EventType event_type,int64_t event_metadata1,int64_t event_metadata2)365     uint32_t BeginEvent(const char* tag, EventType event_type,
366                         int64_t event_metadata1,
367                         int64_t event_metadata2) override {
368       if (!profiler_) return 0;
369       return profiler_->BeginEvent(tag, event_type, event_metadata1,
370                                    subgraph_index_);
371     }
372 
EndEvent(uint32_t event_handle)373     void EndEvent(uint32_t event_handle) override {
374       if (!profiler_) return;
375       profiler_->EndEvent(event_handle);
376     }
377 
EndEvent(uint32_t event_handle,int64_t event_metadata1,int64_t event_metadata2)378     void EndEvent(uint32_t event_handle, int64_t event_metadata1,
379                   int64_t event_metadata2) override {
380       if (!profiler_) return;
381       profiler_->EndEvent(event_handle, event_metadata1, event_metadata2);
382     }
383 
AddEvent(const char * tag,EventType event_type,uint64_t start,uint64_t end,int64_t event_metadata1,int64_t event_metadata2)384     void AddEvent(const char* tag, EventType event_type, uint64_t start,
385                   uint64_t end, int64_t event_metadata1,
386                   int64_t event_metadata2) override {
387       if (!profiler_) return;
388       profiler_->AddEvent(tag, event_type, start, end, event_metadata1,
389                           subgraph_index_);
390     }
391 
392    private:
393     // Not own the memory.
394     Profiler* const profiler_;
395     const int64_t subgraph_index_;
396   };
397 
398   // Prevent 'context_' from accessing functions that are only available to
399   // delegated kernels.
400   void SwitchToKernelContext();
401 
402   // Add delegate-only functions to 'context_'.
403   void SwitchToDelegateContext();
404 
405   // Give 'op_reg' a chance to initialize itself using the contents of
406   // 'buffer'.
OpInit(const TfLiteRegistration & op_reg,const char * buffer,size_t length)407   void* OpInit(const TfLiteRegistration& op_reg, const char* buffer,
408                size_t length) {
409     if (op_reg.init == nullptr) return nullptr;
410     return op_reg.init(&context_, buffer, length);
411   }
412 
413   // Let 'op_reg' release any memory it might have allocated via 'OpInit'.
OpFree(const TfLiteRegistration & op_reg,void * buffer)414   void OpFree(const TfLiteRegistration& op_reg, void* buffer) {
415     if (op_reg.free == nullptr) return;
416     if (buffer) {
417       op_reg.free(&context_, buffer);
418     }
419   }
420 
421   // Prepare the given 'node' for execution.
422   TfLiteStatus OpPrepare(const TfLiteRegistration& op_reg, TfLiteNode* node);
423 
424   // Invoke the operator represented by 'node'.
OpInvoke(const TfLiteRegistration & op_reg,TfLiteNode * node)425   TfLiteStatus OpInvoke(const TfLiteRegistration& op_reg, TfLiteNode* node) {
426     if (op_reg.invoke == nullptr) return kTfLiteError;
427     return op_reg.invoke(&context_, node);
428   }
429 
430   // Call OpPrepare() for as many ops as possible, allocating memory for their
431   // tensors. If an op containing dynamic tensors is found, preparation will be
432   // postponed until this function is called again. This allows the interpreter
433   // to wait until Invoke() to resolve the sizes of dynamic tensors.
434   TfLiteStatus PrepareOpsAndTensors();
435 
436   // Call OpPrepare() for all ops starting at 'first_node'. Stop when a
437   // dynamic tensors is found or all ops have been prepared. Fill
438   // 'last_node_prepared' with the id of the op containing dynamic tensors, or
439   // the last in the graph.
440   TfLiteStatus PrepareOpsStartingAt(int first_execution_plan_index,
441                                     const std::vector<int>& execution_plan,
442                                     int* last_execution_plan_index_prepared);
443 
444   // Tensors needed by the interpreter. Use `AddTensors` to add more blank
445   // tensor entries. Note, `tensors_.data()` needs to be synchronized to the
446   // `context_` whenever this std::vector is reallocated. Currently this
447   // only happens in `AddTensors()`.
448   std::vector<TfLiteTensor> tensors_;
449 
450   // Check if an array of tensor indices are valid with respect to the Tensor
451   // array.
452   // NOTE: this changes consistent_ to be false if indices are out of bounds.
453   TfLiteStatus CheckTensorIndices(const char* label, const int* indices,
454                                   int length);
455 
456   // Check that the input indices and the output indices don't overlap.
457   // This is needed because same tensor must not be used both as input and
458   // output for an operator.
459   // NOTE: this changes consistent_ to be false if indices are out of bounds.
460   TfLiteStatus CheckInputAndOutputForOverlap(const int* input_indices,
461                                              int num_inputs,
462                                              const int* output_indices,
463                                              int num_outputs);
464 
465   // Compute the number of bytes required to represent a tensor with dimensions
466   // specified by the array dims (of length dims_size). Returns the status code
467   // and bytes.
468   TfLiteStatus BytesRequired(TfLiteType type, const int* dims, size_t dims_size,
469                              size_t* bytes);
470 
471   // Request an tensor be resized implementation. If the given tensor is of
472   // type kTfLiteDynamic it will also be allocated new memory.
473   TfLiteStatus ResizeTensorImpl(TfLiteTensor* tensor, TfLiteIntArray* new_size);
474 
475   // Report a detailed error string (will be printed to stderr).
476   // TODO(aselle): allow user of class to provide alternative destinations.
477   void ReportErrorImpl(const char* format, va_list args);
478 
479   // Entry point for C node plugin API to request an tensor be resized.
480   static TfLiteStatus ResizeTensor(TfLiteContext* context, TfLiteTensor* tensor,
481                                    TfLiteIntArray* new_size);
482   // Entry point for C node plugin API to report an error.
483   static void ReportErrorC(TfLiteContext* context, const char* format, ...);
484 
485   // Entry point for C node plugin API to add new tensors.
486   static TfLiteStatus AddTensors(TfLiteContext* context, int tensors_to_add,
487                                  int* first_new_tensor_index);
488 
489   // WARNING: This is an experimental API and subject to change.
490   // Entry point for C API ReplaceNodeSubsetsWithDelegateKernels
491   static TfLiteStatus ReplaceNodeSubsetsWithDelegateKernels(
492       TfLiteContext* context, TfLiteRegistration registration,
493       const TfLiteIntArray* nodes_to_replace, TfLiteDelegate* delegate);
494 
495   // Update the execution graph to replace some of the nodes with stub
496   // nodes. Specifically any node index that has `nodes[index]==1` will be
497   // slated for replacement with a delegate kernel specified by registration.
498   // Ownership of 'nodes_to_replace' and 'delegate' remains with the caller.
499   // WARNING: This is an experimental interface that is subject to change.
500   TfLiteStatus ReplaceNodeSubsetsWithDelegateKernels(
501       TfLiteRegistration registration, const TfLiteIntArray* nodes_to_replace,
502       TfLiteDelegate* delegate);
503 
504   // WARNING: This is an experimental interface that is subject to change.
505   // Gets the internal pointer to a TensorFlow lite node by node_index.
506   TfLiteStatus GetNodeAndRegistration(int node_index, TfLiteNode** node,
507                                       TfLiteRegistration** registration);
508 
509   // WARNING: This is an experimental interface that is subject to change.
510   // Entry point for C node plugin API to get a node by index.
511   static TfLiteStatus GetNodeAndRegistration(struct TfLiteContext*,
512                                              int node_index, TfLiteNode** node,
513                                              TfLiteRegistration** registration);
514 
515   // WARNING: This is an experimental interface that is subject to change.
516   // Gets an TfLiteIntArray* representing the execution plan. The interpreter
517   // owns this memory and it is only guaranteed to exist during the invocation
518   // of the delegate prepare.
519   TfLiteStatus GetExecutionPlan(TfLiteIntArray** execution_plan);
520 
521   // WARNING: This is an experimental interface that is subject to change.
522   // Entry point for C node plugin API to get the execution plan.
523   static TfLiteStatus GetExecutionPlan(struct TfLiteContext* context,
524                                        TfLiteIntArray** execution_plan);
525 
526   // WARNING: This is an experimental interface that is subject to change.
527   // Provides a preview of post-delegation partitioning. Each
528   // TfLiteDelegateParams in the referenced array corresponds to one instance of
529   // the delegate kernel.
530   // nodes_to_replace should point to a valid array. partition_params_array &
531   // num_partitions should be non-null.
532   // Memory allocated by this method is automatically released with another call
533   // to PreviewDelegateParitioning, or after TfLiteDelegate::Prepare is done.
534   TfLiteStatus PreviewDelegatePartitioning(
535       const TfLiteIntArray* nodes_to_replace,
536       TfLiteDelegateParams** partition_params_array, int* num_partitions);
537 
538   // WARNING: This is an experimental interface that is subject to change.
539   // Entry point for C node plugin API to preview delegation partitioning.
540   static TfLiteStatus PreviewDelegatePartitioning(
541       struct TfLiteContext* context, const TfLiteIntArray* nodes_to_replace,
542       TfLiteDelegateParams** partition_params_array, int* num_partitions);
543 
544   // Used to clear partitioning_preview_cache_, in case
545   // PreviewDelegatePartitioning was called.
546   void FreeDelegatePartitioningData();
547 
548   // Retrieve an existing external context by type.
549   TfLiteExternalContext* GetExternalContext(TfLiteExternalContextType type);
550   static TfLiteExternalContext* GetExternalContext(
551       struct TfLiteContext* context, TfLiteExternalContextType type);
552 
553   // Set the value of an external context.
554   static void SetExternalContext(struct TfLiteContext* context,
555                                  TfLiteExternalContextType type,
556                                  TfLiteExternalContext* ctx);
557 
558   // WARNING: This is an experimental API and subject to change.
559   // Allow a delegate to look at the graph and modify the graph to handle
560   // parts of the graph themselves. After this is called, the graph may
561   // contain new nodes that replace 1 more nodes.
562   // NOTE: If tensors were allocated prior to delegate application, they will
563   // be reallocated if the graph was modified (i.e., the caller does *not* need
564   // to explicitly call |AllocateTensors()| again). If tensors were unallocated,
565   // they will remain unallocated after delegate application.
566   // Returns one of the following status codes:
567   // 1. kTfLiteOk: Delegation succeeded
568   // 2. kTfLiteDelegateError: Delegation failed due to an error *in the
569   // delegate*, or the delegate parameter was null. The Subgraph has been
570   // restored to its pre-delegation state.
571   // NOTE: This reverts all delegates previously applied to the Subgraph.
572   // 3. kTfLiteApplicationError : Delegation failed to be applied due to the
573   // incompatibility with the TfLite runtime, e.g., the model graph is already
574   // immutable when applying the delegate. However, the Subgraph is still in a
575   // invokable state.
576   // 4. kTfLiteError: Unexpected/runtime failure.
577   TfLiteStatus ModifyGraphWithDelegate(TfLiteDelegate* delegate);
578 
579   // This un-applies all delegates that have been applied till now, but retains
580   // pointers to them.
581   // The old execution plan and nodes are restored.
582   TfLiteStatus UndoAllDelegates();
583 
584   // This re-applies all delegates that were undone.
585   // Does nothing if UndoAllDelegates wasn't previously called.
586   TfLiteStatus RedoAllDelegates();
587 
588   // This removes all delegates.
589   // The old execution plan and nodes are restored. The graph is invokable
590   // afterwards.
591   TfLiteStatus RemoveAllDelegates();
592 
593   // Returns true if the subgraph has delegates applied.
594   bool HasDelegates();
595 
596   // Cleanups up data reserved for the given node. Does not remove the {node,
597   // registration} pair from nodes_and_registrations_.
598   void CleanupNode(int node_index);
599 
600   // Ensures that `tensors_` has at least `kTensorsCapacityHeadroom` extra
601   // capacity. Calling this function may invalidate existing pointers to
602   // tensors. After calling this function, adding `kTensorsCapacityHeadroom`
603   // more tensors won't invalidate the pointer to existing tensors.
604   void EnsureTensorsVectorCapacity();
605 
606   // Ensures the memory required is planned and allocated.
607   TfLiteStatus EnsureMemoryAllocations();
608 
609   // Returns true if cancellation function returns true.
610   bool IsCancelled();
611 
612   // The state of the Interpreter.
613   enum State {
614     // The interpreter isn't ready to be invoked.
615     // `AllocateTensor` need to be called to enter an invokable state.
616     kStateUninvokable = 0,
617     // The interpreter is ready to be invoked.
618     kStateInvokable,
619     // The interpreter is ready to be invoked, and graph can't be further
620     // modified. The interpreter will enter this state when calling
621     // `ModifyGraphWithDelegate` and the delegate doesn't support dynamic
622     // tensors.
623     kStateInvokableAndImmutable,
624   };
625   State state_ = kStateUninvokable;
626 
627   // A pure C data structure used to communicate with the pure C plugin
628   // interface. To avoid copying tensor metadata, this is also the definitive
629   // structure to store tensors.
630   TfLiteContext context_ = {};
631 
632   // A pointer to the external contexts (kTfLiteMaxExternalContexts) array that
633   // sits inside the associated TFLite interpreter instance.
634   TfLiteExternalContext** external_contexts_;
635 
636   // Node inputs/outputs are stored in TfLiteNode and TfLiteRegistration stores
637   // function pointers to actual implementation.
638   // Nodes should appear in the order in which they are instantiated at runtime.
639   // Delegated nodes are appended after all the original ones.
640   std::vector<std::pair<TfLiteNode, TfLiteRegistration>>
641       nodes_and_registration_;
642 
643   // Whether the model is consistent. That is to say if the inputs and outputs
644   // of every node and the global inputs and outputs are valid indexes into
645   // the tensor array.
646   bool consistent_ = true;
647 
648   // Array of indices representing the tensors that are inputs to the
649   // interpreter.
650   std::vector<int> inputs_;
651 
652   // Array of indices representing the tensors that are outputs to the
653   // interpreter.
654   std::vector<int> outputs_;
655 
656   // Array of indices representing the tensors that are variable tensors.
657   std::vector<int> variables_;
658 
659   // The error reporter delegate that tflite will forward queries errors to.
660   ErrorReporter* error_reporter_;
661 
662   // Index of the next node to prepare.
663   // During Invoke(), Interpreter will allocate input tensors first, which are
664   // known to be fixed size. Then it will allocate outputs from nodes as many
665   // as possible. When there is a node that produces dynamic sized tensor.
666   // Interpreter will stop allocating tensors, set the value of next allocate
667   // node id, and execute the node to generate the output tensor before continue
668   // to allocate successors. This process repeats until all nodes are executed.
669   // NOTE: this relies on the order of nodes that is in topological order.
670   int next_execution_plan_index_to_prepare_;
671 
672   // Only used in cases where a delegate supporting dynamic tensors is applied.
673   // This helps prepare the original execution before the post-delegation one,
674   // so that tensor shapes propagate.
675   int next_original_execution_plan_index_to_prepare_;
676 
677   // This is similar to `next_execution_plan_index_to_prepare_`, but it tracks
678   // which nodes' allocation is planned with the arena planner.
679   //
680   // This is a workaround for b/127354079. It shouldn't be necessary if
681   // ArenaPlanner can "rewind" to a specific point.
682   // TODO(b/127354079): Improve ArenaPlanner and remove this mechanism.
683   int next_execution_plan_index_to_plan_allocation_;
684 
685   // WARNING: This is an experimental interface that is subject to change.
686   // This is a list of node indices (to index into nodes_and_registration).
687   // This represents a valid topological sort (dependency ordered) execution
688   // plan. In particular, it is valid for this ordering to contain only a
689   // subset of the node indices.
690   std::vector<int> execution_plan_;
691 
692   // This is a copy of the first execution_plan_ before any delegates were
693   // applied. It is empty if no delegates were applied to this Subgraph.
694   std::vector<int> pre_delegation_execution_plan_;
695 
696   // Contains a list of delegates applied by the user so far, in order.
697   std::vector<TfLiteDelegate*> delegates_applied_;
698 
699   // Set to true if UndoAllDelegates was called, and to false during
700   // RedoAllDelegates.
701   bool delegates_undone_ = false;
702 
703   // In the future, we'd like a TfLiteIntArray compatible representation.
704   // TODO(aselle): replace execution_plan_ with this.
705   std::unique_ptr<TfLiteIntArray, TfLiteIntArrayDeleter> plan_cache_;
706 
707   // Used by PreviewDelegateParitioning.
708   std::vector<TfLiteDelegateParams> partitioning_preview_cache_;
709 
710   std::unique_ptr<MemoryPlanner> memory_planner_;
711 
712   // Contains <tensor idx, custom allocation> pairs for all applicable tensors.
713   std::vector<std::pair<int, TfLiteCustomAllocation>> custom_allocations_;
714 
715   // Tracking bit for whether a tensor was resized in the course of an op
716   // invocation. This is a useful hint to ensure that dynamic tensor outputs
717   // trigger downstream reallocation after op invocation.
718   bool tensor_resized_since_op_invoke_ = false;
719 
720   // Profiler for this interpreter instance.
721   std::unique_ptr<SubgraphAwareProfiler> profiler_;
722 
723   // A pointer to vector of subgraphs. The vector is owned by the interpreter.
724   std::vector<std::unique_ptr<Subgraph>>* subgraphs_ = nullptr;
725 
726   // True if all tensors in the graph has static size after calling
727   // `PrepareOpsStartingAt` function (which is called by the `AllocateTensors`
728   // public function).
729   // The value is invalid before `PrepareOpStartingAt` is called.
730   bool has_dynamic_tensors_ = true;
731 
732   // Reference to cancellation function that can cancel a request in the middle
733   // of a call to Invoke(). When this function returns True, a kTfLiteError is
734   // thrown by Invoke().
735   bool (*check_cancelled_func_)(void*) = nullptr;
736 
737   // Reference to data used by the cancellation function in
738   // `check_cancelled_func_`.
739   void* cancellation_data_ = nullptr;
740 
741   // A map of resources. Owned by interpreter and shared by multiple subgraphs.
742   resource::ResourceMap* resources_ = nullptr;
743 
744   std::string name_;
745 };
746 
747 }  // namespace tflite
748 #endif  // TENSORFLOW_LITE_CORE_SUBGRAPH_H_
749