perf(allocator): made small allocations reusable by adding a memory bin
This commit is contained in:
parent
dd10dfd376
commit
120ddaed02
1 changed files with 148 additions and 39 deletions
|
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
static HANDLE hallocy_heap = NULL;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
@ -35,7 +37,12 @@ typedef struct HallocyMemoryHeader {
|
||||||
struct HallocyMemoryHeader *next;
|
struct HallocyMemoryHeader *next;
|
||||||
} HallocyMemoryHeader;
|
} HallocyMemoryHeader;
|
||||||
|
|
||||||
|
static _Thread_local size_t hallocy_small_memory_freed = 0;
|
||||||
|
static _Thread_local size_t hallocy_small_memory_allocated = 0;
|
||||||
|
static _Thread_local HallocyMemoryHeader *hallocy_small_memory_bin = NULL;
|
||||||
|
|
||||||
static size_t page_size = 0;
|
static size_t page_size = 0;
|
||||||
|
static size_t hallocy_small_allocation_size = 0;
|
||||||
|
|
||||||
void *hallocy_malloc(size_t size) {
|
void *hallocy_malloc(size_t size) {
|
||||||
if (page_size == 0) {
|
if (page_size == 0) {
|
||||||
|
|
@ -45,20 +52,65 @@ void *hallocy_malloc(size_t size) {
|
||||||
|
|
||||||
page_size = system_info.dwPageSize;
|
page_size = system_info.dwPageSize;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
page_size = sysconf(_SC_PAGESIZE);
|
page_size = sysconf(_SC_PAGE_SIZE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
hallocy_small_allocation_size = page_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t aligned_size = page_size * (((size + sizeof(HallocyMemoryHeader)) / page_size) + 1);
|
size_t aligned_size = page_size * (((size + sizeof(HallocyMemoryHeader)) / page_size) + 1);
|
||||||
HallocyMemoryHeader *memory_pointer = NULL;
|
HallocyMemoryHeader *memory_pointer = NULL;
|
||||||
#if defined(_WIN32)
|
if (aligned_size <= hallocy_small_allocation_size) {
|
||||||
memory_pointer = (HallocyMemoryHeader*)VirtualAlloc(NULL, aligned_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
HallocyMemoryHeader *previous_header = NULL;
|
||||||
#elif defined(__linux__)
|
memory_pointer = hallocy_small_memory_bin;
|
||||||
memory_pointer = (HallocyMemoryHeader*)mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
while (memory_pointer != NULL) {
|
||||||
#endif
|
if (memory_pointer->size >= aligned_size) {
|
||||||
|
hallocy_small_memory_allocated += memory_pointer->size;
|
||||||
|
hallocy_small_memory_freed -= memory_pointer->size;
|
||||||
|
|
||||||
if (memory_pointer == NULL) {
|
if (previous_header == NULL) {
|
||||||
return NULL;
|
hallocy_small_memory_bin = hallocy_small_memory_bin->next;
|
||||||
|
} else {
|
||||||
|
previous_header->next = memory_pointer->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_pointer->next = NULL;
|
||||||
|
return (void*)(memory_pointer + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_header = memory_pointer;
|
||||||
|
memory_pointer = memory_pointer->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (hallocy_heap == NULL) {
|
||||||
|
hallocy_heap = GetProcessHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_pointer = HeapAlloc(hallocy_heap, 0, aligned_size);
|
||||||
|
if (memory_pointer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
memory_pointer = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
if (memory_pointer == MAP_FAILED) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hallocy_small_memory_allocated += aligned_size;
|
||||||
|
} else {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
memory_pointer = (HallocyMemoryHeader*)VirtualAlloc(NULL, aligned_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
if (memory_pointer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
memory_pointer = (HallocyMemoryHeader*)mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
|
if (memory_pointer == MAP_FAILED) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_pointer->size = aligned_size;
|
memory_pointer->size = aligned_size;
|
||||||
|
|
@ -73,45 +125,102 @@ HallocyError hallocy_free(void *pointer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
HallocyMemoryHeader *memory_header = ((HallocyMemoryHeader*)pointer) - 1;
|
HallocyMemoryHeader *memory_header = ((HallocyMemoryHeader*)pointer) - 1;
|
||||||
#if defined(_WIN32)
|
if (memory_header->size <= hallocy_small_allocation_size) {
|
||||||
bool result = VirtualFree(memory_header, 0, MEM_RELEASE);
|
memory_header->next = hallocy_small_memory_bin;
|
||||||
if (result == false) {
|
hallocy_small_memory_bin = memory_header;
|
||||||
DWORD error = GetLastError();
|
|
||||||
switch (error) {
|
hallocy_small_memory_allocated -= memory_header->size;
|
||||||
case ERROR_INVALID_PARAMETER:
|
hallocy_small_memory_freed += memory_header->size;
|
||||||
return HALLOCY_ERROR_INVALID_PARAM;
|
if (hallocy_small_memory_allocated == 0 && hallocy_small_memory_freed > hallocy_small_allocation_size * 10) {
|
||||||
|
HallocyMemoryHeader *previous_header = NULL;
|
||||||
|
HallocyMemoryHeader *current_header = hallocy_small_memory_bin;
|
||||||
|
while (current_header != NULL) {
|
||||||
|
previous_header = current_header;
|
||||||
|
current_header = current_header->next;
|
||||||
|
|
||||||
case ERROR_NOT_ENOUGH_MEMORY:
|
#if defined(_WIN32)
|
||||||
return HALLOCY_ERROR_OUT_OF_MEMORY;
|
bool result = HeapFree(hallocy_heap, 0, previous_header);
|
||||||
|
if (result == false) {
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
switch (error) {
|
||||||
|
case ERROR_INVALID_PARAMETER:
|
||||||
|
return HALLOCY_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||||||
|
return HALLOCY_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
case ERROR_INVALID_HANDLE:
|
||||||
|
return HALLOCY_ERROR_INVALID_POINTER;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HALLOCY_ERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
int result = munmap(previous_header, previous_header->size);
|
||||||
|
if (result == -1) {
|
||||||
|
switch (errno) {
|
||||||
|
case EINVAL:
|
||||||
|
return HALLOCY_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
case ENOMEM:
|
||||||
|
return HALLOCY_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
case EFAULT:
|
||||||
|
return HALLOCY_ERROR_INVALID_POINTER;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HALLOCY_ERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
case ERROR_INVALID_HANDLE:
|
hallocy_small_memory_bin = NULL;
|
||||||
return HALLOCY_ERROR_INVALID_POINTER;
|
hallocy_small_memory_allocated = 0;
|
||||||
|
hallocy_small_memory_freed = 0;
|
||||||
case ERROR_INVALID_ADDRESS:
|
|
||||||
return HALLOCY_ERROR_INVALID_POINTER;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return HALLOCY_ERROR_UNKNOWN;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
#elif defined(__linux__)
|
#if defined(_WIN32)
|
||||||
int result = munmap(memory_header, memory_header->size);
|
bool result = VirtualFree(memory_header, 0, MEM_RELEASE);
|
||||||
if (result == -1) {
|
if (result == false) {
|
||||||
switch (errno) {
|
DWORD error = GetLastError();
|
||||||
case EINVAL:
|
switch (error) {
|
||||||
return HALLOCY_ERROR_INVALID_PARAM;
|
case ERROR_INVALID_PARAMETER:
|
||||||
|
return HALLOCY_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
case ENOMEM:
|
case ERROR_NOT_ENOUGH_MEMORY:
|
||||||
return HALLOCY_ERROR_OUT_OF_MEMORY;
|
return HALLOCY_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
case EFAULT:
|
case ERROR_INVALID_HANDLE:
|
||||||
return HALLOCY_ERROR_INVALID_POINTER;
|
return HALLOCY_ERROR_INVALID_POINTER;
|
||||||
|
|
||||||
default:
|
case ERROR_INVALID_ADDRESS:
|
||||||
return HALLOCY_ERROR_UNKNOWN;
|
return HALLOCY_ERROR_INVALID_POINTER;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HALLOCY_ERROR_UNKNOWN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
int result = munmap(memory_header, memory_header->size);
|
||||||
|
if (result == -1) {
|
||||||
|
switch (errno) {
|
||||||
|
case EINVAL:
|
||||||
|
return HALLOCY_ERROR_INVALID_PARAM;
|
||||||
|
|
||||||
|
case ENOMEM:
|
||||||
|
return HALLOCY_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
case EFAULT:
|
||||||
|
return HALLOCY_ERROR_INVALID_POINTER;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return HALLOCY_ERROR_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return HALLOCY_ERROR_NONE;
|
return HALLOCY_ERROR_NONE;
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue