-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resize-in-place for large allocs. (Shrink-only) #289
Merged
Merged
Changes from all commits
Commits
Show all changes
54 commits
Select commit
Hold shift + click to select a range
49640db
first try at resize-in-place for large allocs.
dsm9000 355d5d0
first try at resize-in-place for large allocs. (minor corrections)
dsm9000 f5febbd
first try at resize-in-place for large allocs. (minor corrections)
dsm9000 0ac6d69
corrections.
dsm9000 4b96dad
corrections.
dsm9000 89a46e0
corrections.
dsm9000 94caea2
corrections. (simplify growAlloc)
dsm9000 e9c14c0
corrections. (simplify growAlloc)
dsm9000 e3f2f28
corrections. (misc. cleanup)
dsm9000 1bb3c1f
corrections. (misc. cleanup)
dsm9000 f774cfb
corrections. (misc. cleanup)
dsm9000 906de70
corrections. (misc. cleanup)
dsm9000 4cee257
corrections. (misc. cleanup)
dsm9000 8a05ead
corrections. (tests)
dsm9000 0f52ff2
corrections. (simplify growAlloc.)
dsm9000 34a1a53
corrections. (simplify growAlloc.)
dsm9000 d43335a
corrections. (simplify growAlloc.)
dsm9000 816c7c7
corrections. (asserts)
dsm9000 91b215c
corrections. (asserts)
dsm9000 9b3c652
uglier but faster growAlloc()
dsm9000 717e975
tmp
dsm9000 04f9bc0
cut-down version where resizeLarge() supports only shrinking.
dsm9000 9bd10c4
cut-down version where resizeLarge() supports only shrinking.
dsm9000 6e0d589
cut-down version where resizeLarge() supports only shrinking.
dsm9000 b7199f6
shrink corrections.
dsm9000 b5d1b90
Merge branch 'master' of github.com:dsm9000/sdc into resize_in_place
dsm9000 4406d9e
shrink corrections.
dsm9000 f0f41ce
shrink tests with full hpd.
dsm9000 821ae45
shrink tests with full hpd.
dsm9000 3bd87ca
shrink tests with full hpd.
dsm9000 4d0c377
shrink corrections.
dsm9000 5de41f6
unregisterHPD from master
dsm9000 b84107e
unregisterHPD from master
dsm9000 d3bbbd9
unregisterHPD from master
dsm9000 da34634
shrink corrections.
dsm9000 d594054
shrink corrections.
dsm9000 a533477
shrink corrections.
dsm9000 7db00ce
Merge branch 'master' of github.com:dsm9000/sdc into resize_in_place
dsm9000 bc94676
shrink corrections
dsm9000 a4cf611
shrink corrections
dsm9000 7a6f6a6
shrink corrections
dsm9000 946f6d7
shrink corrections
dsm9000 f1b96ca
shrink corrections
dsm9000 ddcbfc9
shrink corrections
dsm9000 491c7a9
shrink corrections
dsm9000 af46b49
shrink corrections
dsm9000 daa5f6e
shrink corrections
dsm9000 cd98c58
assert correction.
dsm9000 42a8b96
Merge branch 'master' of github.com:dsm9000/sdc into resize_in_place
dsm9000 235a70d
use new pageCount feature.
dsm9000 6a74319
Merge branch 'master' of github.com:dsm9000/sdc into resize_in_place
dsm9000 c92b1fe
use hpdIndex
dsm9000 b209967
Merge branch 'master' of github.com:dsm9000/sdc into resize_in_place
dsm9000 8f94b7c
use getPageCount. additional test for realloc.
dsm9000 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -144,6 +144,31 @@ public: | |
return null; | ||
} | ||
|
||
bool resizeLarge(shared(ExtentMap)* emap, Extent* e, size_t size) shared { | ||
assert(e !is null, "Extent is null!"); | ||
assert(e.isLarge(), "Expected a large extent!"); | ||
assert(e.arenaIndex == index, "Invalid arena index!"); | ||
assert(isLargeSize(size)); | ||
|
||
// Huge is not supported: | ||
if (e.isHuge()) { | ||
return false; | ||
} | ||
|
||
import d.gc.size; | ||
uint newPages = getPageCount(size); | ||
uint oldPages = e.pageCount; | ||
|
||
// Growing is not yet supported: | ||
if (newPages >= oldPages) { | ||
return newPages == oldPages; | ||
} | ||
|
||
shrinkAlloc(emap, e, newPages); | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Deallocation facility. | ||
*/ | ||
|
@@ -228,6 +253,31 @@ private: | |
(cast(Arena*) &this).freePagesImpl(e, n, pages); | ||
} | ||
|
||
void shrinkAlloc(shared(ExtentMap)* emap, Extent* e, uint pages) shared { | ||
assert(!e.isHuge(), "Does not support huge!"); | ||
assert(isAligned(e.address, PageSize), "Invalid extent address!"); | ||
assert(isAligned(e.size, PageSize), "Invalid extent size!"); | ||
assert(e.hpd.address is alignDown(e.address, HugePageSize), | ||
"Invalid hpd!"); | ||
assert(pages > 0 && pages <= PagesInHugePage, | ||
"Invalid number of pages!"); | ||
|
||
uint currentPages = e.pageCount; | ||
assert(currentPages > pages, "Invalid shrink pages!"); | ||
|
||
uint delta = currentPages - pages; | ||
uint index = e.hpdIndex + pages; | ||
|
||
auto newSize = pages * PageSize; | ||
emap.clear(e.address + newSize, e.size - newSize); | ||
|
||
mutex.lock(); | ||
scope(exit) mutex.unlock(); | ||
|
||
// Shrink: | ||
(cast(Arena*) &this).shrinkAllocImpl(e, index, pages, delta); | ||
} | ||
|
||
private: | ||
Extent* allocPagesImpl(uint pages, ulong mask, ExtentClass ec) { | ||
assert(mutex.isHeld(), "Mutex not held!"); | ||
|
@@ -323,6 +373,23 @@ private: | |
unusedExtents.insert(e); | ||
} | ||
|
||
void shrinkAllocImpl(Extent* e, uint index, uint pages, uint delta) { | ||
assert(mutex.isHeld(), "Mutex not held!"); | ||
assert(index > 0 && index <= PagesInHugePage - pages, "Invalid index!"); | ||
assert(pages > 0 && pages <= PagesInHugePage, | ||
"Invalid number of pages!"); | ||
assert(delta > 0, "Invalid delta!"); | ||
|
||
auto hpd = e.hpd; | ||
unregisterHPD(hpd); | ||
|
||
e.at(e.address, pages * PageSize, hpd); | ||
hpd.clear(index, delta); | ||
|
||
assert(!hpd.empty); | ||
registerHPD(hpd); | ||
dsm9000 marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+383
to
+390
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is great how clean this became. |
||
} | ||
|
||
/** | ||
* HugePageDescriptor heaps management. | ||
*/ | ||
|
@@ -559,3 +626,137 @@ unittest allocHuge { | |
arena.freePages(e3); | ||
arena.freePages(e4); | ||
} | ||
|
||
unittest resizeLarge { | ||
import d.gc.arena; | ||
shared Arena arena; | ||
|
||
auto base = &arena.base; | ||
scope(exit) arena.base.clear(); | ||
|
||
import d.gc.emap; | ||
static shared ExtentMap emap; | ||
emap.tree.base = base; | ||
|
||
import d.gc.region; | ||
shared RegionAllocator regionAllocator; | ||
regionAllocator.base = base; | ||
|
||
arena.regionAllocator = ®ionAllocator; | ||
|
||
// Allocation 0: 35 pages: | ||
auto ptr0 = arena.allocLarge(&emap, 35 * PageSize); | ||
assert(ptr0 !is null); | ||
auto pd0 = emap.lookup(ptr0); | ||
assert(pd0.extent.address is ptr0); | ||
assert(pd0.extent.size == 35 * PageSize); | ||
auto pd0x = emap.lookup(ptr0); | ||
assert(pd0x.extent.address is ptr0); | ||
|
||
// Allocation 1: 20 pages: | ||
auto ptr1 = arena.allocLarge(&emap, 20 * PageSize); | ||
assert(ptr1 !is null); | ||
assert(ptr1 is ptr0 + 35 * PageSize); | ||
auto pd1 = emap.lookup(ptr1); | ||
assert(pd1.extent.address is ptr1); | ||
assert(pd1.extent.size == 20 * PageSize); | ||
|
||
// Growing by zero is allowed: | ||
assert(arena.resizeLarge(&emap, pd0.extent, 35 * PageSize)); | ||
|
||
// Shrink no. 0 down to 10 pages: | ||
assert(arena.resizeLarge(&emap, pd0.extent, 10 * PageSize)); | ||
assert(pd0.extent.address is ptr0); | ||
assert(pd0.extent.size == 10 * PageSize); | ||
auto pd0xx = emap.lookup(ptr0); | ||
assert(pd0xx.extent.address is ptr0); | ||
|
||
// See that newly-last page is mapped: | ||
auto okpd = emap.lookup(ptr0 + 9 * PageSize); | ||
assert(okpd.extent !is null); | ||
|
||
// But the page after the newly-last one, should not be mapped: | ||
auto badpd = emap.lookup(ptr0 + 10 * PageSize); | ||
assert(badpd.extent is null); | ||
|
||
// Allocate 25 pages + 1 byte, will not fit in the hole after no.0: | ||
auto ptr2 = arena.allocLarge(&emap, 1 + 25 * PageSize); | ||
assert(ptr2 !is null); | ||
auto pd2 = emap.lookup(ptr2); | ||
assert(pd2.extent.address is ptr2); | ||
assert(ptr2 is ptr1 + 20 * PageSize); | ||
|
||
// Now allocate precisely 25 pages. | ||
// This new alloc WILL fit in and fill the free space after no. 0: | ||
auto ptr3 = arena.allocLarge(&emap, 25 * PageSize); | ||
assert(ptr3 !is null); | ||
auto pd3 = emap.lookup(ptr3); | ||
assert(pd3.extent.address is ptr3); | ||
assert(ptr3 is ptr0 + 10 * PageSize); | ||
|
||
arena.free(&emap, pd0, ptr0); | ||
arena.free(&emap, pd1, ptr1); | ||
arena.free(&emap, pd2, ptr2); | ||
arena.free(&emap, pd3, ptr3); | ||
|
||
// Allocate 128 pages: | ||
auto ptr4 = arena.allocLarge(&emap, 128 * PageSize); | ||
assert(ptr4 !is null); | ||
auto pd4 = emap.lookup(ptr4); | ||
assert(pd4.extent.address is ptr4); | ||
|
||
// Allocate 256 pages: | ||
auto ptr5 = arena.allocLarge(&emap, 256 * PageSize); | ||
assert(ptr5 !is null); | ||
auto pd5 = emap.lookup(ptr5); | ||
assert(pd5.extent.address is ptr5); | ||
assert(pd5.extent.hpd == pd4.extent.hpd); | ||
|
||
// Allocate 128 pages, hpd full: | ||
auto ptr6 = arena.allocLarge(&emap, 128 * PageSize); | ||
assert(ptr6 !is null); | ||
auto pd6 = emap.lookup(ptr6); | ||
assert(pd6.extent.address is ptr6); | ||
assert(pd6.extent.hpd == pd5.extent.hpd); | ||
assert(pd6.extent.hpd.full); | ||
|
||
// Shrink first alloc: | ||
assert(arena.resizeLarge(&emap, pd4.extent, 96 * PageSize)); | ||
assert(pd4.extent.size == 96 * PageSize); | ||
assert(!pd6.extent.hpd.full); | ||
|
||
// Shrink second alloc: | ||
assert(arena.resizeLarge(&emap, pd5.extent, 128 * PageSize)); | ||
assert(pd5.extent.size == 128 * PageSize); | ||
|
||
// Shrink third alloc: | ||
assert(arena.resizeLarge(&emap, pd6.extent, 64 * PageSize)); | ||
assert(pd6.extent.size == 64 * PageSize); | ||
|
||
// Allocate 128 pages, should go after second alloc: | ||
auto ptr7 = arena.allocLarge(&emap, 128 * PageSize); | ||
assert(ptr7 !is null); | ||
auto pd7 = emap.lookup(ptr7); | ||
assert(pd7.extent.address is ptr7); | ||
assert(pd7.extent.hpd == pd6.extent.hpd); | ||
assert(ptr7 is ptr5 + 128 * PageSize); | ||
|
||
// Allocate 32 pages, should go after first alloc: | ||
auto ptr8 = arena.allocLarge(&emap, 32 * PageSize); | ||
assert(ptr8 !is null); | ||
auto pd8 = emap.lookup(ptr8); | ||
assert(pd8.extent.address is ptr8); | ||
assert(pd8.extent.hpd == pd7.extent.hpd); | ||
assert(ptr8 is ptr4 + 96 * PageSize); | ||
|
||
// Allocate 64 pages, should go after third alloc: | ||
auto ptr9 = arena.allocLarge(&emap, 64 * PageSize); | ||
assert(ptr9 !is null); | ||
auto pd9 = emap.lookup(ptr9); | ||
assert(pd9.extent.address is ptr9); | ||
assert(pd9.extent.hpd == pd8.extent.hpd); | ||
assert(ptr9 is ptr6 + 64 * PageSize); | ||
|
||
// Now full again: | ||
assert(pd9.extent.hpd.full); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,12 +99,13 @@ public: | |
} | ||
} else { | ||
auto esize = pd.extent.size; | ||
if (samePointerness && alignUp(size, PageSize) == esize) { | ||
if (samePointerness && (alignUp(size, PageSize) == esize | ||
|| (isLargeSize(size) | ||
&& pd.arena.resizeLarge(emap, pd.extent, size)))) { | ||
pd.extent.setUsedCapacity(size); | ||
return ptr; | ||
} | ||
|
||
// TODO: Try to extend/shrink in place. | ||
import d.gc.util; | ||
copySize = min(size, pd.extent.usedCapacity); | ||
} | ||
|
@@ -441,13 +442,19 @@ unittest getCapacity { | |
assert(threadCache.getCapacity(p3[0 .. 20000]) == 0); | ||
assert(threadCache.getCapacity(p3[0 .. 20001]) == 20480); | ||
|
||
// This realloc happens in-place: | ||
auto p4 = threadCache.realloc(p3, 16000, false); | ||
assert(p4 !is p3); | ||
assert(p4 is p3); | ||
assert(threadCache.getCapacity(p4[0 .. 16000]) == 16384); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a test shrink from large to small? |
||
|
||
// This one, not: | ||
auto p5 = threadCache.realloc(p4, 20000, false); | ||
assert(p5 !is p4); | ||
assert(threadCache.getCapacity(p5[0 .. 20000]) == 20480); | ||
|
||
// Realloc from large to small size class results in new allocation: | ||
auto p6 = threadCache.realloc(p5, 100, false); | ||
assert(p6 !is p5); | ||
} | ||
|
||
unittest extend { | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this happen if the isLarge assert pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, please see definition,
isLarge
includes any extent that isn't a slab.