micro_allocator.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. ==============================================================================*/
  12. #ifndef TENSORFLOW_LITE_MICRO_MICRO_ALLOCATOR_H_
  13. #define TENSORFLOW_LITE_MICRO_MICRO_ALLOCATOR_H_
  14. #include <cstddef>
  15. #include <cstdint>
  16. #include "flatbuffers/flatbuffers.h" // from @flatbuffers
  17. #include "tensorflow/lite/c/common.h"
  18. #include "tensorflow/lite/core/api/error_reporter.h"
  19. #include "tensorflow/lite/micro/compatibility.h"
  20. #include "tensorflow/lite/micro/micro_op_resolver.h"
  21. #include "tensorflow/lite/micro/simple_memory_allocator.h"
  22. #include "tensorflow/lite/schema/schema_generated.h"
  23. namespace tflite {
  24. // Namespace used for unittests.
  25. namespace internal {
  26. // Sets up all of the data structure members for a TfLiteTensor based on the
  27. // contents of a serialized tensor in the flatbuffer.
  28. TfLiteStatus InitializeTfLiteTensorFromFlatbuffer(
  29. SimpleMemoryAllocator* allocator, const tflite::Tensor& flatbuffer_tensor,
  30. const flatbuffers::Vector<flatbuffers::Offset<Buffer>>* buffers,
  31. ErrorReporter* error_reporter, TfLiteTensor* result);
  32. // A handle tracking scratch buffer allocation. This handle is created by
  33. // `RequestScratchBufferInArena`. `data` field is populated in
  34. // `FinishTensorAllocation` after static memory planning.
  35. // TODO(b/150257460) As a future optimization, this struct could be replaced by
  36. // a union, since once `data` is populated, `bytes` and `node_idx` is not
  37. // needed.
  38. typedef struct {
  39. // Pointer to the scratch buffer.
  40. uint8_t* data;
  41. // Number of bytes required by the buffer. The actual allocated size might be
  42. // greater than `bytes` due to buffer alignment.
  43. size_t bytes;
  44. // Node where the buffer is allocated for. This provides useful information to
  45. // determine the lifetime of the buffer. In AllocationInfo, this buffer will
  46. // have `before` = node_idx and `after` = node_idx.
  47. int node_idx;
  48. } ScratchBufferHandle;
  49. } // namespace internal
  50. typedef struct {
  51. TfLiteNode node;
  52. const TfLiteRegistration* registration;
  53. } NodeAndRegistration;
  54. // Allocator responsible for allocating memory for all intermediate tensors
  55. // necessary to invoke a model.
  56. //
  57. // The lifetime of the model, tensor arena and error reporter must be at
  58. // least as long as that of the allocator object, since the allocator needs
  59. // them to be accessible during its entire lifetime.
  60. //
  61. // The MicroAllocator simply plans out additional allocations that are required
  62. // to standup a model for inference in TF Micro. This class currently relies on
  63. // an additional allocator - SimpleMemoryAllocator - for all allocations from an
  64. // arena. These allocations are divided into head (non-persistent) and tail
  65. // (persistent) regions:
  66. //
  67. // Memory layout to help understand how it works
  68. // This information could change in the future version.
  69. // ************** .memory_allocator->GetBuffer()
  70. // Tensors/Scratch buffers (head)
  71. // ************** .head_watermark
  72. // unused memory
  73. // ************** .memory_allocator->GetBuffer() + ->GetMaxBufferSize()
  74. // - ->GetDataSize()
  75. // persistent area (tail)
  76. // ************** .memory_allocator->GetBuffer() + ->GetMaxBufferSize()
  77. class MicroAllocator {
  78. public:
  79. // Creates a MicroAllocator instance from a given tensor arena. This arena
  80. // will be managed by the created instance.
  81. // Note: Please use __declspec(align(16)) to make sure tensor_arena is 16
  82. // bytes aligned, otherwise some head room will be wasted.
  83. // TODO(b/157615197): Cleanup constructor + factory usage.
  84. static MicroAllocator* Create(TfLiteContext* context, const Model* model,
  85. uint8_t* tensor_arena, size_t arena_size,
  86. ErrorReporter* error_reporter);
  87. // Creates a MicroAllocator instance using the provided SimpleMemoryAllocator
  88. // intance. This allocator instance will use the SimpleMemoryAllocator
  89. // instance to manage allocations internally.
  90. static MicroAllocator* Create(TfLiteContext* context, const Model* model,
  91. SimpleMemoryAllocator* memory_allocator,
  92. ErrorReporter* error_reporter);
  93. // Run through the model flatbuffer data (loaded from the TfLiteModel
  94. // instance) to allocate nodes and registrations. We need to keep them for the
  95. // entire life time of the model to allow persistent tensors. This method
  96. // needs to be called before FinishTensorAllocation method. This method also
  97. // allocates any internal Op data that is required from the flatbuffer.
  98. TfLiteStatus PrepareFromFlatbuffer(
  99. const MicroOpResolver& op_resolver,
  100. NodeAndRegistration** node_and_registrations);
  101. // Runs through the model and allocates all necessary input, output and
  102. // intermediate tensors.
  103. // WARNING: doing any allocation after calling this method has the risk of
  104. // corrupting tensor data so this method should be the last non-const method
  105. // called in this class.
  106. TfLiteStatus FinishTensorAllocation();
  107. // Allocates persistent buffer which has the same life time as the allocator.
  108. // The memory is immediately available and is allocated from the tail of the
  109. // arena.
  110. TfLiteStatus AllocatePersistentBuffer(size_t bytes, void** ptr);
  111. // Register a scratch buffer of size `bytes` for Node with `node_id`.
  112. // This method only allocates a BufferHandle holding information for memory
  113. // planning. The buffer ptr is ready after `FinishTensorAllocation` and can
  114. // be retrieved by `GetScratchBuffer` method using the returned buffer_idx.
  115. // Note that there should be no tail allocation between two consecutive
  116. // `RequestScratchBufferInArena` calls.
  117. TfLiteStatus RequestScratchBufferInArena(int node_id, size_t bytes,
  118. int* buffer_idx);
  119. // Returns the pointer to the planned scratch buffer.
  120. void* GetScratchBuffer(int buffer_idx) const;
  121. // Returns the arena usage in bytes, only available after
  122. // `FinishTensorAllocation`. Otherwise, it will return 0.
  123. size_t used_bytes() const;
  124. protected:
  125. MicroAllocator(TfLiteContext* context, const Model* model,
  126. SimpleMemoryAllocator* memory_allocator,
  127. ErrorReporter* error_reporter);
  128. virtual ~MicroAllocator();
  129. // Allocates an array in the arena to hold pointers to the tensors required
  130. // to initialize and prepare a model. These allocations are stored and
  131. // populated on the context.
  132. virtual TfLiteStatus AllocateTfLiteTensorArray();
  133. // Populates content on the list of tensor pointers required to initialize and
  134. // prepare a model from data in the flatbuffer (loaded from the TfLiteModel
  135. // instance). Persistent data (e.g. quantization params) is allocated from the
  136. // arena.
  137. virtual TfLiteStatus PopulateTfLiteTensorArrayFromFlatbuffer();
  138. // Allocates an array in the arena to hold pointers to the node and
  139. // registration pointers required to represent the inference graph of the
  140. // model.
  141. virtual TfLiteStatus AllocateNodeAndRegistrations(
  142. NodeAndRegistration** node_and_registrations);
  143. // Populates node and registration pointers representing the inference graph
  144. // of the model from values inside the flatbuffer (loaded from the TfLiteModel
  145. // instance). Persistent data (e.g. operator data) is allocated from the
  146. // arena.
  147. virtual TfLiteStatus PrepareNodeAndRegistrationDataFromFlatbuffer(
  148. const MicroOpResolver& op_resolver,
  149. NodeAndRegistration* node_and_registrations);
  150. // Returns the number of tensors in the model subgraph.
  151. size_t GetTensorsCount() const;
  152. // Returns the number of operators in the model subgraph.
  153. size_t GetOperatorsCount() const;
  154. ErrorReporter* error_reporter();
  155. // Initializes the graph and allocates TfLiteContext tensor data.
  156. TfLiteStatus InitGraphAndContextTensorData();
  157. private:
  158. // A simple memory allocator that always allocate from the arena tail.
  159. SimpleMemoryAllocator* memory_allocator_;
  160. const Model* model_;
  161. TfLiteContext* context_;
  162. ErrorReporter* error_reporter_;
  163. // Indicating if the allocator is ready for allocation.
  164. bool active_ = false;
  165. // In reverse order for efficiency.
  166. // i.e. scratch_buffer_handles_[0] is the handle for the last buffer,
  167. // corresponding to the last RequestScratchBufferInArena call.
  168. internal::ScratchBufferHandle* scratch_buffer_handles_ = nullptr;
  169. // How many scratch buffers have been allocated.
  170. size_t scratch_buffer_count_ = 0;
  171. const SubGraph* subgraph_;
  172. TF_LITE_REMOVE_VIRTUAL_DELETE
  173. };
  174. } // namespace tflite
  175. #endif // TENSORFLOW_LITE_MICRO_MICRO_ALLOCATOR_H_