mirror of https://github.com/OpenTTD/OpenTTD
Change: Improve performance of finding free pool slots. (#12055)
Add a bitmap of used pool slots which allows finding a free pool slot without having to check if each index is already used or not. Loosely based on a JGRPP patch.pull/12103/head
parent
1aa9a5c0ab
commit
2ecc3c90f7
|
@ -11,6 +11,7 @@
|
||||||
#define POOL_FUNC_HPP
|
#define POOL_FUNC_HPP
|
||||||
|
|
||||||
#include "alloc_func.hpp"
|
#include "alloc_func.hpp"
|
||||||
|
#include "bitmath_func.hpp"
|
||||||
#include "mem_func.hpp"
|
#include "mem_func.hpp"
|
||||||
#include "pool_type.hpp"
|
#include "pool_type.hpp"
|
||||||
#include "../error_func.h"
|
#include "../error_func.h"
|
||||||
|
@ -60,6 +61,16 @@ DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
|
||||||
this->data = ReallocT(this->data, new_size);
|
this->data = ReallocT(this->data, new_size);
|
||||||
MemSetT(this->data + this->size, 0, new_size - this->size);
|
MemSetT(this->data + this->size, 0, new_size - this->size);
|
||||||
|
|
||||||
|
this->used_bitmap.resize(Align(new_size, BITMAP_SIZE) / BITMAP_SIZE);
|
||||||
|
if (this->size % BITMAP_SIZE != 0) {
|
||||||
|
/* Already-allocated bits above old size are now unused. */
|
||||||
|
this->used_bitmap[this->size / BITMAP_SIZE] &= ~((~static_cast<BitmapStorage>(0)) << (this->size % BITMAP_SIZE));
|
||||||
|
}
|
||||||
|
if (new_size % BITMAP_SIZE != 0) {
|
||||||
|
/* Bits above new size are considered used. */
|
||||||
|
this->used_bitmap[new_size / BITMAP_SIZE] |= (~static_cast<BitmapStorage>(0)) << (new_size % BITMAP_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
this->size = new_size;
|
this->size = new_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,25 +80,20 @@ DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index)
|
||||||
*/
|
*/
|
||||||
DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
|
DEFINE_POOL_METHOD(inline size_t)::FindFirstFree()
|
||||||
{
|
{
|
||||||
size_t index = this->first_free;
|
for (auto it = std::next(std::begin(this->used_bitmap), this->first_free / BITMAP_SIZE); it != std::end(this->used_bitmap); ++it) {
|
||||||
|
BitmapStorage available = ~(*it);
|
||||||
for (; index < this->first_unused; index++) {
|
if (available == 0) continue;
|
||||||
if (this->data[index] == nullptr) return index;
|
return std::distance(std::begin(this->used_bitmap), it) * BITMAP_SIZE + FindFirstBit(available);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < this->size) {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(index == this->size);
|
|
||||||
assert(this->first_unused == this->size);
|
assert(this->first_unused == this->size);
|
||||||
|
|
||||||
if (index < Tmax_size) {
|
if (this->first_unused < Tmax_size) {
|
||||||
this->ResizeFor(index);
|
this->ResizeFor(this->first_unused);
|
||||||
return index;
|
return this->first_unused;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(this->items == Tmax_size);
|
assert(this->first_unused == Tmax_size);
|
||||||
|
|
||||||
return NO_FREE_ITEM;
|
return NO_FREE_ITEM;
|
||||||
}
|
}
|
||||||
|
@ -122,6 +128,7 @@ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index)
|
||||||
item = (Titem *)MallocT<byte>(size);
|
item = (Titem *)MallocT<byte>(size);
|
||||||
}
|
}
|
||||||
this->data[index] = item;
|
this->data[index] = item;
|
||||||
|
SetBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
|
||||||
item->index = (Tindex)(uint)index;
|
item->index = (Tindex)(uint)index;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
@ -190,7 +197,10 @@ DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
|
||||||
this->data[index] = nullptr;
|
this->data[index] = nullptr;
|
||||||
this->first_free = std::min(this->first_free, index);
|
this->first_free = std::min(this->first_free, index);
|
||||||
this->items--;
|
this->items--;
|
||||||
if (!this->cleaning) Titem::PostDestructor(index);
|
if (!this->cleaning) {
|
||||||
|
ClrBit(this->used_bitmap[index / BITMAP_SIZE], index % BITMAP_SIZE);
|
||||||
|
Titem::PostDestructor(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Destroys all items in the pool and resets all member variables. */
|
/** Destroys all items in the pool and resets all member variables. */
|
||||||
|
@ -202,6 +212,8 @@ DEFINE_POOL_METHOD(void)::CleanPool()
|
||||||
}
|
}
|
||||||
assert(this->items == 0);
|
assert(this->items == 0);
|
||||||
free(this->data);
|
free(this->data);
|
||||||
|
this->used_bitmap.clear();
|
||||||
|
this->used_bitmap.shrink_to_fit();
|
||||||
this->first_unused = this->first_free = this->size = 0;
|
this->first_unused = this->first_free = this->size = 0;
|
||||||
this->data = nullptr;
|
this->data = nullptr;
|
||||||
this->cleaning = false;
|
this->cleaning = false;
|
||||||
|
|
|
@ -83,6 +83,9 @@ struct Pool : PoolBase {
|
||||||
|
|
||||||
static constexpr size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside
|
static constexpr size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside
|
||||||
|
|
||||||
|
using BitmapStorage = size_t;
|
||||||
|
static constexpr size_t BITMAP_SIZE = std::numeric_limits<BitmapStorage>::digits;
|
||||||
|
|
||||||
const char * const name; ///< Name of this pool
|
const char * const name; ///< Name of this pool
|
||||||
|
|
||||||
size_t size; ///< Current allocated size
|
size_t size; ///< Current allocated size
|
||||||
|
@ -95,6 +98,7 @@ struct Pool : PoolBase {
|
||||||
bool cleaning; ///< True if cleaning pool (deleting all items)
|
bool cleaning; ///< True if cleaning pool (deleting all items)
|
||||||
|
|
||||||
Titem **data; ///< Pointer to array of pointers to Titem
|
Titem **data; ///< Pointer to array of pointers to Titem
|
||||||
|
std::vector<BitmapStorage> used_bitmap; ///< Bitmap of used indices.
|
||||||
|
|
||||||
Pool(const char *name);
|
Pool(const char *name);
|
||||||
void CleanPool() override;
|
void CleanPool() override;
|
||||||
|
|
Loading…
Reference in New Issue