• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2020 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 
16 #include <stdint.h>
17 
18 #include "tensorflow/lite/micro/all_ops_resolver.h"
19 #include "tensorflow/lite/micro/benchmarks/keyword_scrambled_model_data.h"
20 #include "tensorflow/lite/micro/micro_error_reporter.h"
21 #include "tensorflow/lite/micro/recording_micro_allocator.h"
22 #include "tensorflow/lite/micro/recording_micro_interpreter.h"
23 #include "tensorflow/lite/micro/testing/micro_test.h"
24 #include "tensorflow/lite/micro/testing/test_conv_model.h"
25 
26 /**
27  * Tests to ensure arena memory allocation does not regress by more than 3%.
28  */
29 
30 namespace {
31 
32 // Ensure memory doesn't expand more that 3%:
33 constexpr float kAllocationThreshold = 0.03;
34 
35 // TODO(b/160617245): Record persistent allocations to provide a more accurate
36 // number here.
37 constexpr float kAllocationTailMiscCeiling = 2 * 1024;
38 
39 const bool kIs64BitSystem = (sizeof(void*) == 8);
40 
41 constexpr int kKeywordModelTensorArenaSize = 22 * 1024;
42 uint8_t keyword_model_tensor_arena[kKeywordModelTensorArenaSize];
43 
44 constexpr int kKeywordModelTensorCount = 54;
45 constexpr int kKeywordModelNodeAndRegistrationCount = 15;
46 
47 // NOTE: These values are measured on x86-64:
48 // TODO(b/158651472): Consider auditing these values on non-64 bit systems.
49 //
50 // Run this test with '--copt=-DTF_LITE_STATIC_MEMORY' to get optimized memory
51 // runtime values:
52 #ifdef TF_LITE_STATIC_MEMORY
53 constexpr int kKeywordModelTotalSize = 14384;
54 constexpr int kKeywordModelTailSize = 13712;
55 constexpr int kKeywordModelPersistentTfLiteTensorDataSize = 128;
56 constexpr int kKeywordModelPersistentBufferDataSize = 572;
57 #else
58 constexpr int kKeywordModelTotalSize = 14832;
59 constexpr int kKeywordModelTailSize = 14160;
60 constexpr int kKeywordModelPersistentTfLiteTensorDataSize = 224;
61 constexpr int kKeywordModelPersistentBufferDataSize = 564;
62 #endif
63 constexpr int kKeywordModelHeadSize = 672;
64 constexpr int kKeywordModelTfLiteTensorVariableBufferDataSize = 10240;
65 constexpr int kKeywordModelPersistentTfLiteTensorQuantizationData = 64;
66 constexpr int kKeywordModelOpRuntimeDataSize = 148;
67 
68 constexpr int kTestConvModelArenaSize = 12 * 1024;
69 uint8_t test_conv_tensor_arena[kTestConvModelArenaSize];
70 
71 constexpr int kTestConvModelTensorCount = 15;
72 constexpr int kTestConvModelNodeAndRegistrationCount = 7;
73 
74 // NOTE: These values are measured on x86-64:
75 // TODO(b/158651472): Consider auditing these values on non-64 bit systems.
76 #ifdef TF_LITE_STATIC_MEMORY
77 constexpr int kTestConvModelTotalSize = 9744;
78 constexpr int kTestConvModelTailSize = 2000;
79 constexpr int kTestConvModelPersistentTfLiteTensorDataSize = 128;
80 constexpr int kTestConvModelPersistentBufferDataSize = 672;
81 #else
82 constexpr int kTestConvModelTotalSize = 10016;
83 constexpr int kTestConvModelTailSize = 2272;
84 constexpr int kTestConvModelPersistentTfLiteTensorDataSize = 224;
85 constexpr int kTestConvModelPersistentBufferDataSize = 680;
86 #endif
87 constexpr int kTestConvModelHeadSize = 7744;
88 constexpr int kTestConvModelOpRuntimeDataSize = 136;
89 constexpr int kTestConvModelPersistentTfLiteTensorQuantizationData = 0;
90 
91 struct ModelAllocationThresholds {
92   size_t tensor_count = 0;
93   size_t node_and_registration_count = 0;
94   size_t total_alloc_size = 0;
95   size_t head_alloc_size = 0;
96   size_t tail_alloc_size = 0;
97   size_t tensor_variable_buffer_data_size = 0;
98   size_t persistent_tflite_tensor_data_size = 0;
99   size_t persistent_tflite_tensor_quantization_data_size = 0;
100   size_t op_runtime_data_size = 0;
101   size_t persistent_buffer_data = 0;
102 };
103 
EnsureAllocatedSizeThreshold(const char * allocation_type,size_t actual,size_t expected)104 void EnsureAllocatedSizeThreshold(const char* allocation_type, size_t actual,
105                                   size_t expected) {
106   // TODO(b/158651472): Better auditing of non-64 bit systems:
107   if (kIs64BitSystem) {
108     // 64-bit systems should check floor and ceiling to catch memory savings:
109     TF_LITE_MICRO_EXPECT_NEAR(actual, expected,
110                               expected * kAllocationThreshold);
111     if (actual != expected) {
112       TF_LITE_REPORT_ERROR(tflite::GetMicroErrorReporter(),
113                            "%s threshold failed: %d != %d", allocation_type,
114                            actual, expected);
115     }
116   } else {
117     // Non-64 bit systems should just expect allocation does not exceed the
118     // ceiling:
119     TF_LITE_MICRO_EXPECT_LE(actual, expected + expected * kAllocationThreshold);
120   }
121 }
122 
ValidateModelAllocationThresholds(const tflite::RecordingMicroAllocator & allocator,const ModelAllocationThresholds & thresholds)123 void ValidateModelAllocationThresholds(
124     const tflite::RecordingMicroAllocator& allocator,
125     const ModelAllocationThresholds& thresholds) {
126   allocator.PrintAllocations();
127 
128   EnsureAllocatedSizeThreshold(
129       "Total", allocator.GetSimpleMemoryAllocator()->GetUsedBytes(),
130       thresholds.total_alloc_size);
131   EnsureAllocatedSizeThreshold(
132       "Head", allocator.GetSimpleMemoryAllocator()->GetHeadUsedBytes(),
133       thresholds.head_alloc_size);
134   EnsureAllocatedSizeThreshold(
135       "Tail", allocator.GetSimpleMemoryAllocator()->GetTailUsedBytes(),
136       thresholds.tail_alloc_size);
137   EnsureAllocatedSizeThreshold(
138       "TfLiteEvalTensor",
139       allocator
140           .GetRecordedAllocation(
141               tflite::RecordedAllocationType::kTfLiteEvalTensorData)
142           .used_bytes,
143       sizeof(TfLiteEvalTensor) * thresholds.tensor_count);
144   EnsureAllocatedSizeThreshold(
145       "VariableBufferData",
146       allocator
147           .GetRecordedAllocation(
148               tflite::RecordedAllocationType::kTfLiteTensorVariableBufferData)
149           .used_bytes,
150       thresholds.tensor_variable_buffer_data_size);
151   EnsureAllocatedSizeThreshold(
152       "PersistentTfLiteTensor",
153       allocator
154           .GetRecordedAllocation(
155               tflite::RecordedAllocationType::kPersistentTfLiteTensorData)
156           .used_bytes,
157       thresholds.persistent_tflite_tensor_data_size);
158   EnsureAllocatedSizeThreshold(
159       "PersistentTfliteTensorQuantizationData",
160       allocator
161           .GetRecordedAllocation(tflite::RecordedAllocationType::
162                                      kPersistentTfLiteTensorQuantizationData)
163           .used_bytes,
164       thresholds.persistent_tflite_tensor_quantization_data_size);
165   EnsureAllocatedSizeThreshold(
166       "PersistentBufferData",
167       allocator
168           .GetRecordedAllocation(
169               tflite::RecordedAllocationType::kPersistentBufferData)
170           .used_bytes,
171       thresholds.persistent_buffer_data);
172   EnsureAllocatedSizeThreshold(
173       "NodeAndRegistration",
174       allocator
175           .GetRecordedAllocation(
176               tflite::RecordedAllocationType::kNodeAndRegistrationArray)
177           .used_bytes,
178       sizeof(tflite::NodeAndRegistration) *
179           thresholds.node_and_registration_count);
180   EnsureAllocatedSizeThreshold(
181       "OpData",
182       allocator.GetRecordedAllocation(tflite::RecordedAllocationType::kOpData)
183           .used_bytes,
184       thresholds.op_runtime_data_size);
185 
186   // Ensure tail allocation recording is not missing any large chunks:
187   size_t tail_est_length = sizeof(TfLiteEvalTensor) * thresholds.tensor_count +
188                            thresholds.tensor_variable_buffer_data_size +
189                            sizeof(tflite::NodeAndRegistration) *
190                                thresholds.node_and_registration_count +
191                            thresholds.op_runtime_data_size;
192   TF_LITE_MICRO_EXPECT_LE(thresholds.tail_alloc_size - tail_est_length,
193                           kAllocationTailMiscCeiling);
194 }
195 
196 }  // namespace
197 
198 TF_LITE_MICRO_TESTS_BEGIN
199 
TF_LITE_MICRO_TEST(TestKeywordModelMemoryThreshold)200 TF_LITE_MICRO_TEST(TestKeywordModelMemoryThreshold) {
201   tflite::AllOpsResolver all_ops_resolver;
202   tflite::RecordingMicroInterpreter interpreter(
203       tflite::GetModel(g_keyword_scrambled_model_data), all_ops_resolver,
204       keyword_model_tensor_arena, kKeywordModelTensorArenaSize,
205       tflite::GetMicroErrorReporter());
206 
207   interpreter.AllocateTensors();
208 
209   ModelAllocationThresholds thresholds;
210   thresholds.tensor_count = kKeywordModelTensorCount;
211   thresholds.node_and_registration_count =
212       kKeywordModelNodeAndRegistrationCount;
213   thresholds.total_alloc_size = kKeywordModelTotalSize;
214   thresholds.head_alloc_size = kKeywordModelHeadSize;
215   thresholds.tail_alloc_size = kKeywordModelTailSize;
216   thresholds.tensor_variable_buffer_data_size =
217       kKeywordModelTfLiteTensorVariableBufferDataSize;
218   thresholds.op_runtime_data_size = kKeywordModelOpRuntimeDataSize;
219   thresholds.persistent_buffer_data = kKeywordModelPersistentBufferDataSize;
220   thresholds.persistent_tflite_tensor_data_size =
221       kKeywordModelPersistentTfLiteTensorDataSize;
222   thresholds.persistent_tflite_tensor_quantization_data_size =
223       kKeywordModelPersistentTfLiteTensorQuantizationData;
224 
225   ValidateModelAllocationThresholds(interpreter.GetMicroAllocator(),
226                                     thresholds);
227 }
228 
TF_LITE_MICRO_TEST(TestConvModelMemoryThreshold)229 TF_LITE_MICRO_TEST(TestConvModelMemoryThreshold) {
230   tflite::AllOpsResolver all_ops_resolver;
231   tflite::RecordingMicroInterpreter interpreter(
232       tflite::GetModel(kTestConvModelData), all_ops_resolver,
233       test_conv_tensor_arena, kTestConvModelArenaSize,
234       tflite::GetMicroErrorReporter());
235 
236   interpreter.AllocateTensors();
237 
238   ModelAllocationThresholds thresholds;
239   thresholds.tensor_count = kTestConvModelTensorCount;
240   thresholds.node_and_registration_count =
241       kTestConvModelNodeAndRegistrationCount;
242   thresholds.total_alloc_size = kTestConvModelTotalSize;
243   thresholds.head_alloc_size = kTestConvModelHeadSize;
244   thresholds.tail_alloc_size = kTestConvModelTailSize;
245   thresholds.op_runtime_data_size = kTestConvModelOpRuntimeDataSize;
246   thresholds.persistent_buffer_data = kTestConvModelPersistentBufferDataSize;
247   thresholds.persistent_tflite_tensor_data_size =
248       kTestConvModelPersistentTfLiteTensorDataSize;
249   thresholds.persistent_tflite_tensor_quantization_data_size =
250       kTestConvModelPersistentTfLiteTensorQuantizationData;
251 
252   ValidateModelAllocationThresholds(interpreter.GetMicroAllocator(),
253                                     thresholds);
254 }
255 
256 TF_LITE_MICRO_TESTS_END
257