You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
291 lines
7.9 KiB
291 lines
7.9 KiB
// Copyright (C) 2018 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
#include "base/SubAllocator.h"
|
|
|
|
#include "base/ArraySize.h"
|
|
#include "base/MemStream.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <random>
|
|
#include <string>
|
|
|
|
namespace android {
|
|
namespace base {
|
|
|
|
// Test: can allocate/free memory of various sizes,
|
|
// and if the allocation reasonably cannot be satisfied,
|
|
// the allocation fails.
|
|
TEST(SubAllocator, Basic) {
|
|
const size_t pageSizesToTest[] = {
|
|
1, 2, 4, 8, 16, 32, 64, 128,
|
|
256, 512, 1024, 2048, 4096,
|
|
8192, 16384, 32768, 65536,
|
|
};
|
|
|
|
const size_t sizesToTest[] = {
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
11, 12, 13, 14, 15, 16, 32, 33, 64, 65,
|
|
127, 129, 1023, 1024,
|
|
2047, 2048, 2049,
|
|
4096, 16384, 65535
|
|
};
|
|
|
|
const size_t allocCounts[] = {
|
|
1, 2, 3, 4,
|
|
};
|
|
|
|
const size_t bufferSize = 65536;
|
|
|
|
std::vector<uint8_t> buffer(bufferSize);
|
|
|
|
for (size_t pageSize : pageSizesToTest) {
|
|
SubAllocator subAlloc(
|
|
buffer.data(),
|
|
(uint64_t)bufferSize,
|
|
pageSize);
|
|
EXPECT_TRUE(subAlloc.empty());
|
|
|
|
for (size_t allocCount : allocCounts) {
|
|
std::vector<void*> ptrs;
|
|
|
|
for (size_t allocSize : sizesToTest) {
|
|
|
|
size_t trySize = allocSize / allocCount;
|
|
|
|
size_t atomSize =
|
|
pageSize *
|
|
((trySize + pageSize - 1) / pageSize);
|
|
|
|
size_t total = 0;
|
|
|
|
for (size_t i = 0; i < allocCount; ++i) {
|
|
|
|
void* ptr = subAlloc.alloc(trySize);
|
|
|
|
if (ptr) {
|
|
total += atomSize;
|
|
} else {
|
|
EXPECT_TRUE(
|
|
(trySize == 0) ||
|
|
(total + atomSize > bufferSize)) <<
|
|
"pageSize " << pageSize <<
|
|
"allocCount " << allocCount <<
|
|
"trySize " << trySize <<
|
|
"try# " << i <<
|
|
"allocedSoFar " << total;
|
|
}
|
|
|
|
ptrs.push_back(ptr);
|
|
}
|
|
|
|
for (auto ptr : ptrs) {
|
|
subAlloc.free(ptr);
|
|
}
|
|
EXPECT_TRUE(subAlloc.empty());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test: freeAll resets the state and allows more allocation
|
|
// without individual freeing.
|
|
TEST(SubAllocator, FreeAll) {
|
|
const size_t pageSize = 64;
|
|
const size_t bufferSize = 65536;
|
|
|
|
std::vector<uint8_t> buffer(bufferSize);
|
|
|
|
SubAllocator subAlloc(
|
|
buffer.data(),
|
|
(uint64_t)bufferSize,
|
|
(uint64_t)pageSize);
|
|
|
|
const size_t fillCount = bufferSize / pageSize;
|
|
const size_t numTrials = 10;
|
|
|
|
for (size_t i = 0; i < numTrials; ++i) {
|
|
for (size_t j = 0; j < fillCount; ++j) {
|
|
void* ptr = subAlloc.alloc(pageSize);
|
|
EXPECT_NE(nullptr, ptr);
|
|
}
|
|
subAlloc.freeAll();
|
|
EXPECT_TRUE(subAlloc.empty());
|
|
}
|
|
}
|
|
|
|
// Test: Random testing
|
|
TEST(SubAllocator, Random) {
|
|
// Given the buffer size, any combination of
|
|
// page size, alloc size, and count should work
|
|
// over a single run.
|
|
const size_t pageSizesToTest[] = {
|
|
1, 2, 4, 8, 16, 32, 64, 128,
|
|
256, 512, 1024, 2048, 4096,
|
|
};
|
|
|
|
const size_t sizesToTest[] = {
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
11, 12, 13, 14, 15, 16, 32, 33, 64, 65,
|
|
127, 129, 1023, 1024,
|
|
2047, 2048, 2049,
|
|
4096,
|
|
};
|
|
|
|
const size_t allocCounts[] = {
|
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
};
|
|
|
|
const size_t numSizes = arraySize(sizesToTest);
|
|
const size_t numCounts = arraySize(allocCounts);
|
|
|
|
const size_t bufferSize = 65536;
|
|
std::vector<uint8_t> buffer(bufferSize);
|
|
|
|
const size_t numTrials = 1000;
|
|
|
|
std::default_random_engine generator;
|
|
generator.seed(0);
|
|
|
|
std::uniform_int_distribution<int> sizeDistribution(0, numSizes - 1);
|
|
std::uniform_int_distribution<int> countDistribution(0, numCounts - 1);
|
|
|
|
for (auto pageSize : pageSizesToTest) {
|
|
SubAllocator subAlloc(
|
|
buffer.data(),
|
|
(uint64_t)bufferSize,
|
|
pageSize);
|
|
|
|
for (size_t i = 0; i < numTrials; ++i) {
|
|
size_t count =
|
|
allocCounts[countDistribution(generator)];
|
|
|
|
std::vector<void*> ptrs;
|
|
|
|
size_t total = 0;
|
|
|
|
for (size_t j = 0; j < count; ++j) {
|
|
size_t allocSize =
|
|
sizesToTest[sizeDistribution(generator)];
|
|
void* ptr = subAlloc.alloc(allocSize);
|
|
|
|
if (ptr) {
|
|
total += allocSize;
|
|
}
|
|
|
|
ptrs.push_back(ptr);
|
|
EXPECT_NE(nullptr, ptr) <<
|
|
"pageSize " << pageSize <<
|
|
"runCount " << count <<
|
|
"alloc# " << j <<
|
|
"size " << allocSize <<
|
|
"total " << total;
|
|
}
|
|
|
|
for (auto ptr : ptrs) {
|
|
subAlloc.free(ptr);
|
|
}
|
|
EXPECT_TRUE(subAlloc.empty());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Test save/load of suballocator snapshot
|
|
TEST(SubAllocator, Snapshot) {
|
|
MemStream snapshotStream;
|
|
std::vector<uint8_t*> storage(4096, 0);
|
|
|
|
SubAllocator subAlloc(
|
|
storage.data(), (uint64_t)storage.size(), 8);
|
|
|
|
const size_t numBufs = 6;
|
|
|
|
// Alloc/free a few things.
|
|
|
|
uint8_t* bufs[numBufs] = {
|
|
(uint8_t*)subAlloc.alloc(16),
|
|
(uint8_t*)subAlloc.alloc(8),
|
|
(uint8_t*)subAlloc.alloc(32),
|
|
(uint8_t*)subAlloc.alloc(64),
|
|
(uint8_t*)subAlloc.alloc(8),
|
|
(uint8_t*)subAlloc.alloc(128),
|
|
};
|
|
|
|
subAlloc.free(bufs[3]);
|
|
bufs[3] = (uint8_t*)subAlloc.alloc(24);
|
|
subAlloc.free(bufs[4]);
|
|
bufs[4] = (uint8_t*)subAlloc.alloc(64);
|
|
subAlloc.free(bufs[0]);
|
|
bufs[0] = (uint8_t*)subAlloc.alloc(8);
|
|
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
EXPECT_NE(nullptr, bufs[i]);
|
|
}
|
|
|
|
// Record offsets
|
|
|
|
uint64_t offs[numBufs];
|
|
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
offs[i] = subAlloc.getOffset(bufs[i]);
|
|
}
|
|
|
|
// Write special values
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
*(bufs[i]) = (uint8_t)i;
|
|
}
|
|
|
|
// Save/load the snapshot
|
|
subAlloc.save(&snapshotStream);
|
|
subAlloc.load(&snapshotStream);
|
|
EXPECT_FALSE(subAlloc.empty());
|
|
|
|
// Set the post load buffer to our original one
|
|
EXPECT_TRUE(subAlloc.postLoad(storage.data()));
|
|
|
|
// Do some allocations. None should intersect with any
|
|
// previously allocated buffer.
|
|
for (uint32_t i = 0; i < 10; ++i) {
|
|
uint8_t* buf = (uint8_t*)subAlloc.alloc(8);
|
|
if (!buf) continue;
|
|
for (uint32_t j = 0; j < numBufs; ++j) {
|
|
EXPECT_NE(bufs[j], buf);
|
|
}
|
|
}
|
|
|
|
// Expect all data to remain unchanged
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
EXPECT_EQ((uint8_t)i, *(bufs[i]));
|
|
}
|
|
|
|
// Expect all offsets to be the same
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
EXPECT_EQ(offs[i], subAlloc.getOffset(bufs[i]));
|
|
}
|
|
|
|
// Freeing everything should still work
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
EXPECT_TRUE(subAlloc.free(bufs[i]));
|
|
}
|
|
|
|
// Allocate all buffers again
|
|
for (uint32_t i = 0; i < numBufs; ++i) {
|
|
bufs[i] = (uint8_t*)subAlloc.alloc(8);
|
|
EXPECT_NE(nullptr, bufs[i]);
|
|
}
|
|
}
|
|
|
|
} // namespace base
|
|
} // namespace android
|