1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <executorch/extension/tensor/tensor_ptr_maker.h>
10
11 #include <gtest/gtest.h>
12
13 #include <executorch/runtime/platform/runtime.h>
14
15 using namespace ::executorch::extension;
16 using namespace ::executorch::runtime;
17
18 class TensorPtrMakerTest : public ::testing::Test {
19 protected:
SetUpTestSuite()20 static void SetUpTestSuite() {
21 runtime_init();
22 }
23 };
24
TEST_F(TensorPtrMakerTest,CreateTensorUsingTensorMaker)25 TEST_F(TensorPtrMakerTest, CreateTensorUsingTensorMaker) {
26 float data[20] = {2};
27 auto tensor = for_blob(data, {4, 5})
28 .dim_order({0, 1})
29 .strides({5, 1})
30 .dynamism(exec_aten::TensorShapeDynamism::DYNAMIC_BOUND)
31 .make_tensor_ptr();
32
33 EXPECT_EQ(tensor->dim(), 2);
34 EXPECT_EQ(tensor->size(0), 4);
35 EXPECT_EQ(tensor->size(1), 5);
36 EXPECT_EQ(tensor->strides()[0], 5);
37 EXPECT_EQ(tensor->strides()[1], 1);
38 EXPECT_EQ(tensor->const_data_ptr<float>(), data);
39 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 2);
40 }
41
TEST_F(TensorPtrMakerTest,PerfectForwardingLValue)42 TEST_F(TensorPtrMakerTest, PerfectForwardingLValue) {
43 float data[20] = {2};
44 std::vector<exec_aten::SizesType> sizes = {4, 5};
45 std::vector<exec_aten::DimOrderType> dim_order = {0, 1};
46 std::vector<exec_aten::StridesType> strides = {5, 1};
47
48 auto tensor = for_blob(data, sizes)
49 .dim_order(dim_order)
50 .strides(strides)
51 .make_tensor_ptr();
52
53 EXPECT_EQ(tensor->dim(), 2);
54 EXPECT_EQ(tensor->size(0), 4);
55 EXPECT_EQ(tensor->size(1), 5);
56 EXPECT_EQ(tensor->strides()[0], 5);
57 EXPECT_EQ(tensor->strides()[1], 1);
58
59 EXPECT_EQ(sizes.size(), 2);
60 EXPECT_EQ(dim_order.size(), 2);
61 EXPECT_EQ(strides.size(), 2);
62 }
63
TEST_F(TensorPtrMakerTest,PerfectForwardingRValue)64 TEST_F(TensorPtrMakerTest, PerfectForwardingRValue) {
65 float data[20] = {2};
66 std::vector<exec_aten::SizesType> sizes = {4, 5};
67 std::vector<exec_aten::DimOrderType> dim_order = {0, 1};
68 std::vector<exec_aten::StridesType> strides = {5, 1};
69
70 auto tensor = for_blob(data, std::move(sizes))
71 .dim_order(std::move(dim_order))
72 .strides(std::move(strides))
73 .make_tensor_ptr();
74
75 EXPECT_EQ(tensor->dim(), 2);
76 EXPECT_EQ(tensor->size(0), 4);
77 EXPECT_EQ(tensor->size(1), 5);
78 EXPECT_EQ(tensor->strides()[0], 5);
79 EXPECT_EQ(tensor->strides()[1], 1);
80 // for_blob() moved the contents of the vectors, leaving these empty.
81 EXPECT_EQ(sizes.size(), 0); // NOLINT(bugprone-use-after-move)
82 EXPECT_EQ(dim_order.size(), 0); // NOLINT(bugprone-use-after-move)
83 EXPECT_EQ(strides.size(), 0); // NOLINT(bugprone-use-after-move)
84 }
85
TEST_F(TensorPtrMakerTest,CreateTensorFromBlob)86 TEST_F(TensorPtrMakerTest, CreateTensorFromBlob) {
87 float data[20] = {2};
88 auto tensor = from_blob(data, {4, 5});
89
90 EXPECT_EQ(tensor->dim(), 2);
91 EXPECT_EQ(tensor->size(0), 4);
92 EXPECT_EQ(tensor->size(1), 5);
93 EXPECT_EQ(tensor->strides()[0], 5);
94 EXPECT_EQ(tensor->strides()[1], 1);
95 EXPECT_EQ(tensor->const_data_ptr<float>(), data);
96 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 2);
97 EXPECT_EQ(tensor->const_data_ptr<float>()[19], 0);
98 }
99
TEST_F(TensorPtrMakerTest,CreateTensorUsingFromBlobWithStrides)100 TEST_F(TensorPtrMakerTest, CreateTensorUsingFromBlobWithStrides) {
101 float data[20] = {3};
102 auto tensor = from_blob(data, {2, 2, 2}, {4, 2, 1});
103
104 EXPECT_EQ(tensor->dim(), 3);
105 EXPECT_EQ(tensor->size(0), 2);
106 EXPECT_EQ(tensor->size(1), 2);
107 EXPECT_EQ(tensor->size(2), 2);
108 EXPECT_EQ(tensor->strides()[0], 4);
109 EXPECT_EQ(tensor->strides()[1], 2);
110 EXPECT_EQ(tensor->strides()[2], 1);
111 EXPECT_EQ(tensor->const_data_ptr<float>(), data);
112 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 3);
113 }
114
TEST_F(TensorPtrMakerTest,TensorMakerConversionOperator)115 TEST_F(TensorPtrMakerTest, TensorMakerConversionOperator) {
116 float data[20] = {2};
117 TensorPtr tensor =
118 for_blob(data, {4, 5})
119 .dynamism(exec_aten::TensorShapeDynamism::DYNAMIC_BOUND);
120
121 EXPECT_EQ(tensor->dim(), 2);
122 EXPECT_EQ(tensor->size(0), 4);
123 EXPECT_EQ(tensor->size(1), 5);
124 }
125
TEST_F(TensorPtrMakerTest,CreateTensorWithZeroDimensions)126 TEST_F(TensorPtrMakerTest, CreateTensorWithZeroDimensions) {
127 float data[1] = {2};
128 auto tensor = from_blob(data, {});
129
130 EXPECT_EQ(tensor->dim(), 0);
131 EXPECT_EQ(tensor->numel(), 1);
132 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 2);
133 }
134
TEST_F(TensorPtrMakerTest,TensorWithCustomDataDeleter)135 TEST_F(TensorPtrMakerTest, TensorWithCustomDataDeleter) {
136 auto deleter_called = false;
137 float* data = new float[20]();
138 auto tensor = for_blob(data, {4, 5})
139 .deleter([&deleter_called](void* ptr) {
140 deleter_called = true;
141 delete[] static_cast<float*>(ptr);
142 })
143 .make_tensor_ptr();
144
145 tensor.reset();
146 EXPECT_TRUE(deleter_called);
147 }
148
TEST_F(TensorPtrMakerTest,TensorManagesMovedVector)149 TEST_F(TensorPtrMakerTest, TensorManagesMovedVector) {
150 auto deleter_called = false;
151 std::vector<float> data(20, 3.0f);
152 auto* data_ptr = data.data();
153 auto tensor = for_blob(data_ptr, {4, 5})
154 .deleter([moved_data = std::move(data), &deleter_called](
155 void*) mutable { deleter_called = true; })
156 .make_tensor_ptr();
157
158 EXPECT_TRUE(data.empty()); // NOLINT(bugprone-use-after-move)
159 EXPECT_EQ(tensor->data_ptr<float>(), data_ptr);
160
161 tensor.reset();
162 EXPECT_TRUE(deleter_called);
163 }
164
TEST_F(TensorPtrMakerTest,TensorDeleterReleasesCapturedSharedPtr)165 TEST_F(TensorPtrMakerTest, TensorDeleterReleasesCapturedSharedPtr) {
166 auto deleter_called = false;
167 std::shared_ptr<float[]> data_ptr(
168 new float[10], [](float* ptr) { delete[] ptr; });
169 auto tensor = from_blob(
170 data_ptr.get(),
171 {4, 5},
172 exec_aten::ScalarType::Float,
173 [data_ptr, &deleter_called](void*) mutable { deleter_called = true; });
174
175 EXPECT_EQ(data_ptr.use_count(), 2);
176
177 tensor.reset();
178 EXPECT_TRUE(deleter_called);
179 EXPECT_EQ(data_ptr.use_count(), 1);
180 }
181
TEST_F(TensorPtrMakerTest,CreateEmpty)182 TEST_F(TensorPtrMakerTest, CreateEmpty) {
183 auto tensor = empty({4, 5});
184 EXPECT_EQ(tensor->dim(), 2);
185 EXPECT_EQ(tensor->size(0), 4);
186 EXPECT_EQ(tensor->size(1), 5);
187 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
188
189 auto tensor2 = empty({4, 5}, exec_aten::ScalarType::Int);
190 EXPECT_EQ(tensor2->dim(), 2);
191 EXPECT_EQ(tensor2->size(0), 4);
192 EXPECT_EQ(tensor2->size(1), 5);
193 EXPECT_EQ(tensor2->scalar_type(), exec_aten::ScalarType::Int);
194
195 auto tensor3 = empty({4, 5}, exec_aten::ScalarType::Long);
196 EXPECT_EQ(tensor3->dim(), 2);
197 EXPECT_EQ(tensor3->size(0), 4);
198 EXPECT_EQ(tensor3->size(1), 5);
199 EXPECT_EQ(tensor3->scalar_type(), exec_aten::ScalarType::Long);
200
201 auto tensor4 = empty({4, 5}, exec_aten::ScalarType::Double);
202 EXPECT_EQ(tensor4->dim(), 2);
203 EXPECT_EQ(tensor4->size(0), 4);
204 EXPECT_EQ(tensor4->size(1), 5);
205 EXPECT_EQ(tensor4->scalar_type(), exec_aten::ScalarType::Double);
206 }
207
TEST_F(TensorPtrMakerTest,CreateFull)208 TEST_F(TensorPtrMakerTest, CreateFull) {
209 auto tensor = full({4, 5}, 7);
210 EXPECT_EQ(tensor->dim(), 2);
211 EXPECT_EQ(tensor->size(0), 4);
212 EXPECT_EQ(tensor->size(1), 5);
213 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
214 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 7);
215
216 auto tensor2 = full({4, 5}, 3, exec_aten::ScalarType::Int);
217 EXPECT_EQ(tensor2->dim(), 2);
218 EXPECT_EQ(tensor2->size(0), 4);
219 EXPECT_EQ(tensor2->size(1), 5);
220 EXPECT_EQ(tensor2->scalar_type(), exec_aten::ScalarType::Int);
221 EXPECT_EQ(tensor2->const_data_ptr<int32_t>()[0], 3);
222
223 auto tensor3 = full({4, 5}, 9, exec_aten::ScalarType::Long);
224 EXPECT_EQ(tensor3->dim(), 2);
225 EXPECT_EQ(tensor3->size(0), 4);
226 EXPECT_EQ(tensor3->size(1), 5);
227 EXPECT_EQ(tensor3->scalar_type(), exec_aten::ScalarType::Long);
228 EXPECT_EQ(tensor3->const_data_ptr<int64_t>()[0], 9);
229
230 auto tensor4 = full({4, 5}, 11, exec_aten::ScalarType::Double);
231 EXPECT_EQ(tensor4->dim(), 2);
232 EXPECT_EQ(tensor4->size(0), 4);
233 EXPECT_EQ(tensor4->size(1), 5);
234 EXPECT_EQ(tensor4->scalar_type(), exec_aten::ScalarType::Double);
235 EXPECT_EQ(tensor4->const_data_ptr<double>()[0], 11);
236 }
237
TEST_F(TensorPtrMakerTest,CreateScalar)238 TEST_F(TensorPtrMakerTest, CreateScalar) {
239 auto tensor = scalar_tensor(3.14f);
240
241 EXPECT_EQ(tensor->dim(), 0);
242 EXPECT_EQ(tensor->numel(), 1);
243 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
244 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 3.14f);
245
246 auto tensor2 = scalar_tensor(5, exec_aten::ScalarType::Int);
247
248 EXPECT_EQ(tensor2->dim(), 0);
249 EXPECT_EQ(tensor2->numel(), 1);
250 EXPECT_EQ(tensor2->scalar_type(), exec_aten::ScalarType::Int);
251 EXPECT_EQ(tensor2->const_data_ptr<int32_t>()[0], 5);
252
253 auto tensor3 = scalar_tensor(7.0, exec_aten::ScalarType::Double);
254
255 EXPECT_EQ(tensor3->dim(), 0);
256 EXPECT_EQ(tensor3->numel(), 1);
257 EXPECT_EQ(tensor3->scalar_type(), exec_aten::ScalarType::Double);
258 EXPECT_EQ(tensor3->const_data_ptr<double>()[0], 7.0);
259 }
260
TEST_F(TensorPtrMakerTest,CreateOnes)261 TEST_F(TensorPtrMakerTest, CreateOnes) {
262 auto tensor = ones({4, 5});
263 EXPECT_EQ(tensor->dim(), 2);
264 EXPECT_EQ(tensor->size(0), 4);
265 EXPECT_EQ(tensor->size(1), 5);
266 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
267 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 1);
268
269 auto tensor2 = ones({4, 5}, exec_aten::ScalarType::Int);
270 EXPECT_EQ(tensor2->dim(), 2);
271 EXPECT_EQ(tensor2->size(0), 4);
272 EXPECT_EQ(tensor2->size(1), 5);
273 EXPECT_EQ(tensor2->scalar_type(), exec_aten::ScalarType::Int);
274 EXPECT_EQ(tensor2->const_data_ptr<int32_t>()[0], 1);
275
276 auto tensor3 = ones({4, 5}, exec_aten::ScalarType::Long);
277 EXPECT_EQ(tensor3->dim(), 2);
278 EXPECT_EQ(tensor3->size(0), 4);
279 EXPECT_EQ(tensor3->size(1), 5);
280 EXPECT_EQ(tensor3->scalar_type(), exec_aten::ScalarType::Long);
281 EXPECT_EQ(tensor3->const_data_ptr<int64_t>()[0], 1);
282
283 auto tensor4 = ones({4, 5}, exec_aten::ScalarType::Double);
284 EXPECT_EQ(tensor4->dim(), 2);
285 EXPECT_EQ(tensor4->size(0), 4);
286 EXPECT_EQ(tensor4->size(1), 5);
287 EXPECT_EQ(tensor4->scalar_type(), exec_aten::ScalarType::Double);
288 EXPECT_EQ(tensor4->const_data_ptr<double>()[0], 1);
289 }
290
TEST_F(TensorPtrMakerTest,CreateZeros)291 TEST_F(TensorPtrMakerTest, CreateZeros) {
292 auto tensor = zeros({4, 5});
293 EXPECT_EQ(tensor->dim(), 2);
294 EXPECT_EQ(tensor->size(0), 4);
295 EXPECT_EQ(tensor->size(1), 5);
296 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
297 EXPECT_EQ(tensor->const_data_ptr<float>()[0], 0);
298
299 auto tensor2 = zeros({4, 5}, exec_aten::ScalarType::Int);
300 EXPECT_EQ(tensor2->dim(), 2);
301 EXPECT_EQ(tensor2->size(0), 4);
302 EXPECT_EQ(tensor2->size(1), 5);
303 EXPECT_EQ(tensor2->scalar_type(), exec_aten::ScalarType::Int);
304 EXPECT_EQ(tensor2->const_data_ptr<int32_t>()[0], 0);
305
306 auto tensor3 = zeros({4, 5}, exec_aten::ScalarType::Long);
307 EXPECT_EQ(tensor3->dim(), 2);
308 EXPECT_EQ(tensor3->size(0), 4);
309 EXPECT_EQ(tensor3->size(1), 5);
310 EXPECT_EQ(tensor3->scalar_type(), exec_aten::ScalarType::Long);
311 EXPECT_EQ(tensor3->const_data_ptr<int64_t>()[0], 0);
312
313 auto tensor4 = zeros({4, 5}, exec_aten::ScalarType::Double);
314 EXPECT_EQ(tensor4->dim(), 2);
315 EXPECT_EQ(tensor4->size(0), 4);
316 EXPECT_EQ(tensor4->size(1), 5);
317 EXPECT_EQ(tensor4->scalar_type(), exec_aten::ScalarType::Double);
318 EXPECT_EQ(tensor4->const_data_ptr<double>()[0], 0);
319 }
320
TEST_F(TensorPtrMakerTest,CreateRandTensor)321 TEST_F(TensorPtrMakerTest, CreateRandTensor) {
322 auto tensor = rand({4, 5});
323
324 EXPECT_EQ(tensor->dim(), 2);
325 EXPECT_EQ(tensor->size(0), 4);
326 EXPECT_EQ(tensor->size(1), 5);
327 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
328
329 for (auto i = 0; i < tensor->numel(); ++i) {
330 auto val = tensor->const_data_ptr<float>()[i];
331 EXPECT_GE(val, 0.0f);
332 EXPECT_LT(val, 1.0f);
333 }
334 }
335
TEST_F(TensorPtrMakerTest,CreateRandTensorWithIntType)336 TEST_F(TensorPtrMakerTest, CreateRandTensorWithIntType) {
337 auto tensor = rand({4, 5}, exec_aten::ScalarType::Int);
338
339 EXPECT_EQ(tensor->dim(), 2);
340 EXPECT_EQ(tensor->size(0), 4);
341 EXPECT_EQ(tensor->size(1), 5);
342 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Int);
343
344 for (auto i = 0; i < tensor->numel(); ++i) {
345 auto val = tensor->const_data_ptr<int32_t>()[i];
346 EXPECT_EQ(val, 0);
347 }
348 }
349
TEST_F(TensorPtrMakerTest,CreateRandTensorWithDoubleType)350 TEST_F(TensorPtrMakerTest, CreateRandTensorWithDoubleType) {
351 auto tensor = rand({4, 5}, exec_aten::ScalarType::Double);
352
353 EXPECT_EQ(tensor->dim(), 2);
354 EXPECT_EQ(tensor->size(0), 4);
355 EXPECT_EQ(tensor->size(1), 5);
356 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Double);
357
358 for (auto i = 0; i < tensor->numel(); ++i) {
359 auto val = tensor->const_data_ptr<double>()[i];
360 EXPECT_GE(val, 0.0);
361 EXPECT_LT(val, 1.0);
362 }
363 }
364
TEST_F(TensorPtrMakerTest,CreateRandnTensor)365 TEST_F(TensorPtrMakerTest, CreateRandnTensor) {
366 auto tensor = randn({100, 100});
367
368 EXPECT_EQ(tensor->dim(), 2);
369 EXPECT_EQ(tensor->size(0), 100);
370 EXPECT_EQ(tensor->size(1), 100);
371 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Float);
372
373 auto sum = 0.0f;
374 for (auto i = 0; i < tensor->numel(); ++i) {
375 sum += tensor->const_data_ptr<float>()[i];
376 }
377 const auto average = sum / tensor->numel();
378 EXPECT_NEAR(average, 0.0f, 1.0f);
379 }
380
TEST_F(TensorPtrMakerTest,CreateRandnTensorWithDoubleType)381 TEST_F(TensorPtrMakerTest, CreateRandnTensorWithDoubleType) {
382 auto tensor = randn({100, 100}, exec_aten::ScalarType::Double);
383
384 EXPECT_EQ(tensor->dim(), 2);
385 EXPECT_EQ(tensor->size(0), 100);
386 EXPECT_EQ(tensor->size(1), 100);
387 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Double);
388
389 auto sum = 0.0;
390 for (auto i = 0; i < tensor->numel(); ++i) {
391 sum += tensor->const_data_ptr<double>()[i];
392 }
393 const auto average = sum / tensor->numel();
394 EXPECT_NEAR(average, 0.0, 1.0);
395 }
396
TEST_F(TensorPtrMakerTest,CreateRandIntTensorWithIntType)397 TEST_F(TensorPtrMakerTest, CreateRandIntTensorWithIntType) {
398 auto tensor = randint(10, 20, {4, 5}, exec_aten::ScalarType::Int);
399
400 EXPECT_EQ(tensor->dim(), 2);
401 EXPECT_EQ(tensor->size(0), 4);
402 EXPECT_EQ(tensor->size(1), 5);
403 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Int);
404
405 for (auto i = 0; i < tensor->numel(); ++i) {
406 auto val = tensor->const_data_ptr<int32_t>()[i];
407 EXPECT_GE(val, 10);
408 EXPECT_LT(val, 20);
409 }
410 }
411
TEST_F(TensorPtrMakerTest,CreateRandIntTensorWithLongType)412 TEST_F(TensorPtrMakerTest, CreateRandIntTensorWithLongType) {
413 auto tensor = randint(10, 20, {4, 5}, exec_aten::ScalarType::Long);
414
415 EXPECT_EQ(tensor->dim(), 2);
416 EXPECT_EQ(tensor->size(0), 4);
417 EXPECT_EQ(tensor->size(1), 5);
418 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Long);
419
420 for (auto i = 0; i < tensor->numel(); ++i) {
421 auto val = tensor->const_data_ptr<int64_t>()[i];
422 EXPECT_GE(val, 10);
423 EXPECT_LT(val, 20);
424 }
425 }
426
TEST_F(TensorPtrMakerTest,CreateRandnTensorWithIntType)427 TEST_F(TensorPtrMakerTest, CreateRandnTensorWithIntType) {
428 auto tensor = rand({4, 5}, exec_aten::ScalarType::Int);
429
430 EXPECT_EQ(tensor->dim(), 2);
431 EXPECT_EQ(tensor->size(0), 4);
432 EXPECT_EQ(tensor->size(1), 5);
433 EXPECT_EQ(tensor->scalar_type(), exec_aten::ScalarType::Int);
434
435 for (auto i = 0; i < tensor->numel(); ++i) {
436 auto val = tensor->const_data_ptr<int32_t>()[i];
437 EXPECT_EQ(val, 0);
438 }
439 }
440