GC improvements; distinguish between thread local and globals in the marking step
This commit is contained in:
parent
ee64dcd728
commit
f71f9f83c2
8 changed files with 129 additions and 128 deletions
|
|
@ -21,10 +21,6 @@ const
|
|||
# reaches this threshold
|
||||
# this seems to be a good value
|
||||
withRealTime = defined(useRealtimeGC)
|
||||
useMarkForDebug = defined(gcGenerational)
|
||||
useBackupGc = true # use a simple M&S GC to collect
|
||||
# cycles instead of the complex
|
||||
# algorithm
|
||||
|
||||
when withRealTime and not declared(getTicks):
|
||||
include "system/timers"
|
||||
|
|
@ -92,14 +88,12 @@ type
|
|||
maxPause: Nanos # max allowed pause in nanoseconds; active if > 0
|
||||
region: MemRegion # garbage collected region
|
||||
stat: GcStat
|
||||
when useMarkForDebug or useBackupGc:
|
||||
marked: CellSet
|
||||
additionalRoots: CellSeq # dummy roots for GC_ref/unref
|
||||
marked: CellSet
|
||||
additionalRoots: CellSeq # dummy roots for GC_ref/unref
|
||||
when hasThreadSupport:
|
||||
toDispose: SharedList[pointer]
|
||||
isMainThread: bool
|
||||
|
||||
{.deprecated: [TWalkOp: WalkOp, TFinalizer: Finalizer, TGcHeap: GcHeap,
|
||||
TGcStat: GcStat].}
|
||||
var
|
||||
gch {.rtlThreadVar.}: GcHeap
|
||||
|
||||
|
|
@ -314,27 +308,11 @@ proc initGC() =
|
|||
init(gch.zct)
|
||||
init(gch.tempStack)
|
||||
init(gch.decStack)
|
||||
when useMarkForDebug or useBackupGc:
|
||||
init(gch.marked)
|
||||
init(gch.additionalRoots)
|
||||
init(gch.marked)
|
||||
init(gch.additionalRoots)
|
||||
when hasThreadSupport:
|
||||
init(gch.toDispose)
|
||||
|
||||
when useMarkForDebug or useBackupGc:
|
||||
type
|
||||
GlobalMarkerProc = proc () {.nimcall, benign.}
|
||||
{.deprecated: [TGlobalMarkerProc: GlobalMarkerProc].}
|
||||
var
|
||||
globalMarkersLen: int
|
||||
globalMarkers: array[0.. 7_000, GlobalMarkerProc]
|
||||
|
||||
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
|
||||
if globalMarkersLen <= high(globalMarkers):
|
||||
globalMarkers[globalMarkersLen] = markerProc
|
||||
inc globalMarkersLen
|
||||
else:
|
||||
echo "[GC] cannot register global variable; too many global variables"
|
||||
quit 1
|
||||
gch.isMainThread = true
|
||||
|
||||
proc cellsetReset(s: var CellSet) =
|
||||
deinit(s)
|
||||
|
|
@ -377,10 +355,10 @@ proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) =
|
|||
else: discard
|
||||
|
||||
proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||
gcAssert(cell != nil, "forAllChildren: 1")
|
||||
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
|
||||
gcAssert(cell.typ != nil, "forAllChildren: 3")
|
||||
gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: 4"
|
||||
gcAssert(cell != nil, "forAllChildren: cell is nil")
|
||||
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: pointer not part of the heap")
|
||||
gcAssert(cell.typ != nil, "forAllChildren: cell.typ is nil")
|
||||
gcAssert cell.typ.kind in {tyRef, tyOptAsRef, tySequence, tyString}, "forAllChildren: unknown GC'ed type"
|
||||
let marker = cell.typ.marker
|
||||
if marker != nil:
|
||||
marker(cellToUsr(cell), op.int)
|
||||
|
|
@ -623,30 +601,31 @@ proc freeCyclicCell(gch: var GcHeap, c: PCell) =
|
|||
gcAssert(c.typ != nil, "freeCyclicCell")
|
||||
zeroMem(c, sizeof(Cell))
|
||||
|
||||
when useBackupGc:
|
||||
proc sweep(gch: var GcHeap) =
|
||||
for x in allObjects(gch.region):
|
||||
if isCell(x):
|
||||
# cast to PCell is correct here:
|
||||
var c = cast[PCell](x)
|
||||
if c notin gch.marked: freeCyclicCell(gch, c)
|
||||
proc sweep(gch: var GcHeap) =
|
||||
for x in allObjects(gch.region):
|
||||
if isCell(x):
|
||||
# cast to PCell is correct here:
|
||||
var c = cast[PCell](x)
|
||||
if c notin gch.marked: freeCyclicCell(gch, c)
|
||||
|
||||
when useMarkForDebug or useBackupGc:
|
||||
proc markS(gch: var GcHeap, c: PCell) =
|
||||
incl(gch.marked, c)
|
||||
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
||||
forAllChildren(c, waMarkPrecise)
|
||||
while gch.tempStack.len > 0:
|
||||
dec gch.tempStack.len
|
||||
var d = gch.tempStack.d[gch.tempStack.len]
|
||||
gcAssert isAllocatedPtr(gch.region, d), "markS: foreign heap root detected!"
|
||||
if not containsOrIncl(gch.marked, d):
|
||||
forAllChildren(d, waMarkPrecise)
|
||||
proc markS(gch: var GcHeap, c: PCell) =
|
||||
gcAssert isAllocatedPtr(gch.region, c), "markS: foreign heap root detected A!"
|
||||
incl(gch.marked, c)
|
||||
gcAssert gch.tempStack.len == 0, "stack not empty!"
|
||||
forAllChildren(c, waMarkPrecise)
|
||||
while gch.tempStack.len > 0:
|
||||
dec gch.tempStack.len
|
||||
var d = gch.tempStack.d[gch.tempStack.len]
|
||||
gcAssert isAllocatedPtr(gch.region, d), "markS: foreign heap root detected B!"
|
||||
if not containsOrIncl(gch.marked, d):
|
||||
forAllChildren(d, waMarkPrecise)
|
||||
|
||||
proc markGlobals(gch: var GcHeap) =
|
||||
proc markGlobals(gch: var GcHeap) =
|
||||
if gch.isMainThread:
|
||||
for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
|
||||
let d = gch.additionalRoots.d
|
||||
for i in 0 .. gch.additionalRoots.len-1: markS(gch, d[i])
|
||||
for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]()
|
||||
let d = gch.additionalRoots.d
|
||||
for i in 0 .. gch.additionalRoots.len-1: markS(gch, d[i])
|
||||
|
||||
when logGC:
|
||||
var
|
||||
|
|
@ -690,16 +669,15 @@ proc doOperation(p: pointer, op: WalkOp) =
|
|||
of waPush:
|
||||
add(gch.tempStack, c)
|
||||
of waMarkGlobal:
|
||||
when useMarkForDebug or useBackupGc:
|
||||
when hasThreadSupport:
|
||||
# could point to a cell which we don't own and don't want to touch/trace
|
||||
if isAllocatedPtr(gch.region, c):
|
||||
markS(gch, c)
|
||||
else:
|
||||
when hasThreadSupport:
|
||||
# could point to a cell which we don't own and don't want to touch/trace
|
||||
# XXX: This should not be required anymore!
|
||||
if isAllocatedPtr(gch.region, c):
|
||||
markS(gch, c)
|
||||
else:
|
||||
markS(gch, c)
|
||||
of waMarkPrecise:
|
||||
when useMarkForDebug or useBackupGc:
|
||||
add(gch.tempStack, c)
|
||||
add(gch.tempStack, c)
|
||||
#of waDebug: debugGraph(c)
|
||||
|
||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
|
||||
|
|
@ -713,14 +691,13 @@ proc collectCycles(gch: var GcHeap) =
|
|||
nimGCunref(c)
|
||||
# ensure the ZCT 'color' is not used:
|
||||
while gch.zct.len > 0: discard collectZCT(gch)
|
||||
when useBackupGc:
|
||||
cellsetReset(gch.marked)
|
||||
var d = gch.decStack.d
|
||||
for i in 0..gch.decStack.len-1:
|
||||
sysAssert isAllocatedPtr(gch.region, d[i]), "collectCycles"
|
||||
markS(gch, d[i])
|
||||
markGlobals(gch)
|
||||
sweep(gch)
|
||||
cellsetReset(gch.marked)
|
||||
var d = gch.decStack.d
|
||||
for i in 0..gch.decStack.len-1:
|
||||
sysAssert isAllocatedPtr(gch.region, d[i]), "collectCycles"
|
||||
markS(gch, d[i])
|
||||
markGlobals(gch)
|
||||
sweep(gch)
|
||||
|
||||
proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||
# the addresses are not as cells on the stack, so turn them to cells:
|
||||
|
|
@ -861,7 +838,7 @@ proc collectCT(gch: var GcHeap) =
|
|||
if (gch.zct.len >= stackMarkCosts or (cycleGC and
|
||||
getOccupiedMem(gch.region)>=gch.cycleThreshold) or alwaysGC) and
|
||||
gch.recGcLock == 0:
|
||||
when useMarkForDebug:
|
||||
when false:
|
||||
prepareForInteriorPointerChecking(gch.region)
|
||||
cellsetReset(gch.marked)
|
||||
markForDebug(gch)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue