Update the SkSL pool interface to take an allocation size.

Since our end goal no longer has all IRNodes ending up as the exact same
size in memory, it makes sense for the allocator function to take in a
desired size. This also opens the door to separate "small" and "large"
pools, if we want to add pooling support for large but semi-common
things like Variables.

Change-Id: If3dbe31588adeedede327c5967c344a19507b6fa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/329961
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2020-10-27 10:48:15 -04:00 committed by Skia Commit-Bot
parent 5567a6091c
commit 22ef2257c8
3 changed files with 26 additions and 24 deletions

View File

@ -14,9 +14,12 @@
namespace SkSL { namespace SkSL {
static constexpr int kSmallNodeSize = 120;
static constexpr int kNodesInPool = 512;
namespace { struct IRNodeData { namespace { struct IRNodeData {
union { union {
uint8_t fBuffer[sizeof(IRNode)]; uint8_t fBuffer[kSmallNodeSize];
IRNodeData* fFreeListNext; IRNodeData* fFreeListNext;
}; };
}; } }; }
@ -116,8 +119,6 @@ Pool::~Pool() {
} }
std::unique_ptr<Pool> Pool::Create() { std::unique_ptr<Pool> Pool::Create() {
constexpr int kNodesInPool = 512;
SkAutoMutexExclusive lock(recycled_pool_mutex()); SkAutoMutexExclusive lock(recycled_pool_mutex());
std::unique_ptr<Pool> pool; std::unique_ptr<Pool> pool;
if (sRecycledPool) { if (sRecycledPool) {
@ -159,23 +160,26 @@ void Pool::detachFromThread() {
set_thread_local_pool_data(nullptr); set_thread_local_pool_data(nullptr);
} }
void* Pool::AllocIRNode() { void* Pool::AllocIRNode(size_t size) {
// Is a pool attached? // Can the requested size fit in a pool node?
PoolData* poolData = get_thread_local_pool_data(); if (size <= kSmallNodeSize) {
if (poolData) { // Is a pool attached?
// Does the pool contain a free node? PoolData* poolData = get_thread_local_pool_data();
IRNodeData* node = poolData->fFreeListHead; if (poolData) {
if (node) { // Does the pool contain a free node?
// Yes. Take a node from the freelist. IRNodeData* node = poolData->fFreeListHead;
poolData->fFreeListHead = node->fFreeListNext; if (node) {
VLOG("ALLOC Pool:0x%016llX Index:%04d 0x%016llX\n", // Yes. Take a node from the freelist.
(uint64_t)poolData, poolData->nodeIndex(node), (uint64_t)node); poolData->fFreeListHead = node->fFreeListNext;
return node->fBuffer; VLOG("ALLOC Pool:0x%016llX Index:%04d 0x%016llX\n",
(uint64_t)poolData, poolData->nodeIndex(node), (uint64_t)node);
return node->fBuffer;
}
} }
} }
// The pool is detached or full; allocate nodes using malloc. // The pool can't be used for this allocation. Allocate nodes using the system allocator.
void* ptr = ::operator new(sizeof(IRNode)); void* ptr = ::operator new(size);
VLOG("ALLOC Pool:0x%016llX Index:____ malloc 0x%016llX\n", VLOG("ALLOC Pool:0x%016llX Index:____ malloc 0x%016llX\n",
(uint64_t)poolData, (uint64_t)ptr); (uint64_t)poolData, (uint64_t)ptr);
return ptr; return ptr;
@ -197,7 +201,7 @@ void Pool::FreeIRNode(void* node_v) {
} }
} }
// No pool is attached or the node was malloced; it must be freed. // We couldn't associate this node with our pool. Free it using the system allocator.
VLOG("FREE Pool:0x%016llX Index:____ free 0x%016llX\n", VLOG("FREE Pool:0x%016llX Index:____ free 0x%016llX\n",
(uint64_t)poolData, (uint64_t)node_v); (uint64_t)poolData, (uint64_t)node_v);
::operator delete(node_v); ::operator delete(node_v);

View File

@ -41,8 +41,9 @@ public:
// It is an error to call this while no pool is attached. // It is an error to call this while no pool is attached.
void detachFromThread(); void detachFromThread();
// Retrieves a node from the thread pool. If the pool is exhausted, this will allocate a node. // Retrieves a node from the thread pool. If the pool is exhausted, or if the requested size
static void* AllocIRNode(); // exceeds the size that we can deliver from a pool, this will just allocate memory.
static void* AllocIRNode(size_t size);
// Releases a node that was created by AllocIRNode. This will return it to the pool, or free it, // Releases a node that was created by AllocIRNode. This will return it to the pool, or free it,
// as appropriate. Make sure to free all nodes, since some of them may be real allocations. // as appropriate. Make sure to free all nodes, since some of them may be real allocations.

View File

@ -67,10 +67,7 @@ public:
// Override operator new and delete to allow us to control allocation behavior. // Override operator new and delete to allow us to control allocation behavior.
static void* operator new(const size_t size) { static void* operator new(const size_t size) {
if (size == sizeof(IRNode)) { return Pool::AllocIRNode(size);
return Pool::AllocIRNode();
}
return ::operator new(size);
} }
static void operator delete(void* ptr) { static void operator delete(void* ptr) {