diff --git a/uppsrc/CodeEditor/CInit.cpp b/uppsrc/CodeEditor/CInit.cpp index 31f1b57e3..cd682f0d0 100644 --- a/uppsrc/CodeEditor/CInit.cpp +++ b/uppsrc/CodeEditor/CInit.cpp @@ -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", diff --git a/uppsrc/Core/Heap.h b/uppsrc/Core/Heap.h index 11085270d..ad995b179 100644 --- a/uppsrc/Core/Heap.h +++ b/uppsrc/Core/Heap.h @@ -11,6 +11,7 @@ void *MemoryAlloc48(); void MemoryFree48(void *ptr); void MemoryFreeThread(); void MemoryCheck(); +void MemoryDump(); int MemoryUsedKb(); int MemoryUsedKbMax(); void MemoryLimitKb(int kb); diff --git a/uppsrc/Core/HeapImp.h b/uppsrc/Core/HeapImp.h index 3c43e81d6..8dbda627a 100644 --- a/uppsrc/Core/HeapImp.h +++ b/uppsrc/Core/HeapImp.h @@ -254,10 +254,18 @@ typename BlkHeap::BlkHeader *BlkHeap::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 { @@ -269,6 +277,7 @@ struct Heap : BlkHeap { #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 { }; struct LargeHeapDetail { - BlkHeader_ freelist[6][1]; // <1KB, <2KB, <4KB, <8KB, >= 8KB - static int Cv(int n) { return min(n >> 2, 4); } +// BlkHeader_ freelist[6][1]; // <1KB, <2KB, <4KB, <8KB, >= 8KB +// static int Cv(int n) { return min(n >> 2, 4); } + + BlkHeader_ freelist[LCVCOUNT][1]; + static int Cv(int n) { return SignificantBits(n); } void Free64KB(BlkHeader_ *h); void LinkFree(BlkHeader_ *h) { @@ -431,6 +443,7 @@ struct Heap : BlkHeap { size_t LGetBlockSize(void *ptr); void Make(MemoryProfile& f); + void Dump(); static void Shrink(); diff --git a/uppsrc/Core/Ops.h b/uppsrc/Core/Ops.h index d56453c7b..5e913ec7f 100644 --- a/uppsrc/Core/Ops.h +++ b/uppsrc/Core/Ops.h @@ -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 +} diff --git a/uppsrc/Core/heaputil.cpp b/uppsrc/Core/heaputil.cpp index a2e3cd806..1702e9822 100644 --- a/uppsrc/Core/heaputil.cpp +++ b/uppsrc/Core/heaputil.cpp @@ -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"; diff --git a/uppsrc/Core/hheap.cpp b/uppsrc/Core/hheap.cpp index 5d57a810c..0f6430cf5 100644 --- a/uppsrc/Core/hheap.cpp +++ b/uppsrc/Core/hheap.cpp @@ -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; } } diff --git a/uppsrc/Core/lheap.cpp b/uppsrc/Core/lheap.cpp index d4d04eebf..61857c0a5 100644 --- a/uppsrc/Core/lheap.cpp +++ b/uppsrc/Core/lheap.cpp @@ -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; } } diff --git a/uppsrc/Core/sheap.cpp b/uppsrc/Core/sheap.cpp index d7457b601..72edbe7c2 100644 --- a/uppsrc/Core/sheap.cpp +++ b/uppsrc/Core/sheap.cpp @@ -465,6 +465,11 @@ MemoryProfile::MemoryProfile() ThreadHeap()->Make(*this); } +void MemoryDump() +{ + ThreadHeap()->Dump(); +} + #endif } diff --git a/uppsrc/ide/ide.upp b/uppsrc/ide/ide.upp index 7d0c6e850..0979ad5da 100644 --- a/uppsrc/ide/ide.upp +++ b/uppsrc/ide/ide.upp @@ -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", diff --git a/uppsrc/ide/main.cpp b/uppsrc/ide/main.cpp index abaadb24d..fb046b085 100644 --- a/uppsrc/ide/main.cpp +++ b/uppsrc/ide/main.cpp @@ -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