@@ -651,42 +651,53 @@ class ConservativeGC : GC
651
651
{
652
652
auto lpool = cast (LargeObjectPool* ) pool;
653
653
auto paligned = cast (void * )(cast (size_t )p & ~ (PAGESIZE - 1 )); // abused by std.file.readImpl
654
- auto pagenum = lpool.pagenumOf(paligned);
655
654
auto psz = lpool.getPages(paligned); // get allocated size
656
- psize = psz * PAGESIZE ;
657
655
658
656
if (size <= PAGESIZE / 2 )
657
+ {
658
+ psize = psz * PAGESIZE ;
659
659
goto Lmalloc; // switching from large object pool to small object pool
660
-
660
+ }
661
661
auto newsz = lpool.numPages(size);
662
662
if (newsz == psz)
663
663
{
664
664
alloc_size = psize;
665
665
return p;
666
666
}
667
667
668
+ auto pagenum = lpool.pagenumOf(p);
669
+
668
670
if (newsz < psz)
669
671
{ // Shrink in place
670
672
debug (MEMSTOMP ) memset(p + size, 0xF2 , psize - size);
671
673
lpool.freePages(pagenum + newsz, psz - newsz);
674
+ lpool.mergeFreePageOffsets! (false , true )(pagenum + newsz, psz - newsz);
675
+ lpool.bPageOffsets[pagenum] = cast (uint ) newsz;
672
676
}
673
677
else if (pagenum + newsz <= pool.npages)
674
678
{ // 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;
678
685
679
686
debug (MEMSTOMP ) memset(p + psize, 0xF0 , size - psize);
680
687
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;
684
696
debug (PRINTF ) printFreeInfo(pool);
685
697
}
686
698
else
687
699
goto Lmalloc; // does not fit into current pool
688
700
689
- lpool.updateOffsets(pagenum);
690
701
if (bits)
691
702
{
692
703
immutable biti = cast (size_t )(p - pool.baseAddr) >> pool.shiftBy;
@@ -759,30 +770,32 @@ class ConservativeGC : GC
759
770
return 0 ;
760
771
761
772
auto lpool = cast (LargeObjectPool* ) pool;
762
- auto pagenum = lpool.pagenumOf(p);
773
+ size_t pagenum = lpool.pagenumOf(p);
763
774
if (lpool.pagetable[pagenum] != B_PAGE )
764
775
return 0 ;
765
- auto psz = lpool.bPageOffsets[pagenum]; // get allocated pages
776
+
777
+ size_t psz = lpool.bPageOffsets[pagenum];
778
+ assert (psz > 0 );
779
+
766
780
auto minsz = lpool.numPages(minsize);
767
781
auto maxsz = lpool.numPages(maxsize);
768
782
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)
782
790
return 0 ;
791
+ size_t sz = freesz > maxsz ? maxsz : freesz;
783
792
debug (MEMSTOMP ) memset(pool.baseAddr + (pagenum + psz) * PAGESIZE , 0xF0 , sz * PAGESIZE );
784
793
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);
786
799
lpool.freepages -= sz;
787
800
gcx.usedLargePages += sz;
788
801
return (psz + sz) * PAGESIZE ;
@@ -871,6 +884,7 @@ class ConservativeGC : GC
871
884
size_t npages = lpool.bPageOffsets[pagenum];
872
885
debug (MEMSTOMP ) memset(p, 0xF2 , npages * PAGESIZE );
873
886
lpool.freePages(pagenum, npages);
887
+ lpool.mergeFreePageOffsets! (true , true )(pagenum, npages);
874
888
}
875
889
else
876
890
{
@@ -1793,12 +1807,7 @@ struct Gcx
1793
1807
assert (pool);
1794
1808
1795
1809
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);
1800
1810
usedLargePages += npages;
1801
- pool.freepages -= npages;
1802
1811
1803
1812
debug (PRINTF ) printFreeInfo(&pool.base);
1804
1813
@@ -2183,10 +2192,19 @@ struct Gcx
2183
2192
2184
2193
if (pool.isLargeObject)
2185
2194
{
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)
2187
2199
{
2200
+ npages = pool.bPageOffsets[pn];
2188
2201
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 );
2190
2208
size_t biti = pn;
2191
2209
2192
2210
if (! pool.mark.test(biti))
@@ -2197,7 +2215,7 @@ struct Gcx
2197
2215
2198
2216
if (pool.finals.nbits && pool.finals.clear(biti))
2199
2217
{
2200
- size_t size = pool.bPageOffsets[pn] * PAGESIZE - SENTINEL_EXTRA ;
2218
+ size_t size = npages * PAGESIZE - SENTINEL_EXTRA ;
2201
2219
uint attr = pool.getBits(biti);
2202
2220
rt_finalizeFromGC(q, sentinel_size (q, size), attr);
2203
2221
}
@@ -2206,32 +2224,30 @@ struct Gcx
2206
2224
2207
2225
debug (COLLECT_PRINTF ) printf(" \t collecting big %p\n " , p);
2208
2226
log_free(q);
2209
- pool.pagetable[pn] = B_FREE ;
2227
+ pool.pagetable[pn.. pn + npages ] = B_FREE ;
2210
2228
if (pn < pool.searchStart) pool.searchStart = pn;
2211
- freedLargePages++ ;
2212
- pool.freepages++ ;
2229
+ freedLargePages += npages;
2230
+ pool.freepages += npages;
2231
+ numFree += npages;
2213
2232
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.
2226
2237
2227
- debug (MEMSTOMP )
2228
- { p += PAGESIZE ;
2229
- memset(p, 0xF3 , PAGESIZE );
2230
- }
2231
- }
2232
2238
pool.largestFree = pool.freepages; // invalidate
2233
2239
}
2240
+ else
2241
+ {
2242
+ if (numFree > 0 )
2243
+ {
2244
+ lpool.setFreePageOffsets(pn - numFree, numFree);
2245
+ numFree = 0 ;
2246
+ }
2247
+ }
2234
2248
}
2249
+ if (numFree > 0 )
2250
+ lpool.setFreePageOffsets(pn - numFree, numFree);
2235
2251
}
2236
2252
else
2237
2253
{
@@ -2644,6 +2660,9 @@ struct Pool
2644
2660
// a smaller address than a B_PAGEPLUS. To save space, we use a uint.
2645
2661
// This limits individual allocations to 16 terabytes, assuming a 4k
2646
2662
// 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.
2647
2666
uint * bPageOffsets;
2648
2667
2649
2668
// This variable tracks a conservative estimate of where the first free
@@ -2696,11 +2715,14 @@ struct Pool
2696
2715
if (! pagetable)
2697
2716
onOutOfMemoryErrorNoGC();
2698
2717
2699
- if (isLargeObject)
2718
+ if (isLargeObject && npages > 0 )
2700
2719
{
2701
2720
bPageOffsets = cast (uint * )cstdlib.malloc(npages * uint .sizeof);
2702
2721
if (! bPageOffsets)
2703
2722
onOutOfMemoryErrorNoGC();
2723
+
2724
+ bPageOffsets[0 ] = cast (uint )npages;
2725
+ bPageOffsets[npages- 1 ] = cast (uint )npages;
2704
2726
}
2705
2727
2706
2728
memset(pagetable, B_FREE , npages);
@@ -2735,7 +2757,10 @@ struct Pool
2735
2757
}
2736
2758
2737
2759
if (bPageOffsets)
2760
+ {
2738
2761
cstdlib.free(bPageOffsets);
2762
+ bPageOffsets = null ;
2763
+ }
2739
2764
2740
2765
mark.Dtor();
2741
2766
if (isLargeObject)
@@ -3003,18 +3028,35 @@ struct LargeObjectPool
3003
3028
Pool base;
3004
3029
alias base this ;
3005
3030
3006
- void updateOffsets (size_t fromWhere) nothrow
3031
+ debug (INVARIANT )
3032
+ void Invariant ()
3007
3033
{
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; )
3011
3036
{
3012
- if (pagetable[pn] != B_PAGEPLUS ) break ;
3013
- bPageOffsets[pn] = offset;
3014
- }
3037
+ uint np = bPageOffsets[n];
3038
+ assert (np > 0 && np <= npages - n);
3015
3039
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
+ }
3018
3060
}
3019
3061
3020
3062
/**
@@ -3039,13 +3081,27 @@ struct LargeObjectPool
3039
3081
for (size_t i = searchStart; i < npages; )
3040
3082
{
3041
3083
assert (pagetable[i] == B_FREE );
3042
- size_t p = 1 ;
3043
- while (p < n && i + p < npages && pagetable[i + p] == B_FREE )
3044
- p++ ;
3045
3084
3085
+ auto p = bPageOffsets[i];
3086
+ if (p > n)
3087
+ {
3088
+ setFreePageOffsets(i + n, p - n);
3089
+ goto L_found;
3090
+ }
3046
3091
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;
3047
3103
return i;
3048
-
3104
+ }
3049
3105
if (p > largest)
3050
3106
largest = p;
3051
3107
@@ -3073,16 +3129,44 @@ struct LargeObjectPool
3073
3129
3074
3130
for (size_t i = pagenum; i < npages + pagenum; i++ )
3075
3131
{
3076
- if (pagetable[i] < B_FREE )
3077
- {
3078
- freepages++ ;
3079
- }
3080
-
3132
+ assert (pagetable[i] < B_FREE );
3081
3133
pagetable[i] = B_FREE ;
3082
3134
}
3135
+ freepages += npages;
3083
3136
largestFree = freepages; // invalidate
3084
3137
}
3085
3138
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
+
3086
3170
/**
3087
3171
* Get pages of allocation at pointer p in pool.
3088
3172
*/
@@ -3169,6 +3253,7 @@ struct LargeObjectPool
3169
3253
break ;
3170
3254
debug (MEMSTOMP ) memset(baseAddr + pn * PAGESIZE , 0xF3 , n * PAGESIZE );
3171
3255
freePages(pn, n);
3256
+ mergeFreePageOffsets! (true , true )(pn, n);
3172
3257
}
3173
3258
}
3174
3259
}
0 commit comments