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 = 14416;
54 constexpr int kKeywordModelTailSize = 13744;
55 constexpr int kKeywordModelPersistentTfLiteTensorDataSize = 128;
56 constexpr int kKeywordModelPersistentBufferDataSize = 564;
57 #else
58 constexpr int kKeywordModelTotalSize = 14992;
59 constexpr int kKeywordModelTailSize = 14320;
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 = 9792;
78 constexpr int kTestConvModelTailSize = 2048;
79 constexpr int kTestConvModelPersistentTfLiteTensorDataSize = 128;
80 constexpr int kTestConvModelPersistentBufferDataSize = 680;
81 #else
82 constexpr int kTestConvModelTotalSize = 10112;
83 constexpr int kTestConvModelTailSize = 2368;
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
181 // Ensure tail allocation recording is not missing any large chunks:
182 size_t tail_est_length = sizeof(TfLiteEvalTensor) * thresholds.tensor_count +
183 thresholds.tensor_variable_buffer_data_size +
184 sizeof(tflite::NodeAndRegistration) *
185 thresholds.node_and_registration_count +
186 thresholds.op_runtime_data_size;
187 TF_LITE_MICRO_EXPECT_LE(thresholds.tail_alloc_size - tail_est_length,
188 kAllocationTailMiscCeiling);
189 }
190
191 } // namespace
192
193 TF_LITE_MICRO_TESTS_BEGIN
194
TF_LITE_MICRO_TEST(TestKeywordModelMemoryThreshold)195 TF_LITE_MICRO_TEST(TestKeywordModelMemoryThreshold) {
196 tflite::AllOpsResolver all_ops_resolver;
197 tflite::RecordingMicroInterpreter interpreter(
198 tflite::GetModel(g_keyword_scrambled_model_data), all_ops_resolver,
199 keyword_model_tensor_arena, kKeywordModelTensorArenaSize,
200 tflite::GetMicroErrorReporter());
201
202 interpreter.AllocateTensors();
203
204 ModelAllocationThresholds thresholds;
205 thresholds.tensor_count = kKeywordModelTensorCount;
206 thresholds.node_and_registration_count =
207 kKeywordModelNodeAndRegistrationCount;
208 thresholds.total_alloc_size = kKeywordModelTotalSize;
209 thresholds.head_alloc_size = kKeywordModelHeadSize;
210 thresholds.tail_alloc_size = kKeywordModelTailSize;
211 thresholds.tensor_variable_buffer_data_size =
212 kKeywordModelTfLiteTensorVariableBufferDataSize;
213 thresholds.op_runtime_data_size = kKeywordModelOpRuntimeDataSize;
214 thresholds.persistent_buffer_data = kKeywordModelPersistentBufferDataSize;
215 thresholds.persistent_tflite_tensor_data_size =
216 kKeywordModelPersistentTfLiteTensorDataSize;
217 thresholds.persistent_tflite_tensor_quantization_data_size =
218 kKeywordModelPersistentTfLiteTensorQuantizationData;
219
220 ValidateModelAllocationThresholds(interpreter.GetMicroAllocator(),
221 thresholds);
222 }
223
TF_LITE_MICRO_TEST(TestConvModelMemoryThreshold)224 TF_LITE_MICRO_TEST(TestConvModelMemoryThreshold) {
225 tflite::AllOpsResolver all_ops_resolver;
226 tflite::RecordingMicroInterpreter interpreter(
227 tflite::GetModel(kTestConvModelData), all_ops_resolver,
228 test_conv_tensor_arena, kTestConvModelArenaSize,
229 tflite::GetMicroErrorReporter());
230
231 interpreter.AllocateTensors();
232
233 ModelAllocationThresholds thresholds;
234 thresholds.tensor_count = kTestConvModelTensorCount;
235 thresholds.node_and_registration_count =
236 kTestConvModelNodeAndRegistrationCount;
237 thresholds.total_alloc_size = kTestConvModelTotalSize;
238 thresholds.head_alloc_size = kTestConvModelHeadSize;
239 thresholds.tail_alloc_size = kTestConvModelTailSize;
240 thresholds.op_runtime_data_size = kTestConvModelOpRuntimeDataSize;
241 thresholds.persistent_buffer_data = kTestConvModelPersistentBufferDataSize;
242 thresholds.persistent_tflite_tensor_data_size =
243 kTestConvModelPersistentTfLiteTensorDataSize;
244 thresholds.persistent_tflite_tensor_quantization_data_size =
245 kTestConvModelPersistentTfLiteTensorQuantizationData;
246
247 ValidateModelAllocationThresholds(interpreter.GetMicroAllocator(),
248 thresholds);
249 }
250
251 TF_LITE_MICRO_TESTS_END
252