Core: Improved approximate best fit in allocator

git-svn-id: svn://ultimatepp.org/upp/trunk@13377 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2019-06-10 15:26:34 +00:00
parent d635502c28
commit e53932b2f5
10 changed files with 101 additions and 29 deletions

View file

@ -41,7 +41,7 @@ void CSyntax::InitKeywords()
"do", "__int64", "static", "volatile",
"double", "__leave", "static_cast",
"dynamic_cast", "long", "__stdcall", "while",
"force_inline",
"force_inline", "never_inline",
"and", "bitor", "or", "xor",
"compl", "bitand", "and_eq", "or_eq",
"xor_eq", "not", "not_eq",

View file

@ -11,6 +11,7 @@ void *MemoryAlloc48();
void MemoryFree48(void *ptr);
void MemoryFreeThread();
void MemoryCheck();
void MemoryDump();
int MemoryUsedKb();
int MemoryUsedKbMax();
void MemoryLimitKb(int kb);

View file

@ -254,10 +254,18 @@ typename BlkHeap<Detail, BlkSize>::BlkHeader *BlkHeap<Detail, BlkSize>::Free(Blk
}
struct HugeHeapDetail {
#if 0
static BlkHeader_<4096> freelist[2][1];
static void LinkFree(BlkHeader_<4096> *h) { Dbl_LinkAfter(h, freelist[h->GetSize() >= 16]); }
static void NewFreeSize(BlkHeader_<4096> *h) {}
#else
static BlkHeader_<4096> freelist[20][1];
static int Cv(int n) { return n < 16 ? 0 : SignificantBits(n - 16) + 1; }
static void LinkFree(BlkHeader_<4096> *h) { Dbl_LinkAfter(h, freelist[Cv(h->GetSize())]); }
static void NewFreeSize(BlkHeader_<4096> *h) {}
#endif
};
struct Heap : BlkHeap<HugeHeapDetail, 4096> {
@ -269,6 +277,7 @@ struct Heap : BlkHeap<HugeHeapDetail, 4096> {
#endif
LUNIT = 256, // granularity of large blocks (size always a multiple of this)
LPAGE = LUNIT - 1, // number of LUNITs in large page
LCVCOUNT = 9, // SignificantBits(LPAGE) + 1
LOFFSET = 64, // offset from 64KB start to the first block header
NKLASS = 23, // number of small size classes
@ -315,8 +324,11 @@ struct Heap : BlkHeap<HugeHeapDetail, 4096> {
};
struct LargeHeapDetail {
BlkHeader_<LUNIT> freelist[6][1]; // <1KB, <2KB, <4KB, <8KB, >= 8KB
static int Cv(int n) { return min(n >> 2, 4); }
// BlkHeader_<LUNIT> freelist[6][1]; // <1KB, <2KB, <4KB, <8KB, >= 8KB
// static int Cv(int n) { return min(n >> 2, 4); }
BlkHeader_<LUNIT> freelist[LCVCOUNT][1];
static int Cv(int n) { return SignificantBits(n); }
void Free64KB(BlkHeader_<LUNIT> *h);
void LinkFree(BlkHeader_<LUNIT> *h) {
@ -431,6 +443,7 @@ struct Heap : BlkHeap<HugeHeapDetail, 4096> {
size_t LGetBlockSize(void *ptr);
void Make(MemoryProfile& f);
void Dump();
static void Shrink();

View file

@ -288,3 +288,14 @@ inline dword FoldHash(dword h)
{
return SwapEndian32(0xa3613c16 * h);
}
force_inline
int SignificantBits(dword x)
{ // basically log2(x) + 1 except that for 0 this is 0, number of significant bits of x
#ifdef COMPILER_MSC
DWORD index;
return _BitScanReverse(&index, x) ? index + 1 : 0;
#else
return x ? 32 - __builtin_clz(x) : 0;
#endif
}

View file

@ -181,6 +181,35 @@ void Heap::Make(MemoryProfile& f)
}
}
void Heap::Dump()
{
Mutex::Lock __(mutex);
DLink *m = large->next;
while(m != large) {
LargeHeap::BlkHeader *h = m->GetFirst();
RLOG("--------------------------");
for(;;) {
RLOG(asString(h) << " " << h->GetSize() << (h->IsFree() ? " FREE" : ""));
if(h->IsLast())
break;
h = h->GetNextHeader();
}
m = m->next;
}
HugePage *pg = huge_pages;
while(pg) {
BlkPrefix *h = (BlkPrefix *)pg->page;
RLOG("==========================");
for(;;) {
RLOG(asString(h) << " " << h->GetSize() << (h->IsFree() ? " FREE" : ""));
if(h->IsLast())
break;
h = h->GetNextHeader(4096);
}
pg = pg->next;
}
}
String AsString(const MemoryProfile& mem)
{
String text;
@ -189,7 +218,7 @@ String AsString(const MemoryProfile& mem)
size_t asize = 0;
int fcount = 0;
size_t fsize = 0;
text << "Memory peak " << MemoryUsedKbMax() << "\n";
text << "Memory peak: " << MemoryUsedKbMax() << " KB, current: " << MemoryUsedKb() << "KB \n";
for(int i = 0; i < 1024; i++)
if(mem.allocated[i]) {
int sz = 4 * i;
@ -210,14 +239,8 @@ String AsString(const MemoryProfile& mem)
<< ", total size " << (mem.large_fragments_total >> 10) << " KB\n";
text << "Huge block count " << mem.huge_count
<< ", total size " << int(mem.huge_total >> 10) << " KB\n";
size_t hf = 0;
int cnt = 0;
for(int i = 0; i < 65535; i++) {
hf += 4 * mem.huge_fragments[i];
cnt += !!mem.huge_fragments[i];
}
text << "Huge fragments count " << cnt
<< ", total size " << hf << " KB\n";
text << "Huge fragments count " << mem.huge_fragments_count
<< ", total size " << 4 * mem.huge_fragments_total << " KB\n";
text << "Sys block count " << mem.sys_count
<< ", total size " << int(mem.sys_total >> 10) << " KB\n";
text << Heap::HPAGE * 4 / 1024 << "MB master blocks " << mem.master_chunks << "\n";

View file

@ -14,7 +14,7 @@ namespace Upp {
// 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[2][1]; // only single global Huge heap...
BlkHeader_<4096> HugeHeapDetail::freelist[20][1]; // only single global Huge heap...
Heap::HugePage *Heap::huge_pages;
#ifdef LSTAT
@ -58,17 +58,19 @@ void *Heap::HugeAlloc(size_t count) // count in 4kb pages
#endif
huge_4KB_count += count;
if(huge_4KB_count > huge_4KB_count_max) {
huge_4KB_count_max = huge_4KB_count;
if(MemoryUsedKb() > sKBLimit)
Panic("MemoryLimitKb breached!");
if(sPeak)
Make(*sPeak);
}
auto MaxMem = [&] {
if(huge_4KB_count > huge_4KB_count_max) {
huge_4KB_count_max = huge_4KB_count;
if(MemoryUsedKb() > sKBLimit)
Panic("MemoryLimitKb breached!");
if(sPeak)
Make(*sPeak);
}
};
if(!D::freelist[0]->next) { // initialization
for(int i = 0; i < 2; i++)
for(int i = 0; i < __countof(D::freelist); i++)
Dbl_Self(D::freelist[i]);
}
@ -80,6 +82,7 @@ void *Heap::HugeAlloc(size_t count) // count in 4kb pages
*((size_t *)sysblk) = count;
sys_count++;
sys_size += 4096 * count;
MaxMem();
return h;
}
@ -91,13 +94,16 @@ void *Heap::HugeAlloc(size_t count) // count in 4kb pages
FreeSmallEmpty(INT_MAX, int(free_4KB - huge_4KB_count / 32));
for(int pass = 0; pass < 2; pass++) {
for(int i = count >= 16; i < 2; i++) {
for(int i = Cv(count); i < __countof(D::freelist); i++) {
BlkHeader *l = D::freelist[i];
BlkHeader *h = l->next;
while(h != l) {
word sz = h->GetSize();
if(sz >= count)
return MakeAlloc(h, wcount);
if(sz >= count) {
void *ptr = MakeAlloc(h, wcount);
MaxMem();
return ptr;
}
h = h->next;
}
}

View file

@ -135,7 +135,7 @@ void Heap::LFree(void *ptr)
if(h->heap == NULL) { // this is big block
LTIMING("Big Free");
DLink *d = (DLink *)h - 1;
big_size -= h->size;
big_size -= d->size;
big_count--;
d->Unlink();
LLOG("Big free " << (void *) ptr << " size " << h->size);
@ -182,9 +182,9 @@ bool Heap::TryRealloc(void *ptr, size_t& newsize)
size_t count = (newsize + sizeof(DLink) + sizeof(BlkPrefix) + 4095) >> 12;
if(HugeTryRealloc(d, count)) {
big_size -= h->size;
big_size -= d->size;
d->size = newsize = (count << 12) - sizeof(DLink) - sizeof(BlkPrefix);
big_size += h->size;
big_size += d->size;
return true;
}
}

View file

@ -465,6 +465,11 @@ MemoryProfile::MemoryProfile()
ThreadHeap()->Make(*this);
}
void MemoryDump()
{
ThreadHeap()->Dump();
}
#endif
}

View file

@ -124,7 +124,8 @@ mainconfig
"" = "GUI MT X11",
"" = "GUI MT NOGTK",
"" = "GUI NOGTK",
"" = "GUI MT TEST_HIDPI";
"" = "GUI MT TEST_HIDPI",
"" = "GUI PEAKMEM";
custom() "",
"ASDFASDFASDF",

View file

@ -124,6 +124,10 @@ void AppMain___()
{
// Ctrl::ShowRepaint(50);
#ifdef flagPEAKMEM
PeakMemoryProfile();
#endif
Logi() << UPP_FUNCTION_NAME << "(): " << SplashCtrl::GenerateVersionInfo(' ');
Ctrl::SetUHDEnabled();
@ -331,3 +335,11 @@ void AppMain___()
#endif
#endif
}
#ifdef flagPEAKMEM
EXITBLOCK {
RDUMP(*PeakMemoryProfile());
RDUMP(MemoryProfile());
MemoryDump();
}
#endif