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