mirror of
https://github.com/intel/compute-runtime.git
synced 2026-01-04 15:53:45 +08:00
feature: New allocators for opaque arrays
Adds fast allocators for opaque objects of uniform size. Related-To: NEO-13406 Signed-off-by: Chodor, Jaroslaw <jaroslaw.chodor@intel.com>
This commit is contained in:
committed by
Compute-Runtime-Automation
parent
1a2666d4e2
commit
0bff9def3b
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2023 Intel Corporation
|
||||
* Copyright (C) 2018-2025 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
@@ -92,3 +92,20 @@ TEST(ptrDiff, WhenGettingPtrDiffThen64BitIsPreserved) {
|
||||
auto ptrBefore3 = ptrDiff(ptrAfter, 0x1234ull);
|
||||
EXPECT_EQ(0x800000000ull, ptrBefore3);
|
||||
}
|
||||
|
||||
TEST(ByteRangeContains, WhenInRangeThenReturnTrue) {
|
||||
char stack[3] = {};
|
||||
EXPECT_TRUE(byteRangeContains(stack, 3, &stack[0]));
|
||||
EXPECT_TRUE(byteRangeContains(stack, 3, &stack[1]));
|
||||
EXPECT_TRUE(byteRangeContains(stack, 3, &stack[2]));
|
||||
}
|
||||
|
||||
TEST(ByteRangeContains, WhenNotInRangeThenReturnFalse) {
|
||||
char stack[3] = {};
|
||||
std::vector<char> heap(3, 0);
|
||||
EXPECT_FALSE(byteRangeContains(stack + 1, 1, &stack[2]));
|
||||
EXPECT_FALSE(byteRangeContains(stack + 1, 1, &stack[0]));
|
||||
EXPECT_FALSE(byteRangeContains(stack, 3, &heap[0]));
|
||||
EXPECT_FALSE(byteRangeContains(stack, 3, &heap[1]));
|
||||
EXPECT_FALSE(byteRangeContains(stack, 3, &heap[2]));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "shared/source/utilities/arrayref.h"
|
||||
#include "shared/source/utilities/bitcontainers.h"
|
||||
#include "shared/source/utilities/idlist.h"
|
||||
#include "shared/source/utilities/iflist.h"
|
||||
#include "shared/source/utilities/lookup_array.h"
|
||||
@@ -15,9 +16,11 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
@@ -1654,13 +1657,13 @@ TEST(StackVec, WhenCallingDataThenVectorDataIsReturned) {
|
||||
char dataB[] = {5, 4, 3, 2, 1};
|
||||
|
||||
StackVec<char, 1> stackVecA{dataA, dataA + sizeof(dataA)};
|
||||
StackVec<char, 5> stackVecB{dataB, dataB + sizeof(dataB)};
|
||||
const StackVec<char, 5> stackVecB{dataB, dataB + sizeof(dataB)};
|
||||
|
||||
EXPECT_TRUE(stackVecA.usesDynamicMem());
|
||||
EXPECT_FALSE(stackVecB.usesDynamicMem());
|
||||
|
||||
auto stackVecAData = reinterpret_cast<char *>(stackVecA.data());
|
||||
auto stackVecBData = reinterpret_cast<char *>(stackVecB.data());
|
||||
auto stackVecAData = stackVecA.data();
|
||||
auto stackVecBData = stackVecB.data();
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
EXPECT_EQ(dataA[i], stackVecAData[i]);
|
||||
EXPECT_EQ(dataB[i], stackVecBData[i]);
|
||||
@@ -1728,6 +1731,44 @@ TEST(StackVec, whenPushingUniqueToRootDeviceIndicesContainerThenOnlyUniqueValues
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StackVec, WhenInsertingAtGivenPositionThenOrderIsMaintained) {
|
||||
{
|
||||
StackVec<int, 10> tested;
|
||||
tested.insert(tested.end(), 12);
|
||||
|
||||
StackVec<int, 10> expected{12};
|
||||
EXPECT_EQ(expected, tested);
|
||||
}
|
||||
{
|
||||
StackVec<int, 10> tested{3, 5, 7, 11};
|
||||
tested.insert(tested.end(), 12);
|
||||
tested.insert(tested.begin(), 2);
|
||||
tested.insert(tested.begin() + 2, 4);
|
||||
|
||||
StackVec<int, 10> expected{2, 3, 4, 5, 7, 11, 12};
|
||||
EXPECT_EQ(expected, tested);
|
||||
}
|
||||
{
|
||||
StackVec<int, 1> testedB{3};
|
||||
testedB.insert(testedB.begin(), 2);
|
||||
StackVec<int, 1> testedE{2};
|
||||
testedE.insert(testedE.end(), 3);
|
||||
|
||||
StackVec<int, 10> expected{2, 3};
|
||||
EXPECT_EQ(expected, testedB);
|
||||
EXPECT_EQ(expected, testedE);
|
||||
}
|
||||
{
|
||||
StackVec<int, 4> tested{3, 5, 7, 11};
|
||||
tested.insert(tested.end(), 12);
|
||||
tested.insert(tested.begin(), 2);
|
||||
tested.insert(tested.begin() + 2, 4);
|
||||
|
||||
StackVec<int, 10> expected{2, 3, 4, 5, 7, 11, 12};
|
||||
EXPECT_EQ(expected, tested);
|
||||
}
|
||||
}
|
||||
|
||||
int sum(ArrayRef<int> a) {
|
||||
int sum = 0;
|
||||
for (auto v : a) {
|
||||
@@ -1968,4 +2009,204 @@ TEST(LookupArrayLookUpGreaterEqual, WhenLookingForElementThenReturnFirstThatIsEq
|
||||
EXPECT_EQ(90, res);
|
||||
|
||||
EXPECT_THROW(res = arr.lookUpGreaterEqual(10), std::exception);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BitArray, WhenFfzIsCalledThenReturnsFirstZeroBitOrMinusAllBitAreSet) {
|
||||
{
|
||||
BitArray ba{3};
|
||||
ASSERT_EQ(3U, ba.length());
|
||||
auto pos = ba.ffz();
|
||||
EXPECT_EQ(0, pos);
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(0, pos);
|
||||
ba[0] = true;
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(1, pos);
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(1, pos);
|
||||
ba[1] = true;
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(2, pos);
|
||||
ba[2] = true;
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(-1, pos);
|
||||
}
|
||||
{
|
||||
BitArray ba{64};
|
||||
ASSERT_EQ(64U, ba.length());
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
ba[i] = true;
|
||||
}
|
||||
auto pos = ba.ffz();
|
||||
EXPECT_EQ(-1, pos);
|
||||
}
|
||||
{
|
||||
BitArray ba{4097};
|
||||
ASSERT_EQ(4097U, ba.length());
|
||||
for (int i = 0; i < 4095; ++i) {
|
||||
ba[i] = true;
|
||||
}
|
||||
auto pos = ba.ffz();
|
||||
EXPECT_EQ(4095, pos);
|
||||
ba[4095] = true;
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(4096, pos);
|
||||
ba[4096] = true;
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(-1, pos);
|
||||
|
||||
ba[796] = false;
|
||||
pos = ba.ffz();
|
||||
EXPECT_EQ(796, pos);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BitAllocator, WhenAllocateIsCalledThenAllocatesAndReturnsFirstFreeBitPositionOrMinusOneIfEmpty) {
|
||||
{
|
||||
BitAllocator ba{3};
|
||||
ASSERT_EQ(3U, ba.sizeInBits());
|
||||
auto pos = ba.allocate();
|
||||
EXPECT_EQ(0, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(1, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(2, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(-1, pos);
|
||||
|
||||
ba.free(1);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(1, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(-1, pos);
|
||||
|
||||
ba.free(0);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(0, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(-1, pos);
|
||||
}
|
||||
{
|
||||
BitAllocator ba{64};
|
||||
ASSERT_EQ(64U, ba.sizeInBits());
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
EXPECT_EQ(i, ba.allocate());
|
||||
}
|
||||
auto pos = ba.allocate();
|
||||
EXPECT_EQ(-1, pos);
|
||||
}
|
||||
{
|
||||
BitAllocator ba{4097};
|
||||
ASSERT_EQ(4097U, ba.sizeInBits());
|
||||
for (int i = 0; i < 4095; ++i) {
|
||||
EXPECT_EQ(i, ba.allocate());
|
||||
}
|
||||
auto pos = ba.allocate();
|
||||
EXPECT_EQ(4095, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(4096, pos);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(-1, pos);
|
||||
|
||||
ba.free(796);
|
||||
pos = ba.allocate();
|
||||
EXPECT_EQ(796, pos);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OpaqueArray, WhenAllocateIsCalledThenAllocatesAndReturnsFirstFreeElementOrNullIfEmpty) {
|
||||
struct GraphicsAllocationHandleExample {
|
||||
} handle;
|
||||
double underlyingMemory[5] = {1, 2, 3, 4, 5};
|
||||
const size_t elementStride = 2 * sizeof(double);
|
||||
{
|
||||
OpaqueArrayElementAllocator<GraphicsAllocationHandleExample *> oa{&handle, underlyingMemory, elementStride, sizeof(underlyingMemory) / elementStride};
|
||||
EXPECT_EQ(underlyingMemory, oa.base());
|
||||
EXPECT_EQ(&handle, oa.handle());
|
||||
|
||||
EXPECT_TRUE(oa.contains(underlyingMemory));
|
||||
EXPECT_TRUE(oa.contains(underlyingMemory + 1));
|
||||
EXPECT_TRUE(oa.contains(underlyingMemory + 2));
|
||||
EXPECT_TRUE(oa.contains(underlyingMemory + 3));
|
||||
EXPECT_FALSE(oa.contains(underlyingMemory + 4));
|
||||
|
||||
auto el0 = oa.allocate();
|
||||
EXPECT_EQ(underlyingMemory, el0);
|
||||
EXPECT_EQ(el0, oa.element(0));
|
||||
|
||||
auto el1 = oa.allocate();
|
||||
EXPECT_EQ(underlyingMemory + 2, el1);
|
||||
EXPECT_EQ(el1, oa.element(1));
|
||||
|
||||
auto el2 = oa.allocate();
|
||||
EXPECT_EQ(nullptr, el2);
|
||||
|
||||
oa.free(el0);
|
||||
el2 = oa.allocate();
|
||||
EXPECT_EQ(underlyingMemory, el2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OpaqueElementAllocator, WhenAllocateIsCalledThenAllocatesAndReturnsFirstFreeElementAndGrowsIfNeeded) {
|
||||
struct GraphicsAllocationHandleExample {};
|
||||
using AllocatorT = OpaqueElementAllocator<GraphicsAllocationHandleExample *>;
|
||||
using AllocationT = AllocatorT::AllocationT;
|
||||
|
||||
std::set<GraphicsAllocationHandleExample *> graphicsAllocations;
|
||||
{
|
||||
const size_t chunkSize = 256;
|
||||
const size_t elementSize = 64;
|
||||
AllocatorT allocator(chunkSize, elementSize, AllocatorT::UnderlyingAllocatorT{.allocate = [&](size_t s, size_t a) -> AllocationT {
|
||||
auto newGa = new GraphicsAllocationHandleExample;
|
||||
graphicsAllocations.insert(newGa);
|
||||
return {newGa, alignedMalloc(s, a)};
|
||||
},
|
||||
.free = [&](AllocationT alloc) {
|
||||
UNRECOVERABLE_IF(1 != graphicsAllocations.count(alloc.first));
|
||||
graphicsAllocations.erase(alloc.first);
|
||||
delete alloc.first;
|
||||
alignedFree(alloc.second); }});
|
||||
|
||||
auto elsPerChunk = chunkSize / elementSize;
|
||||
std::set<void *> allocated;
|
||||
int toAllocate = static_cast<int>(elsPerChunk * 3 + 1);
|
||||
for (int i = 0; i < toAllocate; ++i) {
|
||||
AllocationT el = allocator.allocate();
|
||||
EXPECT_NE(nullptr, el.first);
|
||||
EXPECT_NE(nullptr, el.second);
|
||||
EXPECT_EQ(1U, graphicsAllocations.count(el.first));
|
||||
EXPECT_EQ(0U, allocated.count(el.second));
|
||||
allocated.insert(el.second);
|
||||
|
||||
EXPECT_TRUE(isAligned(reinterpret_cast<uintptr_t>(el.second), elementSize));
|
||||
EXPECT_EQ(alignUp(i + 1, elsPerChunk) / elsPerChunk, graphicsAllocations.size());
|
||||
}
|
||||
|
||||
EXPECT_EQ(alignUp(toAllocate, elsPerChunk) / elsPerChunk, graphicsAllocations.size());
|
||||
for (auto ptr : allocated) {
|
||||
EXPECT_TRUE(allocator.contains(ptr));
|
||||
}
|
||||
int stackMem = 0;
|
||||
EXPECT_FALSE(allocator.contains(&stackMem));
|
||||
EXPECT_FALSE(allocator.free(&stackMem));
|
||||
|
||||
EXPECT_EQ(alignUp(toAllocate, elsPerChunk) / elsPerChunk, graphicsAllocations.size());
|
||||
for (auto ptr : allocated) {
|
||||
EXPECT_TRUE(allocator.free(ptr));
|
||||
}
|
||||
|
||||
allocated.clear();
|
||||
for (int i = 0; i < toAllocate; ++i) {
|
||||
AllocationT el = allocator.allocate();
|
||||
EXPECT_NE(nullptr, el.first);
|
||||
EXPECT_NE(nullptr, el.second);
|
||||
EXPECT_EQ(1U, graphicsAllocations.count(el.first));
|
||||
EXPECT_EQ(0U, allocated.count(el.second));
|
||||
allocated.insert(el.second);
|
||||
|
||||
EXPECT_TRUE(isAligned(reinterpret_cast<uintptr_t>(el.second), elementSize));
|
||||
}
|
||||
EXPECT_EQ(alignUp(toAllocate, elsPerChunk) / elsPerChunk, graphicsAllocations.size()) << " alloc reuse failed";
|
||||
}
|
||||
EXPECT_EQ(0U, graphicsAllocations.size());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user