• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <gtest/gtest.h>
16 
17 #include "common/Math.h"
18 #include "common/SlabAllocator.h"
19 
20 namespace {
21 
22     struct Foo : public PlacementAllocated {
Foo__anona2923b940111::Foo23         Foo(int value) : value(value) {
24         }
25 
26         int value;
27     };
28 
29     struct alignas(256) AlignedFoo : public Foo {
30         using Foo::Foo;
31     };
32 
33 }  // namespace
34 
35 // Test that a slab allocator of a single object works.
TEST(SlabAllocatorTests,Single)36 TEST(SlabAllocatorTests, Single) {
37     SlabAllocator<Foo> allocator(1 * sizeof(Foo));
38 
39     Foo* obj = allocator.Allocate(4);
40     EXPECT_EQ(obj->value, 4);
41 
42     allocator.Deallocate(obj);
43 }
44 
45 // Allocate multiple objects and check their data is correct.
TEST(SlabAllocatorTests,AllocateSequential)46 TEST(SlabAllocatorTests, AllocateSequential) {
47     // Check small alignment
48     {
49         SlabAllocator<Foo> allocator(5 * sizeof(Foo));
50 
51         std::vector<Foo*> objects;
52         for (int i = 0; i < 10; ++i) {
53             auto* ptr = allocator.Allocate(i);
54             EXPECT_TRUE(std::find(objects.begin(), objects.end(), ptr) == objects.end());
55             objects.push_back(ptr);
56         }
57 
58         for (int i = 0; i < 10; ++i) {
59             // Check that the value is correct and hasn't been trampled.
60             EXPECT_EQ(objects[i]->value, i);
61 
62             // Check that the alignment is correct.
63             EXPECT_TRUE(IsPtrAligned(objects[i], alignof(Foo)));
64         }
65 
66         // Deallocate all of the objects.
67         for (Foo* object : objects) {
68             allocator.Deallocate(object);
69         }
70     }
71 
72     // Check large alignment
73     {
74         SlabAllocator<AlignedFoo> allocator(9 * sizeof(AlignedFoo));
75 
76         std::vector<AlignedFoo*> objects;
77         for (int i = 0; i < 21; ++i) {
78             auto* ptr = allocator.Allocate(i);
79             EXPECT_TRUE(std::find(objects.begin(), objects.end(), ptr) == objects.end());
80             objects.push_back(ptr);
81         }
82 
83         for (int i = 0; i < 21; ++i) {
84             // Check that the value is correct and hasn't been trampled.
85             EXPECT_EQ(objects[i]->value, i);
86 
87             // Check that the alignment is correct.
88             EXPECT_TRUE(IsPtrAligned(objects[i], 256));
89         }
90 
91         // Deallocate all of the objects.
92         for (AlignedFoo* object : objects) {
93             allocator.Deallocate(object);
94         }
95     }
96 }
97 
98 // Test that when reallocating a number of objects <= pool size, all memory is reused.
TEST(SlabAllocatorTests,ReusesFreedMemory)99 TEST(SlabAllocatorTests, ReusesFreedMemory) {
100     SlabAllocator<Foo> allocator(17 * sizeof(Foo));
101 
102     // Allocate a number of objects.
103     std::set<Foo*> objects;
104     for (int i = 0; i < 17; ++i) {
105         EXPECT_TRUE(objects.insert(allocator.Allocate(i)).second);
106     }
107 
108     // Deallocate all of the objects.
109     for (Foo* object : objects) {
110         allocator.Deallocate(object);
111     }
112 
113     std::set<Foo*> reallocatedObjects;
114     // Allocate objects again. All of the pointers should be the same.
115     for (int i = 0; i < 17; ++i) {
116         Foo* ptr = allocator.Allocate(i);
117         EXPECT_TRUE(reallocatedObjects.insert(ptr).second);
118         EXPECT_TRUE(std::find(objects.begin(), objects.end(), ptr) != objects.end());
119     }
120 
121     // Deallocate all of the objects.
122     for (Foo* object : objects) {
123         allocator.Deallocate(object);
124     }
125 }
126 
127 // Test many allocations and deallocations. Meant to catch corner cases with partially
128 // empty slabs.
TEST(SlabAllocatorTests,AllocateDeallocateMany)129 TEST(SlabAllocatorTests, AllocateDeallocateMany) {
130     SlabAllocator<Foo> allocator(17 * sizeof(Foo));
131 
132     std::set<Foo*> objects;
133     std::set<Foo*> set3;
134     std::set<Foo*> set7;
135 
136     // Allocate many objects.
137     for (uint32_t i = 0; i < 800; ++i) {
138         Foo* object = allocator.Allocate(i);
139         EXPECT_TRUE(objects.insert(object).second);
140 
141         if (i % 3 == 0) {
142             set3.insert(object);
143         } else if (i % 7 == 0) {
144             set7.insert(object);
145         }
146     }
147 
148     // Deallocate every 3rd object.
149     for (Foo* object : set3) {
150         allocator.Deallocate(object);
151         objects.erase(object);
152     }
153 
154     // Allocate many more objects
155     for (uint32_t i = 0; i < 800; ++i) {
156         Foo* object = allocator.Allocate(i);
157         EXPECT_TRUE(objects.insert(object).second);
158 
159         if (i % 7 == 0) {
160             set7.insert(object);
161         }
162     }
163 
164     // Deallocate every 7th object from the first and second rounds of allocation.
165     for (Foo* object : set7) {
166         allocator.Deallocate(object);
167         objects.erase(object);
168     }
169 
170     // Allocate objects again
171     for (uint32_t i = 0; i < 800; ++i) {
172         Foo* object = allocator.Allocate(i);
173         EXPECT_TRUE(objects.insert(object).second);
174     }
175 
176     // Deallocate the rest of the objects
177     for (Foo* object : objects) {
178         allocator.Deallocate(object);
179     }
180 }
181