1 /*
2  * Copyright (C) 2015 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 "berberis/base/arena_alloc.h"
20 #include "berberis/base/arena_list.h"
21 #include "berberis/base/arena_vector.h"
22 #include "berberis/base/mmap.h"
23 
24 namespace berberis {
25 
26 class ArenaTest : public ::testing::Test {
27  public:
28   ArenaTest() = default;
29 
ArenaMappedSize()30   size_t ArenaMappedSize() {
31     size_t size = 0;
32     auto* block = arena_.blocks_;
33     while (block) {
34       size += block->size;
35       block = block->next;
36     }
37     return size;
38   }
39 
BigMapSize(size_t requested_size,size_t align)40   size_t BigMapSize(size_t requested_size, size_t align) {
41     return AlignUpPageSize(AlignUp(sizeof(arena_internal::ArenaBlock), align) + requested_size);
42   }
43 
44  protected:
45   static constexpr size_t kBlockSize = arena_internal::kDefaultArenaBlockSize;
46   static constexpr size_t kReallyBigSize = 8 * kBlockSize;
47   Arena arena_;
48 };
49 
50 namespace {
51 
52 struct Node {
53   unsigned elem1;
54   unsigned elem2;
55 
Nodeberberis::__anonad649b4e0111::Node56   explicit Node(unsigned e) : elem1(e), elem2(e + 11) {}
57 };
58 
59 using FastList = ArenaList<Node*>;
60 using FastVector = ArenaVector<Node*>;
61 
TEST_F(ArenaTest,Smoke)62 TEST_F(ArenaTest, Smoke) {
63   char* p;
64 
65   p = static_cast<char*>(arena_.Alloc(1, 1));
66   ASSERT_NE(p, nullptr);
67   p[0] = 'a';
68   ASSERT_EQ(ArenaMappedSize(), kBlockSize);
69 
70   p = static_cast<char*>(arena_.Alloc(100, 2));
71   ASSERT_NE(p, nullptr);
72   p[99] = 'b';
73   ASSERT_EQ(ArenaMappedSize(), kBlockSize);
74 
75   p = static_cast<char*>(arena_.Alloc(kBlockSize / 10, 4));
76   ASSERT_NE(p, nullptr);
77   p[kBlockSize / 10 - 1] = 'c';
78   ASSERT_EQ(ArenaMappedSize(), kBlockSize);
79 
80   p = static_cast<char*>(arena_.Alloc(kReallyBigSize, 4));
81   ASSERT_NE(p, nullptr);
82   p[kReallyBigSize - 1] = 'z';
83   ASSERT_EQ(ArenaMappedSize(), kBlockSize + BigMapSize(kReallyBigSize, 4));
84 }
85 
TEST_F(ArenaTest,Alloc)86 TEST_F(ArenaTest, Alloc) {
87   size_t requested_size = 0;
88   for (int i = 0; i < 4; ++i) {
89     for (size_t n = 1; n < 2 * kReallyBigSize; n *= 2) {
90       requested_size += n;
91       char* p = static_cast<char*>(arena_.Alloc(n, 1));
92       p[0] = 'a';
93       p[n - 1] = 'z';
94     }
95   }
96   ASSERT_GE(ArenaMappedSize(), requested_size);
97 }
98 
TEST_F(ArenaTest,List)99 TEST_F(ArenaTest, List) {
100   FastList list(&arena_);
101 
102   list.push_back(NewInArena<Node>(&arena_, 1));
103   list.push_back(NewInArena<Node>(&arena_, 2));
104 
105   ASSERT_EQ(2u, list.size());
106   ASSERT_EQ(1u + 11, (*list.begin())->elem2);
107   ASSERT_EQ(2u, (*--list.end())->elem1);
108   ASSERT_EQ(ArenaMappedSize(), kBlockSize);
109 }
110 
TEST_F(ArenaTest,Vector)111 TEST_F(ArenaTest, Vector) {
112   constexpr size_t kElems = 40000;
113   FastVector vector(kElems, nullptr, &arena_);
114 
115   for (size_t i = 0; i < kElems; i++) {
116     vector[i] = NewInArena<Node>(&arena_, i);
117   }
118 
119   ASSERT_EQ(kElems, vector.size());
120   ASSERT_EQ(0u, (*vector.begin())->elem1);
121   ASSERT_EQ(kElems - 1, vector[kElems - 1]->elem1);
122   ASSERT_GE(ArenaMappedSize(), kElems * sizeof(Node));
123 }
124 
125 }  // namespace
126 
127 }  // namespace berberis
128