GC: enable precise global/thread local storage tracing

This commit is contained in:
Araq 2018-01-15 17:41:05 +01:00
commit f1089db175
4 changed files with 47 additions and 63 deletions

View file

@ -92,7 +92,7 @@ type
additionalRoots: CellSeq # dummy roots for GC_ref/unref additionalRoots: CellSeq # dummy roots for GC_ref/unref
when hasThreadSupport: when hasThreadSupport:
toDispose: SharedList[pointer] toDispose: SharedList[pointer]
isMainThread: bool gcThreadId: int
var var
gch {.rtlThreadVar.}: GcHeap gch {.rtlThreadVar.}: GcHeap
@ -163,8 +163,8 @@ when defined(logGC):
c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld from %s(%ld)\n", c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld from %s(%ld)\n",
msg, c, kind, typName, c.refcount shr rcShift, c.filename, c.line) msg, c, kind, typName, c.refcount shr rcShift, c.filename, c.line)
else: else:
c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld; color=%ld\n", c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld; thread=%ld\n",
msg, c, kind, typName, c.refcount shr rcShift, c.color) msg, c, kind, typName, c.refcount shr rcShift, gch.gcThreadId)
template gcTrace(cell, state: untyped) = template gcTrace(cell, state: untyped) =
when traceGC: traceCell(cell, state) when traceGC: traceCell(cell, state)
@ -312,7 +312,8 @@ proc initGC() =
init(gch.additionalRoots) init(gch.additionalRoots)
when hasThreadSupport: when hasThreadSupport:
init(gch.toDispose) init(gch.toDispose)
gch.isMainThread = true gch.gcThreadId = atomicInc(gHeapidGenerator) - 1
gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID")
proc cellsetReset(s: var CellSet) = proc cellsetReset(s: var CellSet) =
deinit(s) deinit(s)
@ -459,7 +460,7 @@ proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
release(gch) release(gch)
when useCellIds: when useCellIds:
inc gch.idGenerator inc gch.idGenerator
res.id = gch.idGenerator res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
result = cellToUsr(res) result = cellToUsr(res)
sysAssert(allocInv(gch.region), "rawNewObj end") sysAssert(allocInv(gch.region), "rawNewObj end")
@ -506,7 +507,7 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
release(gch) release(gch)
when useCellIds: when useCellIds:
inc gch.idGenerator inc gch.idGenerator
res.id = gch.idGenerator res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
result = cellToUsr(res) result = cellToUsr(res)
zeroMem(result, size) zeroMem(result, size)
sysAssert(allocInv(gch.region), "newObjRC1 end") sysAssert(allocInv(gch.region), "newObjRC1 end")
@ -576,7 +577,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
release(gch) release(gch)
when useCellIds: when useCellIds:
inc gch.idGenerator inc gch.idGenerator
res.id = gch.idGenerator res.id = gch.idGenerator * 1000_000 + gch.gcThreadId
result = cellToUsr(res) result = cellToUsr(res)
sysAssert(allocInv(gch.region), "growObj end") sysAssert(allocInv(gch.region), "growObj end")
when defined(memProfiler): nimProfile(newsize-oldsize) when defined(memProfiler): nimProfile(newsize-oldsize)
@ -621,7 +622,7 @@ proc markS(gch: var GcHeap, c: PCell) =
forAllChildren(d, waMarkPrecise) forAllChildren(d, waMarkPrecise)
proc markGlobals(gch: var GcHeap) = proc markGlobals(gch: var GcHeap) =
if gch.isMainThread: if gch.gcThreadId == 0:
for i in 0 .. globalMarkersLen-1: globalMarkers[i]() for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]()
let d = gch.additionalRoots.d let d = gch.additionalRoots.d
@ -669,12 +670,6 @@ proc doOperation(p: pointer, op: WalkOp) =
of waPush: of waPush:
add(gch.tempStack, c) add(gch.tempStack, c)
of waMarkGlobal: of waMarkGlobal:
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) markS(gch, c)
of waMarkPrecise: of waMarkPrecise:
add(gch.tempStack, c) add(gch.tempStack, c)

View file

@ -104,7 +104,7 @@ type
pDumpHeapFile: pointer # File that is used for GC_dumpHeap pDumpHeapFile: pointer # File that is used for GC_dumpHeap
when hasThreadSupport: when hasThreadSupport:
toDispose: SharedList[pointer] toDispose: SharedList[pointer]
isMainThread: bool gcThreadId: int
var var
gch {.rtlThreadVar.}: GcHeap gch {.rtlThreadVar.}: GcHeap
@ -120,23 +120,6 @@ template release(gch: GcHeap) =
when hasThreadSupport and hasSharedHeap: when hasThreadSupport and hasSharedHeap:
releaseSys(HeapLock) releaseSys(HeapLock)
proc initGC() =
when not defined(useNimRtl):
gch.red = (1-gch.black)
gch.cycleThreshold = InitialCycleThreshold
gch.stat.stackScans = 0
gch.stat.completedCollections = 0
gch.stat.maxThreshold = 0
gch.stat.maxStackSize = 0
gch.stat.maxStackCells = 0
gch.stat.cycleTableSize = 0
# init the rt
init(gch.additionalRoots)
init(gch.greyStack)
when hasThreadSupport:
init(gch.toDispose)
gch.isMainThread = true
# Which color to use for new objects is tricky: When we're marking, # Which color to use for new objects is tricky: When we're marking,
# they have to be *white* so that everything is marked that is only # they have to be *white* so that everything is marked that is only
# reachable from them. However, when we are sweeping, they have to # reachable from them. However, when we are sweeping, they have to
@ -342,6 +325,24 @@ proc gcInvariant*() =
include gc_common include gc_common
proc initGC() =
when not defined(useNimRtl):
gch.red = (1-gch.black)
gch.cycleThreshold = InitialCycleThreshold
gch.stat.stackScans = 0
gch.stat.completedCollections = 0
gch.stat.maxThreshold = 0
gch.stat.maxStackSize = 0
gch.stat.maxStackCells = 0
gch.stat.cycleTableSize = 0
# init the rt
init(gch.additionalRoots)
init(gch.greyStack)
when hasThreadSupport:
init(gch.toDispose)
gch.gcThreadId = atomicInc(gHeapidGenerator) - 1
gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID")
proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer = proc rawNewObj(typ: PNimType, size: int, gch: var GcHeap): pointer =
# generates a new object and sets its reference counter to 0 # generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin") sysAssert(allocInv(gch.region), "rawNewObj begin")
@ -480,7 +481,7 @@ proc GC_dumpHeap*(file: File) =
c_fprintf(file, "onstack %p\n", d[i]) c_fprintf(file, "onstack %p\n", d[i])
else: else:
c_fprintf(file, "onstack_invalid %p\n", d[i]) c_fprintf(file, "onstack_invalid %p\n", d[i])
if gch.isMainThread: if gch.gcThreadId == 0:
for i in 0 .. globalMarkersLen-1: globalMarkers[i]() for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]()
while true: while true:
@ -569,7 +570,7 @@ proc markIncremental(gch: var GcHeap): bool =
result = true result = true
proc markGlobals(gch: var GcHeap) = proc markGlobals(gch: var GcHeap) =
if gch.isMainThread: if gch.gcThreadId == 0:
for i in 0 .. globalMarkersLen-1: globalMarkers[i]() for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]()
@ -591,18 +592,10 @@ proc doOperation(p: pointer, op: WalkOp) =
markRoot(gch, c) markRoot(gch, c)
else: else:
dumpRoot(gch, c) dumpRoot(gch, c)
when hasThreadSupport:
# could point to a cell which we don't own and don't want to touch/trace
if isAllocatedPtr(gch.region, c): handleRoot()
else:
#gcAssert(isAllocatedPtr(gch.region, c), "doOperation: waMarkGlobal")
if not isAllocatedPtr(gch.region, c):
c_fprintf(stdout, "[GC] not allocated anymore: MarkGlobal %p\n", c)
#GC_dumpHeap()
sysAssert(false, "wtf")
handleRoot() handleRoot()
discard allocInv(gch.region) discard allocInv(gch.region)
of waMarkGrey: of waMarkGrey:
when false:
if not isAllocatedPtr(gch.region, c): if not isAllocatedPtr(gch.region, c):
c_fprintf(stdout, "[GC] not allocated anymore: MarkGrey %p\n", c) c_fprintf(stdout, "[GC] not allocated anymore: MarkGrey %p\n", c)
#GC_dumpHeap() #GC_dumpHeap()

View file

@ -401,6 +401,7 @@ var
globalMarkers: array[0.. 3499, GlobalMarkerProc] globalMarkers: array[0.. 3499, GlobalMarkerProc]
threadLocalMarkersLen: int threadLocalMarkersLen: int
threadLocalMarkers: array[0.. 3499, GlobalMarkerProc] threadLocalMarkers: array[0.. 3499, GlobalMarkerProc]
gHeapidGenerator: int
proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} = proc nimRegisterGlobalMarker(markerProc: GlobalMarkerProc) {.compilerProc.} =
if globalMarkersLen <= high(globalMarkers): if globalMarkersLen <= high(globalMarkers):

View file

@ -73,7 +73,7 @@ type
stat: GcStat stat: GcStat
when hasThreadSupport: when hasThreadSupport:
toDispose: SharedList[pointer] toDispose: SharedList[pointer]
isMainThread: bool gcThreadId: int
additionalRoots: CellSeq # dummy roots for GC_ref/unref additionalRoots: CellSeq # dummy roots for GC_ref/unref
var var
@ -220,7 +220,8 @@ proc initGC() =
init(gch.marked) init(gch.marked)
when hasThreadSupport: when hasThreadSupport:
init(gch.toDispose) init(gch.toDispose)
gch.isMainThread = true gch.gcThreadId = atomicInc(gHeapidGenerator) - 1
gcAssert(gch.gcThreadId >= 0, "invalid computed thread ID")
proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} = proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: WalkOp) {.benign.} =
var d = cast[ByteAddress](dest) var d = cast[ByteAddress](dest)
@ -394,13 +395,7 @@ proc doOperation(p: pointer, op: WalkOp) =
var c: PCell = usrToCell(p) var c: PCell = usrToCell(p)
gcAssert(c != nil, "doOperation: 1") gcAssert(c != nil, "doOperation: 1")
case op case op
of waMarkGlobal: of waMarkGlobal: mark(gch, c)
when hasThreadSupport:
# could point to a cell which we don't own and don't want to touch/trace
if isAllocatedPtr(gch.region, c):
mark(gch, c)
else:
mark(gch, c)
of waMarkPrecise: add(gch.tempStack, c) of waMarkPrecise: add(gch.tempStack, c)
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
@ -437,7 +432,7 @@ when false:
quit 1 quit 1
proc markGlobals(gch: var GcHeap) = proc markGlobals(gch: var GcHeap) =
if gch.isMainThread: if gch.gcThreadId == 0:
for i in 0 .. globalMarkersLen-1: globalMarkers[i]() for i in 0 .. globalMarkersLen-1: globalMarkers[i]()
for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]() for i in 0 .. threadLocalMarkersLen-1: threadLocalMarkers[i]()
let d = gch.additionalRoots.d let d = gch.additionalRoots.d