• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #define LOG_TAG "shared_memory_allocator_tests"
18 
19 #include <gtest/gtest.h>
20 #include <mediautils/SharedMemoryAllocator.h>
21 #include <sys/stat.h>
22 #include <utils/Log.h>
23 
24 using namespace android;
25 using namespace android::mediautils;
26 
27 namespace {
validate_block(const AllocationType & block)28 void validate_block(const AllocationType& block) {
29     ASSERT_TRUE(block != nullptr);
30     memset(block->unsecurePointer(), 10, 4096);
31     EXPECT_EQ(*(static_cast<char*>(block->unsecurePointer()) + 100), static_cast<char>(10));
32 }
33 
34 template <size_t N = 0, bool FatalOwn = true>
35 struct ValidateForwarding {
alignment__anond0d7275d0111::ValidateForwarding36     static constexpr size_t alignment() { return 1337; }
37 
owns__anond0d7275d0111::ValidateForwarding38     bool owns(const AllocationType& allocation) const {
39         if (allocation == owned) return true;
40         if constexpr (FatalOwn) {
41             LOG_ALWAYS_FATAL_IF(allocation != not_owned, "Invalid allocation passed to allocator");
42         }
43         return false;
44     }
45 
deallocate_all__anond0d7275d0111::ValidateForwarding46     void deallocate_all() { deallocate_all_count++; }
dump__anond0d7275d0111::ValidateForwarding47     std::string dump() const { return dump_string; }
48 
49     static inline size_t deallocate_all_count = 0;
50     static inline const AllocationType owned =
51             MemoryHeapBaseAllocator().allocate(BasicAllocRequest{4096});
52     static inline const AllocationType not_owned =
53             MemoryHeapBaseAllocator().allocate(BasicAllocRequest{4096});
54     static inline const std::string dump_string = std::to_string(N) + "Test Dump Forwarding";
55 };
56 
57 };  // namespace
58 static_assert(shared_allocator_impl::has_owns<MemoryHeapBaseAllocator> == false);
59 static_assert(shared_allocator_impl::has_dump<MemoryHeapBaseAllocator> == false);
60 static_assert(shared_allocator_impl::has_deallocate_all<MemoryHeapBaseAllocator> == false);
61 static_assert(shared_allocator_impl::has_owns<SnoopingAllocator<MemoryHeapBaseAllocator>> == true);
62 static_assert(shared_allocator_impl::has_dump<SnoopingAllocator<MemoryHeapBaseAllocator>> == true);
63 static_assert(
64         shared_allocator_impl::has_deallocate_all<SnoopingAllocator<MemoryHeapBaseAllocator>> ==
65         true);
66 static_assert(
67         shared_allocator_impl::has_owns<
68                 PolicyAllocator<SnoopingAllocator<MemoryHeapBaseAllocator>, SizePolicy<4096>>> ==
69         true);
70 static_assert(
71         shared_allocator_impl::has_dump<
72                 PolicyAllocator<SnoopingAllocator<MemoryHeapBaseAllocator>, SizePolicy<4096>>> ==
73         true);
74 static_assert(
75         shared_allocator_impl::has_deallocate_all<
76                 PolicyAllocator<SnoopingAllocator<MemoryHeapBaseAllocator>, SizePolicy<4096>>> ==
77         true);
78 static_assert(shared_allocator_impl::has_owns<
79                       FallbackAllocator<SnoopingAllocator<MemoryHeapBaseAllocator>,
80                                         SnoopingAllocator<MemoryHeapBaseAllocator>>> == true);
81 
TEST(shared_memory_allocator_tests,roundup)82 TEST(shared_memory_allocator_tests, roundup) {
83     using namespace shared_allocator_impl;
84     EXPECT_EQ(roundup(1023, 1024), 1024ul);
85     EXPECT_EQ(roundup(1024, 1024), 1024ul);
86     EXPECT_EQ(roundup(1025, 1024), 2048ul);
87     EXPECT_DEATH(roundup(1023, 1023), "");
88     EXPECT_DEATH(roundup(1023, 0), "");
89 }
90 
TEST(shared_memory_allocator_tests,mheapbase_allocator)91 TEST(shared_memory_allocator_tests, mheapbase_allocator) {
92     MemoryHeapBaseAllocator allocator;
93     const auto memory = allocator.allocate(BasicAllocRequest{500});
94     ASSERT_TRUE(memory != nullptr);
95     const auto fd = dup(memory->getMemory()->getHeapID());
96     EXPECT_EQ(memory->size(), static_cast<unsigned>(4096));
97     EXPECT_EQ(memory->size(), memory->getMemory()->getSize());
98     validate_block(memory);
99     allocator.deallocate(memory);
100     // Ensures we have closed the fd
101     EXPECT_EQ(memory->unsecurePointer(), nullptr);
102     EXPECT_EQ(memory->getMemory()->getBase(), nullptr);
103     struct stat st;
104     const auto err = fstat(fd, &st);
105     EXPECT_EQ(err, 0);
106     // Ensure we reclaim pages (overly-zealous)
107     EXPECT_EQ(st.st_size, 0);
108 }
109 
TEST(shared_memory_allocator_tests,mheapbase_allocator_independence)110 TEST(shared_memory_allocator_tests, mheapbase_allocator_independence) {
111     static_assert(MemoryHeapBaseAllocator::alignment() == 4096);
112     MemoryHeapBaseAllocator allocator;
113     const auto first_memory = allocator.allocate(BasicAllocRequest{500});
114     const auto second_memory = allocator.allocate(BasicAllocRequest{500});
115     ASSERT_TRUE(first_memory != nullptr && second_memory != nullptr);
116     EXPECT_NE(first_memory->getMemory()->getHeapID(), second_memory->getMemory()->getHeapID());
117     allocator.deallocate(first_memory);
118     validate_block(second_memory);
119     allocator.deallocate(second_memory);
120 }
121 
TEST(shared_memory_allocator_tests,snooping_allocator)122 TEST(shared_memory_allocator_tests, snooping_allocator) {
123     static_assert(SnoopingAllocator<ValidateForwarding<0>>::alignment() ==
124                   ValidateForwarding<0>::alignment());
125 
126     SnoopingAllocator<MemoryHeapBaseAllocator> allocator{"allocator"};
127     const auto first_memory = allocator.allocate(NamedAllocRequest{{500}, "allocate_1"});
128     auto second_memory = first_memory;
129     {
130         const auto tmp = allocator.allocate(NamedAllocRequest{{5000}, "allocate_2"});
131         // Test copying handle around
132         second_memory = tmp;
133     }
134     ASSERT_TRUE(first_memory && second_memory);
135     EXPECT_TRUE(allocator.owns(first_memory) && allocator.owns(second_memory));
136     const auto first_allocations = allocator.getAllocations();
137     EXPECT_EQ(first_allocations.size(), 2ull);
138     for (const auto& [key, val] : allocator.getAllocations()) {
139         if (val.allocation_number == 0) {
140             EXPECT_EQ(val.name, "allocate_1");
141             EXPECT_TRUE(first_memory == key);
142         }
143         if (val.allocation_number == 1) {
144             EXPECT_EQ(val.name, "allocate_2");
145             EXPECT_TRUE(second_memory == key);
146         }
147     }
148     // TODO test dump and deallocate forwarding
149     // EXPECT_EQ(allocator.dump(), std::string{});
150     validate_block(second_memory);
151     allocator.deallocate(second_memory);
152     EXPECT_EQ(second_memory->unsecurePointer(), nullptr);
153     EXPECT_FALSE(allocator.owns(second_memory));
154     EXPECT_TRUE(allocator.owns(first_memory));
155     const auto second_allocations = allocator.getAllocations();
156     EXPECT_EQ(second_allocations.size(), 1ul);
157     for (const auto& [key, val] : second_allocations) {
158         EXPECT_EQ(val.name, "allocate_1");
159         EXPECT_TRUE(first_memory == key);
160     }
161     // EXPECT_EQ(allocator.dump(), std::string{});
162     // TODO test deallocate_all O(1)
163 }
164 
165 // TODO generic policy test
TEST(shared_memory_allocator_tests,size_policy_allocator_enforcement)166 TEST(shared_memory_allocator_tests, size_policy_allocator_enforcement) {
167     PolicyAllocator allocator{MemoryHeapBaseAllocator{},
168                               SizePolicy<4096 * 7, 4096 * 2, 4096 * 4>{}};
169     // Violate max size
170     EXPECT_TRUE(allocator.allocate(BasicAllocRequest{4096 * 5}) == nullptr);
171     // Violate min alloc size
172     EXPECT_TRUE(allocator.allocate(BasicAllocRequest{4096}) == nullptr);
173     const auto first_memory = allocator.allocate(BasicAllocRequest{4096 * 4});
174     validate_block(first_memory);
175     // Violate pool size
176     EXPECT_TRUE(allocator.allocate(BasicAllocRequest{4096 * 4}) == nullptr);
177     const auto second_memory = allocator.allocate(BasicAllocRequest{4096 * 3});
178     validate_block(second_memory);
179     allocator.deallocate(second_memory);
180     // Check pool size update after deallocation
181     const auto new_second_memory = allocator.allocate(BasicAllocRequest{4096 * 2});
182     validate_block(new_second_memory);
183 }
184 
TEST(shared_memory_allocator_tests,indirect_allocator)185 TEST(shared_memory_allocator_tests, indirect_allocator) {
186     static_assert(IndirectAllocator<ValidateForwarding<0>>::alignment() ==
187                   ValidateForwarding<0>::alignment());
188     const auto allocator_handle = std::make_shared<SnoopingAllocator<MemoryHeapBaseAllocator>>();
189     IndirectAllocator allocator{allocator_handle};
190     const auto memory = allocator.allocate(NamedAllocRequest{{4096}, "allocation"});
191     EXPECT_TRUE(allocator_handle->owns(memory));
192     EXPECT_TRUE(allocator_handle->getAllocations().size() == 1);
193     allocator.deallocate(memory);
194     EXPECT_FALSE(allocator_handle->owns(memory));
195     EXPECT_TRUE(allocator_handle->getAllocations().size() == 0);
196 }
197 
TEST(shared_memory_allocator_tests,policy_allocator_forwarding)198 TEST(shared_memory_allocator_tests, policy_allocator_forwarding) {
199     // Test appropriate forwarding of allocator, deallocate
200     const auto primary_allocator =
201             std::make_shared<SnoopingAllocator<MemoryHeapBaseAllocator>>("allocator");
202     PolicyAllocator allocator{IndirectAllocator(primary_allocator), SizePolicy<4096>{}};
203     const auto memory = allocator.allocate(NamedAllocRequest{{4096}, "allocation"});
204     EXPECT_TRUE(primary_allocator->owns(memory));
205     const auto& allocations = primary_allocator->getAllocations();
206     EXPECT_TRUE(allocations.size() == 1);
207     allocator.deallocate(memory);
208     EXPECT_TRUE(allocations.size() == 0);
209     const auto memory2 = allocator.allocate(NamedAllocRequest{{4096}, "allocation_2"});
210     EXPECT_TRUE(allocations.size() == 1);
211     EXPECT_TRUE(primary_allocator->owns(memory2));
212     allocator.deallocate(memory2);
213     EXPECT_FALSE(primary_allocator->owns(memory2));
214     EXPECT_TRUE(allocations.size() == 0);
215     // Test appropriate forwarding of own, dump, alignment, deallocate_all
216     PolicyAllocator allocator2{ValidateForwarding<0>{}, SizePolicy<4096>{}};
217     EXPECT_TRUE(allocator2.owns(ValidateForwarding<0>::owned));
218     EXPECT_FALSE(allocator2.owns(ValidateForwarding<0>::not_owned));
219     EXPECT_TRUE(allocator2.dump().find(ValidateForwarding<0>::dump_string) != std::string::npos);
220     static_assert(decltype(allocator2)::alignment() == ValidateForwarding<0>::alignment());
221     size_t prev = ValidateForwarding<0>::deallocate_all_count;
222     allocator2.deallocate_all();
223     EXPECT_EQ(ValidateForwarding<0>::deallocate_all_count, prev + 1);
224 }
225 
TEST(shared_memory_allocator_tests,snooping_allocator_nullptr)226 TEST(shared_memory_allocator_tests, snooping_allocator_nullptr) {
227     SnoopingAllocator allocator{PolicyAllocator{MemoryHeapBaseAllocator{}, SizePolicy<4096 * 2>{}}};
228     const auto memory = allocator.allocate(NamedAllocRequest{{3000}, "allocation_1"});
229     validate_block(memory);
230     ASSERT_TRUE(allocator.allocate(NamedAllocRequest{{5000}, "allocation_2"}) == nullptr);
231     const auto& allocations = allocator.getAllocations();
232     EXPECT_EQ(allocations.size(), 1ul);
233     for (const auto& [key, val] : allocations) {
234         EXPECT_EQ(val.name, "allocation_1");
235         EXPECT_EQ(val.allocation_number, 0ul);
236         EXPECT_TRUE(key == memory);
237     }
238 }
239 
TEST(shared_memory_allocator_tests,fallback_allocator)240 TEST(shared_memory_allocator_tests, fallback_allocator) {
241     // Construct Fallback Allocator
242     const auto primary_allocator = std::make_shared<
243             SnoopingAllocator<PolicyAllocator<MemoryHeapBaseAllocator, SizePolicy<4096>>>>(
244             PolicyAllocator<MemoryHeapBaseAllocator, SizePolicy<4096>>{}, "primary_allocator");
245     const auto secondary_allocator =
246             std::make_shared<SnoopingAllocator<MemoryHeapBaseAllocator>>("secondary_allocator");
247 
248     FallbackAllocator fallback_allocator{SnoopingAllocator{IndirectAllocator{primary_allocator}},
249                                          SnoopingAllocator{IndirectAllocator{secondary_allocator}}};
250     static_assert(decltype(fallback_allocator)::alignment() == 4096);
251     // Basic Allocation Test
252     const auto memory = fallback_allocator.allocate(NamedAllocRequest{{3000}, "allocation_1"});
253     validate_block(memory);
254     // Correct allocator selected
255     EXPECT_TRUE(fallback_allocator.owns(memory));
256     EXPECT_TRUE(primary_allocator->owns(memory));
257     EXPECT_FALSE(secondary_allocator->owns(memory));
258     // Test fallback allocation
259     const auto memory2 = fallback_allocator.allocate(NamedAllocRequest{{3000}, "allocation_2"});
260     validate_block(memory2);
261     // Correct allocator selected
262     EXPECT_TRUE(fallback_allocator.owns(memory2));
263     EXPECT_FALSE(primary_allocator->owns(memory2));
264     EXPECT_TRUE(secondary_allocator->owns(memory2));
265     // Allocations ended up in the correct allocators
266     const auto& primary_allocations = primary_allocator->getAllocations();
267     EXPECT_TRUE(primary_allocations.size() == 1ul);
268     ASSERT_TRUE(primary_allocations.find(memory) != primary_allocations.end());
269     EXPECT_EQ(primary_allocations.find(memory)->second.name, std::string{"allocation_1"});
270     const auto& secondary_allocations = secondary_allocator->getAllocations();
271     EXPECT_TRUE(secondary_allocations.size() == 1ul);
272     ASSERT_TRUE(secondary_allocations.find(memory2) != secondary_allocations.end());
273     EXPECT_EQ(secondary_allocations.find(memory2)->second.name, std::string{"allocation_2"});
274     // Test deallocate appropriate forwarding
275     fallback_allocator.deallocate(memory);
276     EXPECT_TRUE(primary_allocator->getAllocations().size() == 0ul);
277     EXPECT_TRUE(secondary_allocator->getAllocations().size() == 1ul);
278     // Appropriate fallback after deallocation
279     const auto memory3 = fallback_allocator.allocate(NamedAllocRequest{{3000}, "allocation_3"});
280     EXPECT_TRUE(fallback_allocator.owns(memory3));
281     EXPECT_TRUE(primary_allocator->owns(memory3));
282     EXPECT_FALSE(secondary_allocator->owns(memory3));
283     EXPECT_TRUE(primary_allocator->getAllocations().size() == 1ul);
284     // Test deallocate appropriate forwarding
285     EXPECT_TRUE(secondary_allocator->getAllocations().size() == 1ul);
286     fallback_allocator.deallocate(memory2);
287     EXPECT_TRUE(secondary_allocator->getAllocations().size() == 0ul);
288     const auto memory4 = fallback_allocator.allocate(NamedAllocRequest{{3000}, "allocation_4"});
289     EXPECT_TRUE(fallback_allocator.owns(memory4));
290     EXPECT_FALSE(primary_allocator->owns(memory4));
291     EXPECT_TRUE(secondary_allocator->owns(memory4));
292     // Allocations ended up in the correct allocators
293     EXPECT_TRUE(primary_allocator->getAllocations().size() == 1ul);
294     EXPECT_TRUE(secondary_allocator->getAllocations().size() == 1ul);
295     ASSERT_TRUE(primary_allocations.find(memory3) != primary_allocations.end());
296     EXPECT_EQ(primary_allocations.find(memory3)->second.name, std::string{"allocation_3"});
297     ASSERT_TRUE(secondary_allocations.find(memory4) != secondary_allocations.end());
298     EXPECT_EQ(secondary_allocations.find(memory4)->second.name, std::string{"allocation_4"});
299 }
300 
TEST(shared_memory_allocator_tests,fallback_allocator_forwarding)301 TEST(shared_memory_allocator_tests, fallback_allocator_forwarding) {
302     // Test forwarding
303     using Alloc1 = ValidateForwarding<0, false>;
304     using Alloc2 = ValidateForwarding<1, false>;
305     FallbackAllocator forward_test{Alloc1{}, Alloc2{}};
306     EXPECT_TRUE(forward_test.dump().find(Alloc1::dump_string) != std::string::npos);
307     EXPECT_TRUE(forward_test.dump().find(Alloc2::dump_string) != std::string::npos);
308     // Test owned forwarding
309     EXPECT_TRUE(forward_test.owns(Alloc1::owned));
310     EXPECT_TRUE(forward_test.owns(Alloc2::owned));
311     EXPECT_FALSE(forward_test.owns(Alloc1::not_owned));
312     EXPECT_FALSE(forward_test.owns(Alloc2::not_owned));
313     // Test alignment forwarding
314     static_assert(FallbackAllocator<Alloc1, Alloc2>::alignment() == Alloc1::alignment());
315     // Test deallocate_all forwarding
316     size_t prev1 = Alloc1::deallocate_all_count;
317     size_t prev2 = Alloc2::deallocate_all_count;
318     forward_test.deallocate_all();
319     EXPECT_EQ(prev1 + 1, Alloc1::deallocate_all_count);
320     EXPECT_EQ(prev2 + 1, Alloc2::deallocate_all_count);
321 }
322 
TEST(shared_memory_allocator_tests,scoped_allocator)323 TEST(shared_memory_allocator_tests, scoped_allocator) {
324     const auto underlying_allocator =
325             std::make_shared<SnoopingAllocator<MemoryHeapBaseAllocator>>("Allocator");
326     ScopedAllocator allocator{underlying_allocator};
327     const auto& allocations = underlying_allocator->getAllocations();
328     {
329         decltype(allocator.allocate(NamedAllocRequest{})) copy;
330         {
331             EXPECT_EQ(allocations.size(), 0ul);
332             const auto memory = allocator.allocate(NamedAllocRequest{{3000}, "allocation_1"});
333             copy = memory;
334             EXPECT_EQ(allocations.size(), 1ul);
335             EXPECT_TRUE(allocator.owns(copy));
336             EXPECT_TRUE(allocator.owns(memory));
337         }
338         EXPECT_TRUE(allocator.owns(copy));
339         EXPECT_EQ(allocations.size(), 1ul);
340         for (const auto& [key, value] : allocations) {
341             EXPECT_EQ(value.name, std::string{"allocation_1"});
342         }
343     }
344     EXPECT_EQ(allocations.size(), 0ul);
345     // Test forwarding
346     static_assert(ScopedAllocator<ValidateForwarding<0>>::alignment() ==
347                   ValidateForwarding<0>::alignment());
348     ScopedAllocator<ValidateForwarding<0>> forwarding{};
349     EXPECT_EQ(forwarding.dump(), ValidateForwarding<0>::dump_string);
350 }
351