GC: enable precise global/thread local storage tracing
This commit is contained in:
parent
24a6583fa7
commit
f1089db175
4 changed files with 47 additions and 63 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue