mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
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:
parent
d635502c28
commit
e53932b2f5
10 changed files with 101 additions and 29 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ void *MemoryAlloc48();
|
|||
void MemoryFree48(void *ptr);
|
||||
void MemoryFreeThread();
|
||||
void MemoryCheck();
|
||||
void MemoryDump();
|
||||
int MemoryUsedKb();
|
||||
int MemoryUsedKbMax();
|
||||
void MemoryLimitKb(int kb);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -465,6 +465,11 @@ MemoryProfile::MemoryProfile()
|
|||
ThreadHeap()->Make(*this);
|
||||
}
|
||||
|
||||
void MemoryDump()
|
||||
{
|
||||
ThreadHeap()->Dump();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue