xref: /aosp_15_r20/trusty/kernel/app/memorytest/memorytest.c (revision 344aa361028b423587d4ef3fa52a23d194628137)
1*344aa361SAndroid Build Coastguard Worker #include <err.h>
2*344aa361SAndroid Build Coastguard Worker #include <kernel/thread.h>
3*344aa361SAndroid Build Coastguard Worker #include <lib/unittest/unittest.h>
4*344aa361SAndroid Build Coastguard Worker #include <malloc.h>
5*344aa361SAndroid Build Coastguard Worker #include <stdatomic.h>
6*344aa361SAndroid Build Coastguard Worker 
expected_malloc_alignment(size_t size)7*344aa361SAndroid Build Coastguard Worker static uintptr_t expected_malloc_alignment(size_t size) {
8*344aa361SAndroid Build Coastguard Worker     /* TODO use ffs? */
9*344aa361SAndroid Build Coastguard Worker     if (size >= 16) {
10*344aa361SAndroid Build Coastguard Worker         return sizeof(void*) * 2;
11*344aa361SAndroid Build Coastguard Worker     } else if (size >= 8) {
12*344aa361SAndroid Build Coastguard Worker         return 8;
13*344aa361SAndroid Build Coastguard Worker     } else if (size >= 4) {
14*344aa361SAndroid Build Coastguard Worker         return 4;
15*344aa361SAndroid Build Coastguard Worker     } else if (size >= 2) {
16*344aa361SAndroid Build Coastguard Worker         return 2;
17*344aa361SAndroid Build Coastguard Worker     } else {
18*344aa361SAndroid Build Coastguard Worker         return 1;
19*344aa361SAndroid Build Coastguard Worker     }
20*344aa361SAndroid Build Coastguard Worker }
21*344aa361SAndroid Build Coastguard Worker 
TEST(memorytest,malloc_alignment)22*344aa361SAndroid Build Coastguard Worker TEST(memorytest, malloc_alignment) {
23*344aa361SAndroid Build Coastguard Worker     for (int size = 2; size < 256; size++) {
24*344aa361SAndroid Build Coastguard Worker         const uintptr_t alignment_mask = expected_malloc_alignment(size) - 1;
25*344aa361SAndroid Build Coastguard Worker         void* ptr1 = malloc(size);
26*344aa361SAndroid Build Coastguard Worker         void* ptr2 = malloc(size / 2); /* Try to shake up the alignment. */
27*344aa361SAndroid Build Coastguard Worker         void* ptr3 = malloc(size);
28*344aa361SAndroid Build Coastguard Worker 
29*344aa361SAndroid Build Coastguard Worker         ASSERT_EQ(0, (uintptr_t)ptr1 & alignment_mask, "size %d / align %ld\n",
30*344aa361SAndroid Build Coastguard Worker                   size, alignment_mask + 1);
31*344aa361SAndroid Build Coastguard Worker         ASSERT_EQ(0, (uintptr_t)ptr3 & alignment_mask, "size %d / align %ld\n",
32*344aa361SAndroid Build Coastguard Worker                   size, alignment_mask + 1);
33*344aa361SAndroid Build Coastguard Worker 
34*344aa361SAndroid Build Coastguard Worker         free(ptr3);
35*344aa361SAndroid Build Coastguard Worker         free(ptr2);
36*344aa361SAndroid Build Coastguard Worker         free(ptr1);
37*344aa361SAndroid Build Coastguard Worker     }
38*344aa361SAndroid Build Coastguard Worker test_abort:;
39*344aa361SAndroid Build Coastguard Worker }
40*344aa361SAndroid Build Coastguard Worker 
41*344aa361SAndroid Build Coastguard Worker #define MEMORYTEST_CONCURRENT_ALLOCATION_THREADS 64
42*344aa361SAndroid Build Coastguard Worker 
43*344aa361SAndroid Build Coastguard Worker struct memorytest_alloc_thread_arg {
44*344aa361SAndroid Build Coastguard Worker     size_t alloc_size;
45*344aa361SAndroid Build Coastguard Worker     int count;
46*344aa361SAndroid Build Coastguard Worker     atomic_int threads_done;
47*344aa361SAndroid Build Coastguard Worker     atomic_int chunks_allocated;
48*344aa361SAndroid Build Coastguard Worker     atomic_bool go;
49*344aa361SAndroid Build Coastguard Worker };
50*344aa361SAndroid Build Coastguard Worker 
memorytest_alloc_thread(void * _arg)51*344aa361SAndroid Build Coastguard Worker int memorytest_alloc_thread(void* _arg) {
52*344aa361SAndroid Build Coastguard Worker     struct memorytest_alloc_thread_arg* arg = _arg;
53*344aa361SAndroid Build Coastguard Worker     void** ptrs;
54*344aa361SAndroid Build Coastguard Worker     int i;
55*344aa361SAndroid Build Coastguard Worker     int ret;
56*344aa361SAndroid Build Coastguard Worker 
57*344aa361SAndroid Build Coastguard Worker     ptrs = calloc(arg->count, sizeof(*ptrs));
58*344aa361SAndroid Build Coastguard Worker     if (!ptrs) {
59*344aa361SAndroid Build Coastguard Worker         return ERR_NO_MEMORY;
60*344aa361SAndroid Build Coastguard Worker     }
61*344aa361SAndroid Build Coastguard Worker 
62*344aa361SAndroid Build Coastguard Worker     /* Busy-wait until control thread says go. */
63*344aa361SAndroid Build Coastguard Worker     while (!atomic_load(&arg->go)) {
64*344aa361SAndroid Build Coastguard Worker     }
65*344aa361SAndroid Build Coastguard Worker 
66*344aa361SAndroid Build Coastguard Worker     for (i = 0; i < arg->count; i++) {
67*344aa361SAndroid Build Coastguard Worker         ptrs[i] = malloc(arg->alloc_size);
68*344aa361SAndroid Build Coastguard Worker         if (!ptrs[i]) {
69*344aa361SAndroid Build Coastguard Worker             ret = ERR_NO_MEMORY;
70*344aa361SAndroid Build Coastguard Worker             goto err_malloc;
71*344aa361SAndroid Build Coastguard Worker         }
72*344aa361SAndroid Build Coastguard Worker         atomic_fetch_add(&arg->chunks_allocated, 1);
73*344aa361SAndroid Build Coastguard Worker     }
74*344aa361SAndroid Build Coastguard Worker     ret = 0;
75*344aa361SAndroid Build Coastguard Worker 
76*344aa361SAndroid Build Coastguard Worker err_malloc:
77*344aa361SAndroid Build Coastguard Worker     atomic_fetch_add(&arg->threads_done, 1);
78*344aa361SAndroid Build Coastguard Worker     while (atomic_load(&arg->threads_done) !=
79*344aa361SAndroid Build Coastguard Worker            MEMORYTEST_CONCURRENT_ALLOCATION_THREADS) {
80*344aa361SAndroid Build Coastguard Worker         thread_sleep(10);
81*344aa361SAndroid Build Coastguard Worker     }
82*344aa361SAndroid Build Coastguard Worker 
83*344aa361SAndroid Build Coastguard Worker     while (i-- > 0) {
84*344aa361SAndroid Build Coastguard Worker         free(ptrs[i]);
85*344aa361SAndroid Build Coastguard Worker     }
86*344aa361SAndroid Build Coastguard Worker     free(ptrs);
87*344aa361SAndroid Build Coastguard Worker     return ret;
88*344aa361SAndroid Build Coastguard Worker }
89*344aa361SAndroid Build Coastguard Worker 
TEST(memorytest,concurrent_allocation)90*344aa361SAndroid Build Coastguard Worker TEST(memorytest, concurrent_allocation) {
91*344aa361SAndroid Build Coastguard Worker     /*
92*344aa361SAndroid Build Coastguard Worker      * Test concurrent allocation by creating many threads. If this test is
93*344aa361SAndroid Build Coastguard Worker      * as the first test after boot, it will test the behavior while growing
94*344aa361SAndroid Build Coastguard Worker      * the heap. Assuming the heap implemention never shrinks the heap,
95*344aa361SAndroid Build Coastguard Worker      * additional test runs will not exercise this path.
96*344aa361SAndroid Build Coastguard Worker      */
97*344aa361SAndroid Build Coastguard Worker     struct memorytest_alloc_thread_arg thread_arg = {
98*344aa361SAndroid Build Coastguard Worker             .alloc_size = PAGE_SIZE / 4 * 3, /* ~1 page after heap overhead */
99*344aa361SAndroid Build Coastguard Worker             .count = 8,
100*344aa361SAndroid Build Coastguard Worker             .threads_done = 0,
101*344aa361SAndroid Build Coastguard Worker             .chunks_allocated = 0,
102*344aa361SAndroid Build Coastguard Worker             .go = false,
103*344aa361SAndroid Build Coastguard Worker     };
104*344aa361SAndroid Build Coastguard Worker     struct thread* thread[MEMORYTEST_CONCURRENT_ALLOCATION_THREADS];
105*344aa361SAndroid Build Coastguard Worker     for (size_t i = 0; i < countof(thread); i++) {
106*344aa361SAndroid Build Coastguard Worker         thread[i] = thread_create("memorytest", memorytest_alloc_thread,
107*344aa361SAndroid Build Coastguard Worker                                   &thread_arg, HIGH_PRIORITY - 1,
108*344aa361SAndroid Build Coastguard Worker                                   DEFAULT_STACK_SIZE);
109*344aa361SAndroid Build Coastguard Worker         ASSERT_NE(0, thread[i]);
110*344aa361SAndroid Build Coastguard Worker     }
111*344aa361SAndroid Build Coastguard Worker     for (size_t i = 0; i < countof(thread); i++) {
112*344aa361SAndroid Build Coastguard Worker         ASSERT_EQ(0, thread_resume(thread[i]));
113*344aa361SAndroid Build Coastguard Worker     }
114*344aa361SAndroid Build Coastguard Worker 
115*344aa361SAndroid Build Coastguard Worker     /* Wait for test threads to start and migrate to other cpus */
116*344aa361SAndroid Build Coastguard Worker     thread_sleep(100);
117*344aa361SAndroid Build Coastguard Worker     atomic_store(&thread_arg.go, true);
118*344aa361SAndroid Build Coastguard Worker 
119*344aa361SAndroid Build Coastguard Worker     for (size_t i = 0; i < countof(thread); i++) {
120*344aa361SAndroid Build Coastguard Worker         int retcode;
121*344aa361SAndroid Build Coastguard Worker         ASSERT_EQ(0, thread_join(thread[i], &retcode, INFINITE_TIME));
122*344aa361SAndroid Build Coastguard Worker         EXPECT_EQ(0, retcode, "Chunks allocated: %d\n",
123*344aa361SAndroid Build Coastguard Worker                   atomic_load(&thread_arg.chunks_allocated));
124*344aa361SAndroid Build Coastguard Worker     }
125*344aa361SAndroid Build Coastguard Worker test_abort:;
126*344aa361SAndroid Build Coastguard Worker }
127*344aa361SAndroid Build Coastguard Worker 
128*344aa361SAndroid Build Coastguard Worker PORT_TEST(memorytest, "com.android.kernel.memorytest");
129