Skip to content

Commit

Permalink
[GC] Only realloc roots on root removal when asked to do so by the GC…
Browse files Browse the repository at this point in the history
… cycle.
  • Loading branch information
schveiguy committed Nov 27, 2024
1 parent af95483 commit 0a8cb2a
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 15 deletions.
2 changes: 2 additions & 0 deletions sdlib/d/gc/collector.d
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ private:
threadCache.flush();

collect(gcCycle);

gState.minimizeRoots();
}

void prepareGCCycle() {
Expand Down
63 changes: 48 additions & 15 deletions sdlib/d/gc/global.d
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ private:
*/
const(void*)[][] roots;

/**
* How many roots elements are valid.
*/
size_t valid;

public:
ubyte nextGCCycle() shared {
auto old = cycle.load();
Expand Down Expand Up @@ -83,18 +88,36 @@ public:
(cast(GCState*) &this).scanRootsImpl(scan);
}

/**
* Tidy up any root structure. This should be called periodically to
* ensure the roots structure does not become too large. Should not be
* called during collection.
*/
void minimizeRoots() shared {
import d.gc.thread;
enterBusyState();
scope(exit) exitBusyState();

mutex.lock();
scope(exit) mutex.unlock();

(cast(GCState*) &this).minimizeRootsImpl();
}

private:
void addRootsImpl(const void[] range) {
assert(mutex.isHeld(), "Mutex not held!");

auto ptr = cast(void*) roots.ptr;
auto index = roots.length;
auto length = index + 1;
auto index = valid;
++valid;

// We realloc every time. It doesn't really matter at this point.
import d.gc.tcache;
ptr = threadCache.realloc(ptr, length * void*[].sizeof, true);
roots = (cast(const(void*)[]*) ptr)[0 .. length];
// If we run out of root space, realloc.
if (valid > roots.length) {
import d.gc.tcache;
ptr = threadCache.realloc(ptr, valid * void*[].sizeof, true);
roots = (cast(const(void*)[]*) ptr)[0 .. valid];
}

import d.gc.range;
if (range.length == 0) {
Expand All @@ -115,28 +138,38 @@ private:
* Search in reverse, since it's most likely for things to be removed
* in the reverse order they were added.
*/
foreach_reverse (i; 0 .. roots.length) {
foreach_reverse (i; 0 .. valid) {
if (cast(void*) roots[i].ptr !is ptr
&& cast(void*) roots[i].ptr !is alignedPtr) {
continue;
}

auto length = roots.length - 1;
roots[i] = roots[length];
roots[length] = [];
--valid;
roots[i] = roots[valid];
roots[valid] = [];

import d.gc.tcache;
auto newRoots =
threadCache.realloc(roots.ptr, length * void*[].sizeof, true);
roots = (cast(const(void*)[]*) newRoots)[0 .. length];
break;
}
}

void minimizeRootsImpl() {
assert(mutex.isHeld(), "Mutex not held!");

if (valid == roots.length) {
// Already minimal.
return;
}

import d.gc.tcache;
auto newRoots =
threadCache.realloc(roots.ptr, valid * void*[].sizeof, true);
roots = (cast(const(void*)[]*) newRoots)[0 .. valid];
}

void scanRootsImpl(ScanDg scan) {
assert(mutex.isHeld(), "Mutex not held!");

foreach (range; roots) {
foreach (range; roots[0 .. valid]) {
/**
* Adding a range of length 0 is like pinning the given range
* address. This is scanned when the roots array itself is scanned
Expand Down

0 comments on commit 0a8cb2a

Please sign in to comment.