BBlockCache: Use a pthread_mutex instead of BLocker.

The lighter "struct mutex" is in a private header, so we can't
inline it in a public one, so just use pthread_mutex here.

By adjusting padding, the class size stays the same (72 bytes
on 32-bit, 96 bytes on 64-bit; confirmed via static_assert.)

A quick benchmark running "new/delete BMessage" in a loop on 4
threads at once goes from 30-36 seconds before this commit
to around 13-17 seconds, sometimes as low as 3 seconds, afterwards,
so clearly this is a significant improvement.

This also eliminates another BLocker allocated on application startup.
This commit is contained in:
Augustin Cavalier
2026-03-02 19:37:13 -05:00
parent 184b57aa71
commit ae70142168
2 changed files with 30 additions and 23 deletions
+12 -10
View File
@@ -6,7 +6,7 @@
#define _BLOCK_CACHE_H
#include <Locker.h>
#include <SupportDefs.h>
enum {
@@ -31,16 +31,18 @@ private:
BBlockCache &operator=(const BBlockCache &);
private:
struct _FreeBlock;
struct _FreeBlock;
_FreeBlock* fFreeList;
size_t fBlockSize;
int32 fFreeBlocks;
int32 fBlockCount;
BLocker fLocker;
void* (*fAlloc)(size_t size);
void (*fFree)(void *pointer);
uint32 _reserved[2];
_FreeBlock* fFreeList;
const size_t fBlockSize;
void* (*fAlloc)(size_t size);
void (*fFree)(void *pointer);
pthread_mutex_t fLock;
int32 fFreeBlocks;
int32 fBlockCount;
uint32 _reserved[6];
};
+18 -13
View File
@@ -9,6 +9,7 @@
#include <string.h>
#include <stdlib.h>
#include <new>
#include <pthread.h>
#ifdef __HAIKU__
@@ -39,11 +40,10 @@ BBlockCache::BBlockCache(uint32 blockCount, size_t blockSize,
:
fFreeList(0),
fBlockSize(blockSize),
fAlloc(NULL),
fFree(NULL),
fFreeBlocks(0),
fBlockCount(blockCount),
fLocker("some BBlockCache lock"),
fAlloc(0),
fFree(0)
fBlockCount(blockCount)
{
switch (allocationType) {
case B_OBJECT_CACHE:
@@ -61,6 +61,8 @@ BBlockCache::BBlockCache(uint32 blockCount, size_t blockSize,
if (heap_debug_get_allocation_info != NULL)
return;
pthread_mutex_init(&fLock, NULL);
// To properly maintain a list of free buffers, a buffer must be
// large enough to contain the _FreeBlock struct that is used.
if (blockSize < sizeof(_FreeBlock))
@@ -87,7 +89,7 @@ BBlockCache::BBlockCache(uint32 blockCount, size_t blockSize,
BBlockCache::~BBlockCache()
{
// walk the free list and deallocate all blocks
fLocker.Lock();
pthread_mutex_lock(&fLock);
while (fFreeList) {
ASSERT(fFreeList->magic1 == MAGIC1);
ASSERT(fFreeList->magic2 == MAGIC2 + (uint32)(addr_t)fFreeList->next);
@@ -96,7 +98,8 @@ BBlockCache::~BBlockCache()
DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock)));
fFree(pointer);
}
fLocker.Unlock();
pthread_mutex_destroy(&fLock);
}
@@ -106,8 +109,7 @@ BBlockCache::Get(size_t blockSize)
if (heap_debug_get_allocation_info != NULL)
return fAlloc(blockSize);
if (!fLocker.Lock())
return 0;
pthread_mutex_lock(&fLock);
void *pointer;
if (blockSize == fBlockSize && fFreeList != 0) {
// we can take a block from the list
@@ -117,14 +119,16 @@ BBlockCache::Get(size_t blockSize)
fFreeList = fFreeList->next;
fFreeBlocks--;
DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock)));
pthread_mutex_unlock(&fLock);
return pointer;
} else {
pthread_mutex_unlock(&fLock);
if (blockSize < sizeof(_FreeBlock))
blockSize = sizeof(_FreeBlock);
pointer = fAlloc(blockSize);
DEBUG_ONLY(if (pointer) memset(pointer, 0xCC, sizeof(_FreeBlock)));
return pointer;
}
fLocker.Unlock();
return pointer;
}
@@ -136,8 +140,7 @@ BBlockCache::Save(void *pointer, size_t blockSize)
return;
}
if (!fLocker.Lock())
return;
pthread_mutex_lock(&fLock);
if (blockSize == fBlockSize && fFreeBlocks < fBlockCount) {
// the block needs to be returned to the cache
_FreeBlock *block = reinterpret_cast<_FreeBlock *>(pointer);
@@ -146,11 +149,13 @@ BBlockCache::Save(void *pointer, size_t blockSize)
fFreeBlocks++;
DEBUG_ONLY(block->magic1 = MAGIC1);
DEBUG_ONLY(block->magic2 = MAGIC2 + (uint32)(addr_t)block->next);
pthread_mutex_unlock(&fLock);
} else {
pthread_mutex_unlock(&fLock);
DEBUG_ONLY(memset(pointer, 0xCC, sizeof(_FreeBlock)));
fFree(pointer);
return;
}
fLocker.Unlock();
}