$uvs: PENDING CONFLICT #include using namespace Upp; $uvs: REPOSITORY INSERT void LMemoryCheck() { $uvs: END REPOSITORY INSERT $uvs: REPOSITORY DELETE #define RESERVE_CHUNK 4 * 1024 * 1024 static byte **free_raw64_page; static int free_raw64_alloc; static int free_raw64_count; int sMediumKb; byte *Alloc64KBRaw() { sMediumKb += 64; if(free_raw64_count) { byte *ptr = free_raw64_page[--free_raw64_count]; VirtualAlloc(ptr, 65536, MEM_COMMIT, PAGE_READWRITE); return ptr; } static byte *ptr = NULL; static byte *limit = NULL; if(ptr >= limit) { ptr = (byte *) VirtualAlloc(NULL, RESERVE_CHUNK, MEM_RESERVE, PAGE_READWRITE); limit = ptr + RESERVE_CHUNK; } VirtualAlloc(ptr, 65536, MEM_COMMIT, PAGE_READWRITE); byte *p = ptr; ptr += 65536; return p; } void Free64KBRaw(byte *ptr) { sMediumKb -= 64; if(free_raw64_count >= free_raw64_alloc) { byte **prev = free_raw64_page; if(free_raw64_alloc) free_raw64_alloc *= 2; else free_raw64_alloc = 100000; free_raw64_page = (byte **)malloc(sizeof(byte *) * free_raw64_alloc); if(prev) { memcpy(free_raw64_page, prev, free_raw64_count * sizeof(byte *)); free(prev); } } free_raw64_page[free_raw64_count++] = ptr; VirtualFree(ptr, 65536, MEM_DECOMMIT); } void *AllocBigRaw(size_t size) { return VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); } void FreeBigRaw(void *ptr, size_t size) { VirtualFree(ptr, 0, MEM_RELEASE); } struct MLink; struct MHeader { byte free; byte d1, d2, d3; word size; word prev; MLink *Block() { return (MLink *)(this + 1); } MHeader *Next() { return (MHeader *)((byte *)this + size) + 1; } MHeader *Prev() { return (MHeader *)((byte *)this - prev) - 1; } }; struct MLink { MLink *next; MLink *prev; void LinkSelf() { prev = next = this; } void Unlink() { prev->next = next; next->prev = prev; } void Link(MLink *lnk) { prev = lnk; next = lnk->next; next->prev = this; lnk->next = this; } MHeader *Header() { return (MHeader *)this - 1; } }; #define BINS 113 #define MAXBLOCK 65504 static word BinSz[BINS]; static byte sSzBin[MAXBLOCK / 8 + 1]; static byte sBlBin[MAXBLOCK / 8 + 1]; static MLink freebin[BINS]; static int binaccel[BINS / 8 + 1]; static MLink mall; static MLink ball; void Init() { int p = 24; int bi = 0; while(p < MAXBLOCK) { BinSz[bi++] = p; int add = minmax(6 * p / 100 / 32 * 32, 32, 2048); p += add; } ASSERT(bi == BINS - 1); BinSz[BINS - 1] = MAXBLOCK; int k = 0; for(int i = 0; i <= MAXBLOCK / 8; i++) { while(i * 8 + 7 > BinSz[k]) k++; sSzBin[i] = k; } k = BINS - 1; for(int i = MAXBLOCK / 8; i >= 0; i--) { while(i * 8 < BinSz[k]) k--; sBlBin[i] = k; } sBlBin[0] = 0; for(int i = 0; i < BINS; i++) freebin[i].LinkSelf(); mall.LinkSelf(); ball.LinkSelf(); binaccel[BINS / 8] = 1; } inline int SzBin(int n) { return sSzBin[(n - 1) >> 3]; } inline int BlBin(int n) { return sBlBin[n >> 3]; } void LinkFree(MLink *b, int size) { int q = BlBin(size); b->Link(&freebin[q]); $uvs: YOUR INSERT (REPOSITORY DELETE) // binaccel[q >> 3]++; $uvs: END YOUR INSERT (REPOSITORY DELETE) $uvs: YOUR DELETE (REPOSITORY DELETE) binaccel[q >> 3]++; $uvs: END YOUR DELETE (REPOSITORY DELETE) } MLink *AddChunk() { ASSERT(sizeof(MHeader) == 8); ASSERT(sizeof(MLink) <= 16); MLink *ml = (MLink *)Alloc64KBRaw(); ml->Link(&mall); MHeader *bh = (MHeader *)((byte *)ml + 16); bh->size = MAXBLOCK; bh->prev = 0; bh->free = true; MLink *b = bh->Block(); LinkFree(b, MAXBLOCK); bh = bh->Next(); bh->prev = MAXBLOCK; bh->size = 0; bh->free = false; return b; } void *DivideBlock(MLink *b, int size, int ii) { b->Unlink(); $uvs: YOUR INSERT (REPOSITORY DELETE) // binaccel[ii >> 3]--; $uvs: END YOUR INSERT (REPOSITORY DELETE) $uvs: YOUR DELETE (REPOSITORY DELETE) binaccel[ii >> 3]--; $uvs: END YOUR DELETE (REPOSITORY DELETE) MHeader *bh = b->Header(); ASSERT(bh->size >= size); bh->free = false; int sz2 = bh->size - size - sizeof(MHeader); if(sz2 >= 32) { MHeader *bh2 = (MHeader *)((byte *)b + size); bh2->prev = size; bh2->free = true; LinkFree(bh2->Block(), sz2); bh->Next()->prev = bh2->size = sz2; bh->size = size; } return b; } void *Alloc(size_t size) { static inited; if(!inited) { Init(); inited = true; } if(size > MAXBLOCK) { MLink *b = (MLink *)AllocBigRaw(size + 40); b->Link(&ball); *(size_t *)((byte *)b + 16) = size; MHeader *h = (MHeader *)((byte *)b + 32); h->size = 0; h->free = false; return (byte *)b + 40; } if(size < 256) size = 256; int ii = SzBin(size); size = BinSz[ii]; while(ii < BINS) { /* int q = ii >> 3; if(binaccel[q] == 0) { while(binaccel[q] == 0) q++; ii = q << 3; } else {*/ MLink *b = &freebin[ii]; MLink *n = b->next; if(b != n) return DivideBlock(n, size, ii); ii++; // } } return DivideBlock(AddChunk(), size, BINS - 1); } void Free(void *ptr) { MLink *b = (MLink *)ptr; MHeader *bh = b->Header(); if(bh->size == 0) { ASSERT(((dword)bh & 4095) == 32); b = (MLink *)((byte *)bh - 32); b->Unlink(); FreeBigRaw(b, *(size_t *)((byte *)b + 16)); return; } if(bh->prev) { MHeader *p = bh->Prev(); if(p->free) { b = p->Block(); b->Unlink(); p->size += bh->size + sizeof(MHeader); p->Next()->prev = p->size; bh = p; } } MHeader *n = bh->Next(); if(n->free) { n->Block()->Unlink(); bh->size += n->size + sizeof(MHeader); n->Next()->prev = bh->size; } bh->free = true; LinkFree(b, bh->size); $uvs: END REPOSITORY DELETE } void DumpHeap() { LOG("--------------------------------------------------------"); $uvs: REPOSITORY INSERT LOG("heap"); MLink *m = s_mall.next; while(m != &s_mall) { $uvs: END REPOSITORY INSERT $uvs: REPOSITORY DELETE MLink *m = mall.next; while(m != &mall) { $uvs: END REPOSITORY DELETE MHeader *h = (MHeader *)((byte *)m + 16); while(h->size) { LOG((h->free ? "FREE" : "USED") << " " << h->size); h = h->Next(); } m = m->next; LOG("==========="); } $uvs: REPOSITORY INSERT LOG("......"); $uvs: END REPOSITORY INSERT } void *ptr[8192]; $uvs: REPOSITORY INSERT void *LAlloc(int sz) { size_t s = sz; return LAlloc(s); } $uvs: END REPOSITORY INSERT void Benchmark() { RTIMING("Benchmark"); void *ptr[8192]; $uvs: REPOSITORY INSERT for(int q = 0; q < 20; q++) { for(int i = 0; i < 8192; i++) ptr[i] = LAlloc(2048); for(int i = 0; i < 8192; i++) LFree(ptr[i]); $uvs: END REPOSITORY INSERT $uvs: REPOSITORY DELETE for(int q = 0; q < 2000; q++) { for(int i = 0; i < 8192; i++) ptr[i] = Alloc(2048); for(int i = 0; i < 8192; i++) Free(ptr[i]); $uvs: END REPOSITORY DELETE } } CONSOLE_APP_MAIN { $uvs: REPOSITORY INSERT sLInit(); for(int i = 0; i < BINS; i++) LOG(i << ": " << sBinSz[i]); for(int i = 32; i <= MAXBLOCK; i++) LOG(i << ": bin " << (int)sSzBin(i) << " - " << sBinSz[sSzBin(i)] << ", bl " << (int)sBlBin(i) << " - " << sBinSz[sBlBin(i)]); $uvs: END REPOSITORY INSERT Benchmark(); DumpHeap(); $uvs: REPOSITORY INSERT LMemoryShrink(); DumpHeap(); memset(ptr, 0, sizeof(ptr)); for(int n = 1; n < 5000000; n++) { int q = rand() & 511; if(ptr[q]) LFree(ptr[q]); int sz = 5 * ((rand() & 16383) + 270); ptr[q] = LAlloc(sz); } DumpHeap(); for(int q = 0; q < 512; q++) if(ptr[q]) LFree(ptr[q]); DumpHeap(); LMemoryShrink(); LOG("Final"); DumpHeap(); return; void *p1, *p2, *p3; p1 = LAlloc(500); DumpHeap(); p2 = LAlloc(300); DumpHeap(); p3 = LAlloc(400); DumpHeap(); LFree(p2); DumpHeap(); LFree(p1); DumpHeap(); LFree(p3); DumpHeap(); } $uvs: END REPOSITORY INSERT $uvs: REPOSITORY DELETE return; Init(); for(int i = 0; i < BINS; i++) LOG(i << ": " << BinSz[i]); for(int i = 32; i <= MAXBLOCK; i++) LOG(i << ": bin " << (int)SzBin(i) << " - " << BinSz[SzBin(i)] << ", bl " << (int)BlBin(i) << " - " << BinSz[BlBin(i)]); void *p1, *p2, *p3; p1 = Alloc(500); DumpHeap(); p2 = Alloc(300); DumpHeap(); p3 = Alloc(400); DumpHeap(); Free(p2); DumpHeap(); Free(p1); DumpHeap(); Free(p3); DumpHeap(); memset(ptr, 0, sizeof(ptr)); for(int n = 1; n < 500; n++) { int q = rand() & 63; if(ptr[q]) Free(ptr[q]); DumpHeap(); int sz = (rand() & 16383) + 270; DUMP(sz); ptr[q] = Alloc(sz); DumpHeap(); } for(int q = 0; q < 64; q++) if(ptr[q]) { Free(ptr[q]); DumpHeap(); } } $uvs: END REPOSITORY DELETE