mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
185 lines
No EOL
4.3 KiB
C++
185 lines
No EOL
4.3 KiB
C++
#include <Core/Core.h>
|
|
|
|
#define LTIMING(x) // RTIMING(x)
|
|
// #define LSTAT
|
|
|
|
namespace Upp {
|
|
|
|
#ifdef UPP_HEAP
|
|
|
|
#include "HeapImp.h"
|
|
|
|
// this part reserves very large (HPAGE*4 KB, default 16MB)
|
|
// chunks form the system and then serves as 4KB rounded allocator
|
|
// used as manager of huge memory blocks. 4KB and 64KB blocks are allocated from here too
|
|
// also able to deal with bigger blocks, those are directly allocated / freed from system
|
|
|
|
BlkHeader_<4096> HugeHeapDetail::freelist[20][1]; // only single global Huge heap...
|
|
Heap::HugePage *Heap::huge_pages;
|
|
|
|
#ifdef LSTAT
|
|
static int hstat[65536];
|
|
|
|
EXITBLOCK {
|
|
int cnt = 0;
|
|
for(int i = 0; i < 65536; i++) {
|
|
cnt += hstat[i];
|
|
if(hstat[i])
|
|
RLOG(i * 4 << " KB: " << hstat[i] << " / " << cnt);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
size_t sKBLimit = SIZE_MAX;
|
|
|
|
void MemoryLimitKb(int kb)
|
|
{
|
|
sKBLimit = kb;
|
|
}
|
|
|
|
static MemoryProfile *sPeak;
|
|
|
|
MemoryProfile *PeakMemoryProfile()
|
|
{
|
|
if(sPeak)
|
|
return sPeak;
|
|
sPeak = (MemoryProfile *)MemoryAllocPermanent(sizeof(MemoryProfile));
|
|
memset((void *)sPeak, 0, sizeof(MemoryProfile));
|
|
return NULL;
|
|
}
|
|
|
|
Heap::HugePage *Heap::free_huge_pages;
|
|
int Heap::free_hpages;
|
|
|
|
void *Heap::HugeAlloc(size_t count) // count in 4kb pages
|
|
{
|
|
LTIMING("HugeAlloc");
|
|
ASSERT(count);
|
|
|
|
#ifdef LSTAT
|
|
if(count < 65536)
|
|
hstat[count]++;
|
|
#endif
|
|
|
|
huge_4KB_count += count;
|
|
|
|
auto MaxMem = [&] {
|
|
if(huge_4KB_count > huge_4KB_count_max) {
|
|
huge_4KB_count_max = huge_4KB_count;
|
|
if(4 * (Heap::huge_4KB_count - Heap::free_4KB) > sKBLimit)
|
|
Panic("MemoryLimitKb breached!");
|
|
if(sPeak)
|
|
Make(*sPeak);
|
|
}
|
|
};
|
|
|
|
if(!D::freelist[0]->next) { // initialization
|
|
for(int i = 0; i < __countof(D::freelist); i++)
|
|
Dbl_Self(D::freelist[i]);
|
|
}
|
|
|
|
if(count > sys_block_limit) { // we are wasting 4KB to store just 4 bytes here, but this is n MB after all..
|
|
LTIMING("SysAlloc");
|
|
byte *sysblk = (byte *)SysAllocRaw((count + 1) * 4096);
|
|
BlkHeader *h = (BlkHeader *)(sysblk + 4096);
|
|
h->size = 0;
|
|
*((size_t *)sysblk) = count;
|
|
sys_count++;
|
|
sys_size += 4096 * count;
|
|
MaxMem();
|
|
return h;
|
|
}
|
|
|
|
LTIMING("Huge Alloc");
|
|
|
|
word wcount = (word)count;
|
|
|
|
for(int pass = 0; pass < 2; pass++) {
|
|
for(int i = Cv(wcount); i < __countof(D::freelist); i++) {
|
|
BlkHeader *l = D::freelist[i];
|
|
BlkHeader *h = l->next;
|
|
while(h != l) {
|
|
word sz = h->GetSize();
|
|
if(sz >= count) {
|
|
if(h->IsFirst() && h->IsLast()) // this is whole free page
|
|
free_hpages--;
|
|
void *ptr = MakeAlloc(h, wcount);
|
|
MaxMem();
|
|
return ptr;
|
|
}
|
|
h = h->next;
|
|
}
|
|
}
|
|
|
|
if(!FreeSmallEmpty(wcount, INT_MAX)) { // try to coalesce 4KB small free blocks back to huge storage
|
|
void *ptr = SysAllocRaw(HPAGE * 4096); // failed, add HPAGE from the system
|
|
|
|
HugePage *pg; // record in set of huge pages
|
|
if(free_huge_pages) {
|
|
pg = free_huge_pages;
|
|
free_huge_pages = free_huge_pages->next;
|
|
}
|
|
else
|
|
pg = (HugePage *)MemoryAllocPermanent(sizeof(HugePage));
|
|
|
|
pg->page = ptr;
|
|
pg->next = huge_pages;
|
|
huge_pages = pg;
|
|
huge_chunks++;
|
|
free_hpages++;
|
|
AddChunk((BlkHeader *)ptr, HPAGE);
|
|
}
|
|
}
|
|
Panic("Out of memory");
|
|
return NULL;
|
|
}
|
|
|
|
int Heap::HugeFree(void *ptr)
|
|
{
|
|
LTIMING("HugeFree");
|
|
BlkHeader *h = (BlkHeader *)ptr;
|
|
if(h->size == 0) {
|
|
LTIMING("Sys Free");
|
|
byte *sysblk = (byte *)h - 4096;
|
|
size_t count = *((size_t *)sysblk);
|
|
SysFreeRaw(sysblk, (count + 1) * 4096);
|
|
huge_4KB_count -= count;
|
|
sys_count--;
|
|
sys_size -= 4096 * count;
|
|
return 0;
|
|
}
|
|
LTIMING("Huge Free");
|
|
huge_4KB_count -= h->GetSize();
|
|
h = BlkHeap::Free(h);
|
|
int sz = h->GetSize();
|
|
if(h->IsFirst() && h->IsLast()) {
|
|
if(free_hpages >= max_free_hpages) { // we have enough pages in the reserve, return to the system
|
|
LTIMING("Free Huge Page");
|
|
h->UnlinkFree();
|
|
HugePage *p = NULL;
|
|
while(huge_pages) { // remove the page from the set of huge pages
|
|
HugePage *n = huge_pages->next;
|
|
if(huge_pages->page != h) {
|
|
huge_pages->next = p;
|
|
p = huge_pages;
|
|
}
|
|
huge_pages = n;
|
|
}
|
|
huge_pages = p;
|
|
huge_chunks--;
|
|
SysFreeRaw(h, sz * 4096);
|
|
}
|
|
else
|
|
free_hpages++;
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
bool Heap::HugeTryRealloc(void *ptr, size_t count)
|
|
{
|
|
return count <= HPAGE && BlkHeap::TryRealloc(ptr, count, huge_4KB_count);
|
|
}
|
|
|
|
#endif
|
|
|
|
} |