GC improvements; distinguish between thread local and globals in the marking step

This commit is contained in:
Araq 2018-01-14 17:34:27 +01:00
commit f71f9f83c2
8 changed files with 129 additions and 128 deletions

View file

@ -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)