[dali_2.3.42] Merge branch 'devel/master'
[platform/core/uifw/dali-core.git] / automated-tests / src / dali-internal / utc-Dali-Internal-FixedSizeMemoryPool.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <dali-test-suite-utils.h>
19 #include <dali/public-api/dali-core.h>
20
21 // Internal headers are allowed here
22 #include <dali/internal/common/fixed-size-memory-pool.h>
23
24 using namespace Dali;
25
26 void utc_dali_internal_fixedsizememorypool_startup(void)
27 {
28   test_return_value = TET_UNDEF;
29 }
30
31 void utc_dali_internal_fixedsizememorypool_cleanup(void)
32 {
33   test_return_value = TET_PASS;
34 }
35
36 namespace
37 {
38 unsigned int gTestObjectConstructed = 0;
39 unsigned int gTestObjectDestructed  = 0;
40 unsigned int gTestObjectMethod      = 0;
41 unsigned int gTestObjectDataAccess  = 0;
42
43 class TestObject
44 {
45 public:
46   TestObject()
47   : mData1(0),
48     mData2(false)
49   {
50     gTestObjectConstructed++;
51   }
52
53   ~TestObject()
54   {
55     gTestObjectDestructed++;
56   }
57
58   void Method()
59   {
60     gTestObjectMethod++;
61   }
62
63   void DataAccess()
64   {
65     mData1++;
66     mData2 = true;
67
68     gTestObjectDataAccess++;
69   }
70
71 private:
72   unsigned int mData1;
73   bool         mData2;
74 };
75
76 } // namespace
77
78 int UtcDaliFixedSizeMemoryPoolCreate(void)
79 {
80   gTestObjectConstructed = 0;
81   gTestObjectDestructed  = 0;
82   gTestObjectMethod      = 0;
83   gTestObjectDataAccess  = 0;
84
85   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size);
86
87   TestObject* testObject1 = new(memoryPool.Allocate()) TestObject();
88   DALI_TEST_CHECK(testObject1);
89   DALI_TEST_EQUALS(gTestObjectConstructed, 1U, TEST_LOCATION);
90
91   testObject1->Method();
92   DALI_TEST_EQUALS(gTestObjectMethod, 1U, TEST_LOCATION);
93
94   testObject1->DataAccess();
95   DALI_TEST_EQUALS(gTestObjectDataAccess, 1U, TEST_LOCATION);
96
97   testObject1->~TestObject();
98   memoryPool.Free(testObject1);
99   DALI_TEST_EQUALS(gTestObjectDestructed, 1U, TEST_LOCATION);
100
101   END_TEST;
102 }
103
104 int UtcDaliFixedSizeMemoryPoolStressTest01(void)
105 {
106   gTestObjectConstructed = 0;
107   gTestObjectDestructed  = 0;
108   gTestObjectMethod      = 0;
109   gTestObjectDataAccess  = 0;
110
111   const size_t       initialCapacity = 32;
112   const unsigned int numObjects      = 7 * 1024 * 1024;
113
114   // Don't specify key layout
115   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity /*, default max cap(1M) */);
116
117   Dali::Vector<TestObject*> objects;
118   objects.Reserve(numObjects);
119
120   for(unsigned int i = 0; i < numObjects; ++i)
121   {
122     TestObject* testObject = new(memoryPool.Allocate()) TestObject();
123     DALI_TEST_CHECK(testObject);
124
125     objects.PushBack(testObject);
126
127     uint32_t key = memoryPool.GetKeyFromPtr(testObject);
128     DALI_TEST_EQUALS(key, i, TEST_LOCATION);
129     void* ptr = memoryPool.GetPtrFromKey(key);
130     DALI_TEST_EQUALS(static_cast<void*>(testObject), ptr, TEST_LOCATION);
131   }
132
133   DALI_TEST_EQUALS(gTestObjectConstructed, numObjects, TEST_LOCATION);
134
135   for(unsigned int i = 0; i < numObjects; ++i)
136   {
137     objects[i]->~TestObject();
138     memoryPool.Free(objects[i]);
139   }
140
141   DALI_TEST_EQUALS(gTestObjectDestructed, numObjects, TEST_LOCATION);
142
143   END_TEST;
144 }
145
146 int UtcDaliFixedSizeMemoryPoolStressTest02(void)
147 {
148   gTestObjectConstructed = 0;
149   gTestObjectDestructed  = 0;
150   gTestObjectMethod      = 0;
151   gTestObjectDataAccess  = 0;
152
153   const size_t       initialCapacity = 32;
154   const unsigned int numObjects      = 7 * 1024 * 1024;
155
156   // Maxing the number of blocks and providing key layout.
157   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, 4194304, 27);
158
159   Dali::Vector<TestObject*> objects;
160   objects.Reserve(numObjects);
161
162   uint32_t     blockSizes[]       = {32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304};
163   unsigned int curBlock           = 0;
164   unsigned int curBlockStartIndex = 0;
165   for(unsigned int i = 0; i < numObjects; ++i)
166   {
167     TestObject* testObject = new(memoryPool.Allocate()) TestObject();
168     DALI_TEST_CHECK(testObject);
169
170     objects.PushBack(testObject);
171
172     if(i == curBlockStartIndex + blockSizes[curBlock])
173     {
174       curBlockStartIndex += blockSizes[curBlock++];
175       tet_printf("Next Block [%d] size %d\n", curBlock, blockSizes[curBlock]);
176       tet_printf("  StartIdx [%d]\n", curBlockStartIndex);
177     }
178     uint32_t key = memoryPool.GetKeyFromPtr(testObject);
179     DALI_TEST_EQUALS((key & 0xf8000000) >> 27, curBlock, TEST_LOCATION);
180     DALI_TEST_EQUALS((key & 0x07ffffff), i - curBlockStartIndex, TEST_LOCATION);
181     void* ptr = memoryPool.GetPtrFromKey(key);
182     DALI_TEST_EQUALS(static_cast<void*>(testObject), ptr, TEST_LOCATION);
183   }
184
185   DALI_TEST_EQUALS(gTestObjectConstructed, numObjects, TEST_LOCATION);
186
187   for(unsigned int i = 0; i < numObjects; ++i)
188   {
189     objects[i]->~TestObject();
190     memoryPool.Free(objects[i]);
191   }
192
193   DALI_TEST_EQUALS(gTestObjectDestructed, numObjects, TEST_LOCATION);
194
195   END_TEST;
196 }
197
198 int UtcDaliFixedSizeMemoryPoolStressTest03(void)
199 {
200   gTestObjectConstructed = 0;
201   gTestObjectDestructed  = 0;
202   gTestObjectMethod      = 0;
203   gTestObjectDataAccess  = 0;
204
205   const size_t initialCapacity = 32;
206   const size_t maximumCapacity = 1024; // @todo smaller max cap means higher number of blocks, and bit width should change accordingly.
207
208   const unsigned int numObjects = 1024 * 1024;
209
210   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, maximumCapacity);
211
212   Dali::Vector<TestObject*> objects;
213   objects.Reserve(numObjects);
214
215   for(unsigned int i = 0; i < numObjects; ++i)
216   {
217     TestObject* testObject = new(memoryPool.Allocate()) TestObject();
218     DALI_TEST_CHECK(testObject);
219
220     uint32_t key = memoryPool.GetKeyFromPtr(testObject);
221     DALI_TEST_EQUALS(key, i, TEST_LOCATION);
222     DALI_TEST_EQUALS((void*)testObject, (void*)memoryPool.GetPtrFromKey(i), TEST_LOCATION);
223     objects.PushBack(testObject);
224   }
225
226   DALI_TEST_EQUALS(gTestObjectConstructed, numObjects, TEST_LOCATION);
227
228   for(unsigned int i = 0; i < numObjects; ++i)
229   {
230     objects[i]->~TestObject();
231     memoryPool.Free(objects[i]);
232   }
233
234   DALI_TEST_EQUALS(gTestObjectDestructed, numObjects, TEST_LOCATION);
235
236   END_TEST;
237 }
238
239 int UtcDaliFixedSizeMemoryPoolPtrFromKeyP01(void)
240 {
241   gTestObjectConstructed = 0;
242   gTestObjectDestructed  = 0;
243   gTestObjectMethod      = 0;
244   gTestObjectDataAccess  = 0;
245
246   const size_t       initialCapacity = 32;
247   const unsigned int numObjects      = 1024;
248
249   // Maxing the number of blocks and providing key layout.
250   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, 4194304, 27);
251
252   Dali::Vector<TestObject*> objects;
253   objects.Reserve(numObjects);
254
255   uint32_t     blockSizes[]       = {32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304};
256   unsigned int curBlock           = 0;
257   unsigned int curBlockStartIndex = 0;
258   for(unsigned int i = 0; i < numObjects; ++i)
259   {
260     TestObject* testObject = new(memoryPool.Allocate()) TestObject();
261     DALI_TEST_CHECK(testObject);
262
263     objects.PushBack(testObject);
264
265     if(i == curBlockStartIndex + blockSizes[curBlock])
266     {
267       curBlockStartIndex += blockSizes[curBlock++];
268       tet_printf("Next Block [%d] size %d\n", curBlock, blockSizes[curBlock]);
269       tet_printf("  StartIdx [%d]\n", curBlockStartIndex);
270     }
271     uint32_t key = memoryPool.GetKeyFromPtr(testObject);
272     DALI_TEST_EQUALS((key & 0xf8000000) >> 27, curBlock, TEST_LOCATION);
273     DALI_TEST_EQUALS((key & 0x07ffffff), i - curBlockStartIndex, TEST_LOCATION);
274     void* ptr = memoryPool.GetPtrFromKey(key);
275     DALI_TEST_EQUALS(static_cast<void*>(testObject), ptr, TEST_LOCATION);
276   }
277
278   DALI_TEST_EQUALS(gTestObjectConstructed, numObjects, TEST_LOCATION);
279   END_TEST;
280 }
281
282 int UtcDaliFixedSizeMemoryPoolKeyFromPtrN01(void)
283 {
284   gTestObjectConstructed = 0;
285   gTestObjectDestructed  = 0;
286   gTestObjectMethod      = 0;
287   gTestObjectDataAccess  = 0;
288
289   const size_t       initialCapacity = 32;
290   const unsigned int numObjects      = 1024;
291
292   // Maxing the number of blocks and providing key layout.
293   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, 4194304, 27);
294
295   Dali::Vector<TestObject*> objects;
296   objects.Reserve(numObjects);
297
298   TestObject* testObject = nullptr;
299   for(unsigned int i = 0; i < numObjects; ++i)
300   {
301     testObject = new(memoryPool.Allocate()) TestObject();
302     objects.PushBack(testObject);
303   }
304
305   uint32_t key = memoryPool.GetKeyFromPtr(nullptr);
306   DALI_TEST_EQUALS(key, (uint32_t)-1, TEST_LOCATION);
307
308   testObject += 1500; // Ensure it's outside block
309   key = memoryPool.GetKeyFromPtr(testObject);
310   DALI_TEST_EQUALS(key, (uint32_t)-1, TEST_LOCATION);
311
312   END_TEST;
313 }
314
315 int UtcDaliFixedSizeMemoryPoolPtrFromKeyN01(void)
316 {
317   gTestObjectConstructed = 0;
318   gTestObjectDestructed  = 0;
319   gTestObjectMethod      = 0;
320   gTestObjectDataAccess  = 0;
321
322   const size_t       initialCapacity = 32;
323   const unsigned int numObjects      = 1024;
324
325   // Maxing the number of blocks and providing key layout.
326   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, 4194304, 27);
327
328   Dali::Vector<TestObject*> objects;
329   objects.Reserve(numObjects);
330
331   TestObject* testObject = nullptr;
332   for(unsigned int i = 0; i < numObjects; ++i)
333   {
334     testObject = new(memoryPool.Allocate()) TestObject();
335     objects.PushBack(testObject);
336   }
337
338   void* object = memoryPool.GetPtrFromKey((uint32_t)-1);
339   DALI_TEST_CHECK(object == nullptr);
340
341   uint32_t key = (8 << 27) | 33; // Index 33 in block 8 should be out of range
342
343   object = memoryPool.GetPtrFromKey(key);
344   DALI_TEST_CHECK(object == nullptr);
345
346   END_TEST;
347 }
348
349 int UtcDaliFixedSizeMemoryPoolKeyFromPtrP02(void)
350 {
351   gTestObjectConstructed = 0;
352   gTestObjectDestructed  = 0;
353   gTestObjectMethod      = 0;
354   gTestObjectDataAccess  = 0;
355
356   const size_t       initialCapacity = 32;
357   const size_t       maximumCapacity = 1024;
358   const unsigned int numObjects      = 1024;
359
360   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, maximumCapacity, 0xffffffff /*No block limit*/);
361
362   Dali::Vector<TestObject*> objects;
363   objects.Reserve(numObjects);
364
365   TestObject* testObject;
366   TestObject* firstObject;
367
368   for(unsigned int i = 0; i < numObjects; ++i)
369   {
370     testObject = new(memoryPool.Allocate()) TestObject();
371     if(i == 0)
372     {
373       firstObject = testObject;
374     }
375
376     objects.PushBack(testObject);
377   }
378
379   uint32_t key = memoryPool.GetKeyFromPtr(testObject);
380   // Check key == index with no block id
381   DALI_TEST_EQUALS(key, 1023, TEST_LOCATION);
382
383   key = memoryPool.GetKeyFromPtr(firstObject);
384   // Check key == index with no block id
385   DALI_TEST_EQUALS(key, 0, TEST_LOCATION);
386
387   END_TEST;
388 }
389
390 int UtcDaliFixedSizeMemoryPoolKeyFromPtrN02(void)
391 {
392   gTestObjectConstructed = 0;
393   gTestObjectDestructed  = 0;
394   gTestObjectMethod      = 0;
395   gTestObjectDataAccess  = 0;
396
397   const size_t       initialCapacity = 32;
398   const size_t       maximumCapacity = 512;
399   const unsigned int numObjects      = 1024;
400
401   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, maximumCapacity, 0xffffffff /*No block limit*/);
402
403   Dali::Vector<TestObject*> objects;
404   objects.Reserve(numObjects);
405
406   TestObject* testObject;
407   TestObject* firstObject;
408
409   for(unsigned int i = 0; i < numObjects; ++i)
410   {
411     testObject = new(memoryPool.Allocate()) TestObject();
412     if(i == 0)
413     {
414       firstObject = testObject;
415     }
416
417     objects.PushBack(testObject);
418   }
419
420   firstObject--;
421   uint32_t key = memoryPool.GetKeyFromPtr(firstObject);
422   DALI_TEST_EQUALS(key, (uint32_t)-1, TEST_LOCATION);
423
424   testObject += 1024; // Ensure it's outside the block
425   key = memoryPool.GetKeyFromPtr(testObject);
426   DALI_TEST_EQUALS(key, (uint32_t)-1, TEST_LOCATION);
427
428   key = memoryPool.GetKeyFromPtr(nullptr);
429   DALI_TEST_EQUALS(key, (uint32_t)-1, TEST_LOCATION);
430
431   END_TEST;
432 }
433
434 int UtcDaliFixedSizeMemoryPoolPtrFromKeyP02(void)
435 {
436   gTestObjectConstructed = 0;
437   gTestObjectDestructed  = 0;
438   gTestObjectMethod      = 0;
439   gTestObjectDataAccess  = 0;
440
441   const size_t       initialCapacity = 32;
442   const size_t       maximumCapacity = 1024;
443   const unsigned int numObjects      = 1024;
444
445   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, maximumCapacity, 0xffffffff /*No block limit*/);
446
447   Dali::Vector<TestObject*> objects;
448   objects.Reserve(numObjects);
449
450   TestObject* testObject;
451   TestObject* firstObject;
452
453   for(unsigned int i = 0; i < numObjects; ++i)
454   {
455     testObject = new(memoryPool.Allocate()) TestObject();
456     if(i == 0)
457     {
458       firstObject = testObject;
459     }
460
461     objects.PushBack(testObject);
462   }
463
464   void* ptr = memoryPool.GetPtrFromKey(0);
465   DALI_TEST_EQUALS(ptr, (void*)firstObject, TEST_LOCATION);
466
467   ptr = memoryPool.GetPtrFromKey(1023);
468   DALI_TEST_EQUALS(ptr, (void*)(testObject), TEST_LOCATION);
469
470   END_TEST;
471 }
472
473 int UtcDaliFixedSizeMemoryPoolPtrFromKeyN02(void)
474 {
475   tet_infoline("Negative Test of PtrFromKey in a memory pool with unlimited blocks");
476
477   gTestObjectConstructed = 0;
478   gTestObjectDestructed  = 0;
479   gTestObjectMethod      = 0;
480   gTestObjectDataAccess  = 0;
481
482   const size_t       initialCapacity = 32;
483   const size_t       maximumCapacity = 1024;
484   const unsigned int numObjects      = 1024;
485
486   Internal::FixedSizeMemoryPool memoryPool(Internal::TypeSizeWithAlignment<TestObject>::size, initialCapacity, maximumCapacity, 0xffffffff /*No block limit*/);
487
488   Dali::Vector<TestObject*> objects;
489   objects.Reserve(numObjects);
490
491   TestObject* testObject;
492
493   // There is always 1 block allocated, so testing indices in this range won't fail
494   void* ptr = memoryPool.GetPtrFromKey(33);
495   DALI_TEST_CHECK(ptr == nullptr);
496
497   for(unsigned int i = 0; i < numObjects; ++i)
498   {
499     testObject = new(memoryPool.Allocate()) TestObject();
500     objects.PushBack(testObject);
501   }
502
503   ptr = memoryPool.GetPtrFromKey(1024);
504   DALI_TEST_CHECK(ptr != nullptr); // this key successfully finds a block, even though
505                                    // it's not been alloc'd.
506
507   ptr = memoryPool.GetPtrFromKey(204029); // Check a key outside the allocd range.
508   DALI_TEST_CHECK(ptr == nullptr);
509
510   END_TEST;
511 }