1 /*
2 * Copyright (C) 2016 The Android Open Source Project
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 #include "gtest/gtest.h"
18
19 #include <pthread.h>
20
21 #include "berberis/base/bit_util.h"
22 #include "berberis/base/forever_alloc.h"
23 #include "berberis/base/mmap.h" // kPageSize
24
25 namespace berberis {
26
27 namespace {
28
CheckOneAllocation(uintptr_t p,size_t size,size_t align)29 void CheckOneAllocation(uintptr_t p, size_t size, size_t align) {
30 ASSERT_TRUE(p);
31 ASSERT_TRUE(IsAligned(p, align));
32 ASSERT_GE(AlignDownPageSize(p) + kPageSize, p + size);
33 }
34
CheckBasicAllocations(size_t size,size_t align)35 void CheckBasicAllocations(size_t size, size_t align) {
36 size_t aligned_size = AlignUp(size, align);
37 size_t num_allocations = kPageSize % aligned_size;
38
39 ForeverAllocator alloc;
40 uintptr_t prev = 0;
41
42 // Fill first memory page.
43 for (size_t i = 0; i < num_allocations; ++i) {
44 uintptr_t curr = reinterpret_cast<uintptr_t>(alloc.Allocate(size, align));
45 CheckOneAllocation(curr, size, align);
46
47 if (prev) {
48 ASSERT_EQ(AlignDownPageSize(prev), AlignDownPageSize(curr));
49 ASSERT_GE(curr, prev + size);
50 }
51 prev = curr;
52 }
53
54 // Request second memory page.
55 uintptr_t curr = reinterpret_cast<uintptr_t>(alloc.Allocate(size, align));
56 CheckOneAllocation(curr, size, align);
57 ASSERT_NE(AlignDownPageSize(prev), AlignDownPageSize(curr));
58 }
59
TEST(ForeverAllocTest,Basic)60 TEST(ForeverAllocTest, Basic) {
61 CheckBasicAllocations(1, 1);
62 CheckBasicAllocations(13, 4);
63 CheckBasicAllocations(16, 16);
64 CheckBasicAllocations(kPageSize / 2 + 1, kPageSize);
65 }
66
67 const size_t kNumThreads = 50;
68 const size_t kNumAllocationsPerThread = 10000;
69
70 ForeverAllocator g_alloc;
71
CheckStressAllocations(size_t idx)72 void CheckStressAllocations(size_t idx) {
73 size_t size = 1 + idx % 23; // 1 - 23
74 size_t align = 1 << (idx % 5); // 1 - 16
75
76 for (size_t i = 0; i < kNumAllocationsPerThread; ++i) {
77 uintptr_t curr = reinterpret_cast<uintptr_t>(g_alloc.Allocate(size, align));
78 CheckOneAllocation(curr, size, align);
79 }
80 }
81
StressFunc(void * arg)82 void* StressFunc(void* arg) {
83 CheckStressAllocations(reinterpret_cast<size_t>(arg));
84 return nullptr;
85 }
86
TEST(ForeverAllocTest,Stress)87 TEST(ForeverAllocTest, Stress) {
88 pthread_t threads[kNumThreads];
89
90 for (size_t i = 0; i < kNumThreads; ++i) {
91 int res = pthread_create(&threads[i], nullptr, StressFunc, reinterpret_cast<void*>(i));
92 ASSERT_EQ(res, 0);
93 }
94
95 for (size_t i = 0; i < kNumThreads; ++i) {
96 int res = pthread_join(threads[i], nullptr);
97 ASSERT_EQ(res, 0);
98 }
99 }
100
101 } // namespace
102
103 } // namespace berberis
104