Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 3228441

Browse files
authored
Merge pull request #2430 from rainers/gc_opt_sweep2
GC: keep track of the size of contiguous free pages to avoid loops merged-on-behalf-of: Nicholas Wilson <thewilsonator@users.noreply.github.com>
2 parents 3aef0c7 + 59aaec6 commit 3228441

File tree

1 file changed

+158
-73
lines changed
  • src/gc/impl/conservative

1 file changed

+158
-73
lines changed

src/gc/impl/conservative/gc.d

Lines changed: 158 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -651,42 +651,53 @@ class ConservativeGC : GC
651651
{
652652
auto lpool = cast(LargeObjectPool*) pool;
653653
auto paligned = cast(void*)(cast(size_t)p & ~(PAGESIZE - 1)); // abused by std.file.readImpl
654-
auto pagenum = lpool.pagenumOf(paligned);
655654
auto psz = lpool.getPages(paligned); // get allocated size
656-
psize = psz * PAGESIZE;
657655

658656
if (size <= PAGESIZE / 2)
657+
{
658+
psize = psz * PAGESIZE;
659659
goto Lmalloc; // switching from large object pool to small object pool
660-
660+
}
661661
auto newsz = lpool.numPages(size);
662662
if (newsz == psz)
663663
{
664664
alloc_size = psize;
665665
return p;
666666
}
667667

668+
auto pagenum = lpool.pagenumOf(p);
669+
668670
if (newsz < psz)
669671
{ // Shrink in place
670672
debug (MEMSTOMP) memset(p + size, 0xF2, psize - size);
671673
lpool.freePages(pagenum + newsz, psz - newsz);
674+
lpool.mergeFreePageOffsets!(false, true)(pagenum + newsz, psz - newsz);
675+
lpool.bPageOffsets[pagenum] = cast(uint) newsz;
672676
}
673677
else if (pagenum + newsz <= pool.npages)
674678
{ // Attempt to expand in place
675-
foreach (binsz; lpool.pagetable[pagenum + psz .. pagenum + newsz])
676-
if (binsz != B_FREE)
677-
goto Lmalloc;
679+
if (lpool.pagetable[pagenum + psz] != B_FREE)
680+
goto Lmalloc;
681+
auto newPages = newsz - psz;
682+
auto freesz = lpool.bPageOffsets[pagenum + psz];
683+
if (freesz < newPages)
684+
goto Lmalloc;
678685

679686
debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize);
680687
debug(PRINTF) printFreeInfo(pool);
681-
memset(&lpool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
682-
gcx.usedLargePages += newsz - psz;
683-
lpool.freepages -= (newsz - psz);
688+
memset(&lpool.pagetable[pagenum + psz], B_PAGEPLUS, newPages);
689+
lpool.bPageOffsets[pagenum] = cast(uint) newsz;
690+
for (auto offset = psz + 1; offset < newsz; offset++)
691+
lpool.bPageOffsets[pagenum + offset] = cast(uint) offset;
692+
if (freesz > newPages)
693+
lpool.setFreePageOffsets(pagenum + newsz, freesz - newPages);
694+
gcx.usedLargePages += newPages;
695+
lpool.freepages -= newPages;
684696
debug(PRINTF) printFreeInfo(pool);
685697
}
686698
else
687699
goto Lmalloc; // does not fit into current pool
688700

689-
lpool.updateOffsets(pagenum);
690701
if (bits)
691702
{
692703
immutable biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy;
@@ -759,30 +770,32 @@ class ConservativeGC : GC
759770
return 0;
760771

761772
auto lpool = cast(LargeObjectPool*) pool;
762-
auto pagenum = lpool.pagenumOf(p);
773+
size_t pagenum = lpool.pagenumOf(p);
763774
if (lpool.pagetable[pagenum] != B_PAGE)
764775
return 0;
765-
auto psz = lpool.bPageOffsets[pagenum]; // get allocated pages
776+
777+
size_t psz = lpool.bPageOffsets[pagenum];
778+
assert(psz > 0);
779+
766780
auto minsz = lpool.numPages(minsize);
767781
auto maxsz = lpool.numPages(maxsize);
768782

769-
size_t sz;
770-
for (sz = 0; sz < maxsz; sz++)
771-
{
772-
auto i = pagenum + psz + sz;
773-
if (i == lpool.npages)
774-
break;
775-
if (lpool.pagetable[i] != B_FREE)
776-
{ if (sz < minsz)
777-
return 0;
778-
break;
779-
}
780-
}
781-
if (sz < minsz)
783+
if (pagenum + psz >= lpool.npages)
784+
return 0;
785+
if (lpool.pagetable[pagenum + psz] != B_FREE)
786+
return 0;
787+
788+
size_t freesz = lpool.bPageOffsets[pagenum + psz];
789+
if (freesz < minsz)
782790
return 0;
791+
size_t sz = freesz > maxsz ? maxsz : freesz;
783792
debug (MEMSTOMP) memset(pool.baseAddr + (pagenum + psz) * PAGESIZE, 0xF0, sz * PAGESIZE);
784793
memset(lpool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
785-
lpool.updateOffsets(pagenum);
794+
lpool.bPageOffsets[pagenum] = cast(uint) (psz + sz);
795+
for (auto offset = psz; offset < psz + sz; offset++)
796+
lpool.bPageOffsets[pagenum + offset] = cast(uint) offset;
797+
if (freesz > sz)
798+
lpool.setFreePageOffsets(pagenum + psz + sz, freesz - sz);
786799
lpool.freepages -= sz;
787800
gcx.usedLargePages += sz;
788801
return (psz + sz) * PAGESIZE;
@@ -871,6 +884,7 @@ class ConservativeGC : GC
871884
size_t npages = lpool.bPageOffsets[pagenum];
872885
debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE);
873886
lpool.freePages(pagenum, npages);
887+
lpool.mergeFreePageOffsets!(true, true)(pagenum, npages);
874888
}
875889
else
876890
{
@@ -1793,12 +1807,7 @@ struct Gcx
17931807
assert(pool);
17941808

17951809
debug(PRINTF) printFreeInfo(&pool.base);
1796-
pool.pagetable[pn] = B_PAGE;
1797-
if (npages > 1)
1798-
memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
1799-
pool.updateOffsets(pn);
18001810
usedLargePages += npages;
1801-
pool.freepages -= npages;
18021811

18031812
debug(PRINTF) printFreeInfo(&pool.base);
18041813

@@ -2183,10 +2192,19 @@ struct Gcx
21832192

21842193
if (pool.isLargeObject)
21852194
{
2186-
for (pn = 0; pn < pool.npages; pn++)
2195+
auto lpool = cast(LargeObjectPool*)pool;
2196+
size_t numFree = 0;
2197+
size_t npages;
2198+
for (pn = 0; pn < pool.npages; pn += npages)
21872199
{
2200+
npages = pool.bPageOffsets[pn];
21882201
Bins bin = cast(Bins)pool.pagetable[pn];
2189-
if (bin > B_PAGE) continue;
2202+
if (bin == B_FREE)
2203+
{
2204+
numFree += npages;
2205+
continue;
2206+
}
2207+
assert(bin == B_PAGE);
21902208
size_t biti = pn;
21912209

21922210
if (!pool.mark.test(biti))
@@ -2197,7 +2215,7 @@ struct Gcx
21972215

21982216
if (pool.finals.nbits && pool.finals.clear(biti))
21992217
{
2200-
size_t size = pool.bPageOffsets[pn] * PAGESIZE - SENTINEL_EXTRA;
2218+
size_t size = npages * PAGESIZE - SENTINEL_EXTRA;
22012219
uint attr = pool.getBits(biti);
22022220
rt_finalizeFromGC(q, sentinel_size(q, size), attr);
22032221
}
@@ -2206,32 +2224,30 @@ struct Gcx
22062224

22072225
debug(COLLECT_PRINTF) printf("\tcollecting big %p\n", p);
22082226
log_free(q);
2209-
pool.pagetable[pn] = B_FREE;
2227+
pool.pagetable[pn..pn+npages] = B_FREE;
22102228
if (pn < pool.searchStart) pool.searchStart = pn;
2211-
freedLargePages++;
2212-
pool.freepages++;
2229+
freedLargePages += npages;
2230+
pool.freepages += npages;
2231+
numFree += npages;
22132232

2214-
debug (MEMSTOMP) memset(p, 0xF3, PAGESIZE);
2215-
while (pn + 1 < pool.npages && pool.pagetable[pn + 1] == B_PAGEPLUS)
2216-
{
2217-
pn++;
2218-
pool.pagetable[pn] = B_FREE;
2219-
2220-
// Don't need to update searchStart here because
2221-
// pn is guaranteed to be greater than last time
2222-
// we updated it.
2223-
2224-
pool.freepages++;
2225-
freedLargePages++;
2233+
debug (MEMSTOMP) memset(p, 0xF3, npages * PAGESIZE);
2234+
// Don't need to update searchStart here because
2235+
// pn is guaranteed to be greater than last time
2236+
// we updated it.
22262237

2227-
debug (MEMSTOMP)
2228-
{ p += PAGESIZE;
2229-
memset(p, 0xF3, PAGESIZE);
2230-
}
2231-
}
22322238
pool.largestFree = pool.freepages; // invalidate
22332239
}
2240+
else
2241+
{
2242+
if (numFree > 0)
2243+
{
2244+
lpool.setFreePageOffsets(pn - numFree, numFree);
2245+
numFree = 0;
2246+
}
2247+
}
22342248
}
2249+
if (numFree > 0)
2250+
lpool.setFreePageOffsets(pn - numFree, numFree);
22352251
}
22362252
else
22372253
{
@@ -2644,6 +2660,9 @@ struct Pool
26442660
// a smaller address than a B_PAGEPLUS. To save space, we use a uint.
26452661
// This limits individual allocations to 16 terabytes, assuming a 4k
26462662
// pagesize.
2663+
// For B_PAGE and B_FREE, this specifies the number of pages in this block.
2664+
// As an optimization, a contiguous range of free pages tracks this information
2665+
// only for the first and the last page.
26472666
uint* bPageOffsets;
26482667

26492668
// This variable tracks a conservative estimate of where the first free
@@ -2696,11 +2715,14 @@ struct Pool
26962715
if (!pagetable)
26972716
onOutOfMemoryErrorNoGC();
26982717

2699-
if (isLargeObject)
2718+
if (isLargeObject && npages > 0)
27002719
{
27012720
bPageOffsets = cast(uint*)cstdlib.malloc(npages * uint.sizeof);
27022721
if (!bPageOffsets)
27032722
onOutOfMemoryErrorNoGC();
2723+
2724+
bPageOffsets[0] = cast(uint)npages;
2725+
bPageOffsets[npages-1] = cast(uint)npages;
27042726
}
27052727

27062728
memset(pagetable, B_FREE, npages);
@@ -2735,7 +2757,10 @@ struct Pool
27352757
}
27362758

27372759
if (bPageOffsets)
2760+
{
27382761
cstdlib.free(bPageOffsets);
2762+
bPageOffsets = null;
2763+
}
27392764

27402765
mark.Dtor();
27412766
if (isLargeObject)
@@ -3003,18 +3028,35 @@ struct LargeObjectPool
30033028
Pool base;
30043029
alias base this;
30053030

3006-
void updateOffsets(size_t fromWhere) nothrow
3031+
debug(INVARIANT)
3032+
void Invariant()
30073033
{
3008-
assert(pagetable[fromWhere] == B_PAGE);
3009-
size_t pn = fromWhere + 1;
3010-
for (uint offset = 1; pn < npages; pn++, offset++)
3034+
//base.Invariant();
3035+
for (size_t n = 0; n < npages; )
30113036
{
3012-
if (pagetable[pn] != B_PAGEPLUS) break;
3013-
bPageOffsets[pn] = offset;
3014-
}
3037+
uint np = bPageOffsets[n];
3038+
assert(np > 0 && np <= npages - n);
30153039

3016-
// Store the size of the block in bPageOffsets[fromWhere].
3017-
bPageOffsets[fromWhere] = cast(uint) (pn - fromWhere);
3040+
if (pagetable[n] == B_PAGE)
3041+
{
3042+
for (uint p = 1; p < np; p++)
3043+
{
3044+
assert(pagetable[n + p] == B_PAGEPLUS);
3045+
assert(bPageOffsets[n + p] == p);
3046+
}
3047+
}
3048+
else if (pagetable[n] == B_FREE)
3049+
{
3050+
for (uint p = 1; p < np; p++)
3051+
{
3052+
assert(pagetable[n + p] == B_FREE);
3053+
}
3054+
assert(bPageOffsets[n + np - 1] == np);
3055+
}
3056+
else
3057+
assert(false);
3058+
n += np;
3059+
}
30183060
}
30193061

30203062
/**
@@ -3039,13 +3081,27 @@ struct LargeObjectPool
30393081
for (size_t i = searchStart; i < npages; )
30403082
{
30413083
assert(pagetable[i] == B_FREE);
3042-
size_t p = 1;
3043-
while (p < n && i + p < npages && pagetable[i + p] == B_FREE)
3044-
p++;
30453084

3085+
auto p = bPageOffsets[i];
3086+
if (p > n)
3087+
{
3088+
setFreePageOffsets(i + n, p - n);
3089+
goto L_found;
3090+
}
30463091
if (p == n)
3092+
{
3093+
L_found:
3094+
pagetable[i] = B_PAGE;
3095+
bPageOffsets[i] = cast(uint) n;
3096+
if (n > 1)
3097+
{
3098+
memset(&pagetable[i + 1], B_PAGEPLUS, n - 1);
3099+
for (auto offset = 1; offset < n; offset++)
3100+
bPageOffsets[i + offset] = cast(uint) offset;
3101+
}
3102+
freepages -= n;
30473103
return i;
3048-
3104+
}
30493105
if (p > largest)
30503106
largest = p;
30513107

@@ -3073,16 +3129,44 @@ struct LargeObjectPool
30733129

30743130
for (size_t i = pagenum; i < npages + pagenum; i++)
30753131
{
3076-
if (pagetable[i] < B_FREE)
3077-
{
3078-
freepages++;
3079-
}
3080-
3132+
assert(pagetable[i] < B_FREE);
30813133
pagetable[i] = B_FREE;
30823134
}
3135+
freepages += npages;
30833136
largestFree = freepages; // invalidate
30843137
}
30853138

3139+
/**
3140+
* Set the first and the last entry of a B_FREE block to the size
3141+
*/
3142+
void setFreePageOffsets(size_t page, size_t num) nothrow @nogc
3143+
{
3144+
assert(pagetable[page] == B_FREE);
3145+
assert(pagetable[page + num - 1] == B_FREE);
3146+
bPageOffsets[page] = cast(uint)num;
3147+
if (num > 1)
3148+
bPageOffsets[page + num - 1] = cast(uint)num;
3149+
}
3150+
3151+
void mergeFreePageOffsets(bool bwd, bool fwd)(size_t page, size_t num) nothrow @nogc
3152+
{
3153+
static if (bwd)
3154+
{
3155+
if (page > 0 && pagetable[page - 1] == B_FREE)
3156+
{
3157+
auto sz = bPageOffsets[page - 1];
3158+
page -= sz;
3159+
num += sz;
3160+
}
3161+
}
3162+
static if (fwd)
3163+
{
3164+
if (page + num < npages && pagetable[page + num] == B_FREE)
3165+
num += bPageOffsets[page + num];
3166+
}
3167+
setFreePageOffsets(page, num);
3168+
}
3169+
30863170
/**
30873171
* Get pages of allocation at pointer p in pool.
30883172
*/
@@ -3169,6 +3253,7 @@ struct LargeObjectPool
31693253
break;
31703254
debug (MEMSTOMP) memset(baseAddr + pn * PAGESIZE, 0xF3, n * PAGESIZE);
31713255
freePages(pn, n);
3256+
mergeFreePageOffsets!(true, true)(pn, n);
31723257
}
31733258
}
31743259
}

0 commit comments

Comments
 (0)