Add a bump allocator.
This CL adds a simple allocator which will provide a chunk of memory of the given size. It allocates out of slabs of memory. Change-Id: I9acf59fac88cd6bef260b7ebae7d7b77fd939754 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/127302 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
dc071b1098
commit
fa3c08d112
|
@ -222,6 +222,7 @@ libtint_source_set("libtint_base_src") {
|
|||
"utils/bitcast.h",
|
||||
"utils/bitset.h",
|
||||
"utils/block_allocator.h",
|
||||
"utils/bump_allocator.h",
|
||||
"utils/compiler_macros.h",
|
||||
"utils/concat.h",
|
||||
"utils/crc32.h",
|
||||
|
@ -1588,6 +1589,7 @@ if (tint_build_unittests) {
|
|||
"utils/bitcast_test.cc",
|
||||
"utils/bitset_test.cc",
|
||||
"utils/block_allocator_test.cc",
|
||||
"utils/bump_allocator_test.cc",
|
||||
"utils/crc32_test.cc",
|
||||
"utils/defer_test.cc",
|
||||
"utils/enum_set_test.cc",
|
||||
|
|
|
@ -517,6 +517,7 @@ list(APPEND TINT_LIB_SRCS
|
|||
utils/bitcast.h
|
||||
utils/bitset.h
|
||||
utils/block_allocator.h
|
||||
utils/bump_allocator.h
|
||||
utils/compiler_macros.h
|
||||
utils/concat.h
|
||||
utils/crc32.h
|
||||
|
@ -998,6 +999,7 @@ if(TINT_BUILD_TESTS)
|
|||
utils/bitcast_test.cc
|
||||
utils/bitset_test.cc
|
||||
utils/block_allocator_test.cc
|
||||
utils/bump_allocator_test.cc
|
||||
utils/crc32_test.cc
|
||||
utils/defer_test.cc
|
||||
utils/enum_set_test.cc
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2023 The Tint Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#ifndef SRC_TINT_UTILS_BUMP_ALLOCATOR_H_
|
||||
#define SRC_TINT_UTILS_BUMP_ALLOCATOR_H_
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "src/tint/utils/bitcast.h"
|
||||
#include "src/tint/utils/math.h"
|
||||
|
||||
namespace tint::utils {
|
||||
|
||||
constexpr size_t kBlockSize = 64 * 1024;
|
||||
|
||||
/// A allocator for chunks of memory. The memory is owned by the BumpAllocator. When the
|
||||
/// BumpAllocator is freed all of the allocated memory is freed.
|
||||
class BumpAllocator {
|
||||
/// Block is linked list of memory blocks.
|
||||
/// Blocks are allocated out of heap memory.
|
||||
struct Block {
|
||||
uint8_t data[kBlockSize];
|
||||
Block* next;
|
||||
};
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
BumpAllocator() = default;
|
||||
|
||||
/// Move constructor
|
||||
/// @param rhs the BumpAllocator to move
|
||||
BumpAllocator(BumpAllocator&& rhs) { std::swap(data, rhs.data); }
|
||||
|
||||
/// Move assignment operator
|
||||
/// @param rhs the BumpAllocator to move
|
||||
/// @return this BumpAllocator
|
||||
BumpAllocator& operator=(BumpAllocator&& rhs) {
|
||||
if (this != &rhs) {
|
||||
Reset();
|
||||
std::swap(data, rhs.data);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Destructor
|
||||
~BumpAllocator() { Reset(); }
|
||||
|
||||
/// Allocates @p size_in_bytes from the current block, or from a newly allocated block if the
|
||||
/// current block is full.
|
||||
/// @param size_in_bytes the number of bytes to allocate
|
||||
/// @returns the pointer to the allocated memory or |nullptr| if the memory can not be allocated
|
||||
char* Allocate(size_t size_in_bytes) {
|
||||
auto& block = data.block;
|
||||
if (block.current_offset + size_in_bytes > kBlockSize) {
|
||||
// Allocate a new block from the heap
|
||||
auto* prev_block = block.current;
|
||||
block.current = new Block;
|
||||
if (!block.current) {
|
||||
return nullptr; // out of memory
|
||||
}
|
||||
block.current->next = nullptr;
|
||||
block.current_offset = 0;
|
||||
if (prev_block) {
|
||||
prev_block->next = block.current;
|
||||
} else {
|
||||
block.root = block.current;
|
||||
}
|
||||
}
|
||||
|
||||
auto* base = &block.current->data[0];
|
||||
auto* ptr = reinterpret_cast<char*>(base + block.current_offset);
|
||||
block.current_offset += size_in_bytes;
|
||||
data.count++;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// Frees all allocations from the allocator.
|
||||
void Reset() {
|
||||
auto* block = data.block.root;
|
||||
while (block != nullptr) {
|
||||
auto* next = block->next;
|
||||
delete block;
|
||||
block = next;
|
||||
}
|
||||
data = {};
|
||||
}
|
||||
|
||||
/// @returns the total number of allocations
|
||||
size_t Count() const { return data.count; }
|
||||
|
||||
private:
|
||||
BumpAllocator(const BumpAllocator&) = delete;
|
||||
BumpAllocator& operator=(const BumpAllocator&) = delete;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
/// The root block of the block linked list
|
||||
Block* root = nullptr;
|
||||
/// The current (end) block of the blocked linked list.
|
||||
/// New allocations come from this block
|
||||
Block* current = nullptr;
|
||||
/// The byte offset in #current for the next allocation.
|
||||
/// Initialized with kBlockSize so that the first allocation triggers a block
|
||||
/// allocation.
|
||||
size_t current_offset = kBlockSize;
|
||||
} block;
|
||||
|
||||
size_t count = 0;
|
||||
} data;
|
||||
};
|
||||
|
||||
} // namespace tint::utils
|
||||
|
||||
#endif // SRC_TINT_UTILS_BUMP_ALLOCATOR_H_
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2023 The Tint Authors.
|
||||
//
|
||||
// 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 "src/tint/utils/bump_allocator.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace tint::utils {
|
||||
namespace {
|
||||
|
||||
using BumpAllocatorTest = testing::Test;
|
||||
|
||||
TEST_F(BumpAllocatorTest, Count) {
|
||||
for (size_t n : {0u, 1u, 10u, 16u, 20u, 32u, 50u, 64u, 100u, 256u, 300u, 512u, 500u, 512u}) {
|
||||
BumpAllocator allocator;
|
||||
EXPECT_EQ(allocator.Count(), 0u);
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
allocator.Allocate(5);
|
||||
}
|
||||
EXPECT_EQ(allocator.Count(), n);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BumpAllocatorTest, MoveConstruct) {
|
||||
for (size_t n : {0u, 1u, 10u, 16u, 20u, 32u, 50u, 64u, 100u, 256u, 300u, 512u, 500u, 512u}) {
|
||||
BumpAllocator allocator_a;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
allocator_a.Allocate(5);
|
||||
}
|
||||
EXPECT_EQ(allocator_a.Count(), n);
|
||||
|
||||
BumpAllocator allocator_b{std::move(allocator_a)};
|
||||
EXPECT_EQ(allocator_b.Count(), n);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::utils
|
Loading…
Reference in New Issue