mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
411 lines
8.8 KiB
C++
411 lines
8.8 KiB
C++
$uvs: PENDING CONFLICT
|
|
#include <Core/Core.h>
|
|
|
|
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
|