M&S GC gets the heap dump feature
This commit is contained in:
parent
e216e0debd
commit
03916fa3b1
3 changed files with 76 additions and 69 deletions
|
|
@ -167,15 +167,6 @@ proc writeCell(msg: cstring, c: PCell) =
|
||||||
c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld; color=%ld\n",
|
c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld; color=%ld\n",
|
||||||
msg, c, kind, typName, c.refcount shr rcShift, c.color)
|
msg, c, kind, typName, c.refcount shr rcShift, c.color)
|
||||||
|
|
||||||
|
|
||||||
when defined(nimTypeNames):
|
|
||||||
proc dumpNumberOfInstances* =
|
|
||||||
var it = nimTypeRoot
|
|
||||||
while it != nil:
|
|
||||||
if it.instances > 0:
|
|
||||||
c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
|
|
||||||
it = it.nextType
|
|
||||||
|
|
||||||
template gcTrace(cell, state: expr): stmt {.immediate.} =
|
template gcTrace(cell, state: expr): stmt {.immediate.} =
|
||||||
when traceGC: traceCell(cell, state)
|
when traceGC: traceCell(cell, state)
|
||||||
|
|
||||||
|
|
@ -196,34 +187,16 @@ else:
|
||||||
x <% rcIncrement
|
x <% rcIncrement
|
||||||
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
template `++`(x: expr): stmt = inc(x, rcIncrement)
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
proc incRef(c: PCell) {.inline.} =
|
||||||
when useMarkForDebug:
|
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
||||||
gcAssert(cell notin gch.marked, "Cell still alive!")
|
c.refcount = c.refcount +% rcIncrement
|
||||||
let t = cell.typ
|
# and not colorMask
|
||||||
if t.finalizer != nil:
|
#writeCell("incRef", c)
|
||||||
# the finalizer could invoke something that
|
|
||||||
# allocates memory; this could trigger a garbage
|
|
||||||
# collection. Since we are already collecting we
|
|
||||||
# prevend recursive entering here by a lock.
|
|
||||||
# XXX: we should set the cell's children to nil!
|
|
||||||
inc(gch.recGcLock)
|
|
||||||
(cast[Finalizer](t.finalizer))(cellToUsr(cell))
|
|
||||||
dec(gch.recGcLock)
|
|
||||||
when defined(nimTypeNames):
|
|
||||||
if t.kind in {tyString, tySequence}:
|
|
||||||
let len = cast[PGenericSeq](cellToUsr(cell)).len
|
|
||||||
let base = if t.kind == tyString: 1 else: t.base.size
|
|
||||||
let size = addInt(mulInt(len, base), GenericSeqSize)
|
|
||||||
dec t.sizes, size+sizeof(Cell)
|
|
||||||
else:
|
|
||||||
dec t.sizes, t.size+sizeof(Cell)
|
|
||||||
dec t.instances
|
|
||||||
|
|
||||||
template beforeDealloc(gch: var GcHeap; c: PCell; msg: typed) =
|
proc nimGCref(p: pointer) {.compilerProc.} =
|
||||||
when false:
|
# we keep it from being collected by pretending it's not even allocated:
|
||||||
for i in 0..gch.decStack.len-1:
|
add(gch.additionalRoots, usrToCell(p))
|
||||||
if gch.decStack.d[i] == c:
|
incRef(usrToCell(p))
|
||||||
sysAssert(false, msg)
|
|
||||||
|
|
||||||
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
proc rtlAddCycleRoot(c: PCell) {.rtl, inl.} =
|
||||||
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
# we MUST access gch as a global here, because this crosses DLL boundaries!
|
||||||
|
|
@ -246,17 +219,6 @@ proc decRef(c: PCell) {.inline.} =
|
||||||
if --c.refcount:
|
if --c.refcount:
|
||||||
rtlAddZCT(c)
|
rtlAddZCT(c)
|
||||||
|
|
||||||
proc incRef(c: PCell) {.inline.} =
|
|
||||||
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
|
|
||||||
c.refcount = c.refcount +% rcIncrement
|
|
||||||
# and not colorMask
|
|
||||||
#writeCell("incRef", c)
|
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerProc.} =
|
|
||||||
# we keep it from being collected by pretending it's not even allocated:
|
|
||||||
add(gch.additionalRoots, usrToCell(p))
|
|
||||||
incRef(usrToCell(p))
|
|
||||||
|
|
||||||
proc nimGCunref(p: pointer) {.compilerProc.} =
|
proc nimGCunref(p: pointer) {.compilerProc.} =
|
||||||
let cell = usrToCell(p)
|
let cell = usrToCell(p)
|
||||||
var L = gch.additionalRoots.len-1
|
var L = gch.additionalRoots.len-1
|
||||||
|
|
@ -270,6 +232,29 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
|
||||||
dec(i)
|
dec(i)
|
||||||
decRef(usrToCell(p))
|
decRef(usrToCell(p))
|
||||||
|
|
||||||
|
include gc_common
|
||||||
|
|
||||||
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
when useMarkForDebug:
|
||||||
|
gcAssert(cell notin gch.marked, "Cell still alive!")
|
||||||
|
let t = cell.typ
|
||||||
|
if t.finalizer != nil:
|
||||||
|
# the finalizer could invoke something that
|
||||||
|
# allocates memory; this could trigger a garbage
|
||||||
|
# collection. Since we are already collecting we
|
||||||
|
# prevend recursive entering here by a lock.
|
||||||
|
# XXX: we should set the cell's children to nil!
|
||||||
|
inc(gch.recGcLock)
|
||||||
|
(cast[Finalizer](t.finalizer))(cellToUsr(cell))
|
||||||
|
dec(gch.recGcLock)
|
||||||
|
decTypeSize(cell, t)
|
||||||
|
|
||||||
|
template beforeDealloc(gch: var GcHeap; c: PCell; msg: typed) =
|
||||||
|
when false:
|
||||||
|
for i in 0..gch.decStack.len-1:
|
||||||
|
if gch.decStack.d[i] == c:
|
||||||
|
sysAssert(false, msg)
|
||||||
|
|
||||||
proc GC_addCycleRoot*[T](p: ref T) {.inline.} =
|
proc GC_addCycleRoot*[T](p: ref T) {.inline.} =
|
||||||
## adds 'p' to the cycle candidate set for the cycle collector. It is
|
## adds 'p' to the cycle candidate set for the cycle collector. It is
|
||||||
## necessary if you used the 'acyclic' pragma for optimization
|
## necessary if you used the 'acyclic' pragma for optimization
|
||||||
|
|
@ -481,9 +466,7 @@ template setFrameInfo(c: PCell) =
|
||||||
|
|
||||||
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
|
||||||
when defined(nimTypeNames):
|
incTypeSize typ, size
|
||||||
inc typ.instances
|
|
||||||
inc typ.sizes, size+sizeof(Cell)
|
|
||||||
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
sysAssert(allocInv(gch.region), "rawNewObj begin")
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
|
|
@ -531,9 +514,7 @@ proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||||
|
|
||||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||||
# generates a new object and sets its reference counter to 1
|
# generates a new object and sets its reference counter to 1
|
||||||
when defined(nimTypeNames):
|
incTypeSize typ, size
|
||||||
inc typ.instances
|
|
||||||
inc typ.sizes, size+sizeof(Cell)
|
|
||||||
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
sysAssert(allocInv(gch.region), "newObjRC1 begin")
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
|
|
@ -578,6 +559,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
incTypeSize ol.typ, newsize
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(Cell))
|
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||||
|
|
@ -765,8 +747,6 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||||
add(gch.decStack, cell)
|
add(gch.decStack, cell)
|
||||||
sysAssert(allocInv(gch.region), "gcMark end")
|
sysAssert(allocInv(gch.region), "gcMark end")
|
||||||
|
|
||||||
include gc_common
|
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
forEachStackSlot(gch, gcMark)
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,30 @@ proc protect*(x: pointer): ForeignCell =
|
||||||
result.data = x
|
result.data = x
|
||||||
result.owner = addr(gch)
|
result.owner = addr(gch)
|
||||||
|
|
||||||
|
when defined(nimTypeNames):
|
||||||
|
proc dumpNumberOfInstances* =
|
||||||
|
var it = nimTypeRoot
|
||||||
|
while it != nil:
|
||||||
|
if it.instances > 0:
|
||||||
|
c_fprintf(stdout, "[Heap] %s: #%ld; bytes: %ld\n", it.name, it.instances, it.sizes)
|
||||||
|
it = it.nextType
|
||||||
|
|
||||||
|
template decTypeSize(cell, t) =
|
||||||
|
when defined(nimTypeNames):
|
||||||
|
if t.kind in {tyString, tySequence}:
|
||||||
|
let len = cast[PGenericSeq](cellToUsr(cell)).len
|
||||||
|
let base = if t.kind == tyString: 1 else: t.base.size
|
||||||
|
let size = addInt(mulInt(len, base), GenericSeqSize)
|
||||||
|
dec t.sizes, size+sizeof(Cell)
|
||||||
|
else:
|
||||||
|
dec t.sizes, t.size+sizeof(Cell)
|
||||||
|
dec t.instances
|
||||||
|
|
||||||
|
template incTypeSize(typ, size) =
|
||||||
|
when defined(nimTypeNames):
|
||||||
|
inc typ.instances
|
||||||
|
inc typ.sizes, size+sizeof(Cell)
|
||||||
|
|
||||||
proc dispose*(x: ForeignCell) =
|
proc dispose*(x: ForeignCell) =
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
# if we own it we can free it directly:
|
# if we own it we can free it directly:
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ template mulThreshold(x): expr {.immediate.} = x * 2
|
||||||
|
|
||||||
when defined(memProfiler):
|
when defined(memProfiler):
|
||||||
proc nimProfile(requestedSize: int)
|
proc nimProfile(requestedSize: int)
|
||||||
|
|
||||||
when hasThreadSupport:
|
when hasThreadSupport:
|
||||||
import sharedlist
|
import sharedlist
|
||||||
|
|
||||||
|
|
@ -140,17 +140,6 @@ proc doOperation(p: pointer, op: WalkOp) {.benign.}
|
||||||
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: WalkOp) {.benign.}
|
||||||
# we need the prototype here for debugging purposes
|
# we need the prototype here for debugging purposes
|
||||||
|
|
||||||
proc prepareDealloc(cell: PCell) =
|
|
||||||
if cell.typ.finalizer != nil:
|
|
||||||
# the finalizer could invoke something that
|
|
||||||
# allocates memory; this could trigger a garbage
|
|
||||||
# collection. Since we are already collecting we
|
|
||||||
# prevend recursive entering here by a lock.
|
|
||||||
# XXX: we should set the cell's children to nil!
|
|
||||||
inc(gch.recGcLock)
|
|
||||||
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
|
|
||||||
dec(gch.recGcLock)
|
|
||||||
|
|
||||||
proc nimGCref(p: pointer) {.compilerProc.} =
|
proc nimGCref(p: pointer) {.compilerProc.} =
|
||||||
# we keep it from being collected by pretending it's not even allocated:
|
# we keep it from being collected by pretending it's not even allocated:
|
||||||
when false:
|
when false:
|
||||||
|
|
@ -173,6 +162,20 @@ proc nimGCunref(p: pointer) {.compilerProc.} =
|
||||||
when withBitvectors: incl(gch.allocated, usrToCell(p))
|
when withBitvectors: incl(gch.allocated, usrToCell(p))
|
||||||
else: usrToCell(p).refcount = rcWhite
|
else: usrToCell(p).refcount = rcWhite
|
||||||
|
|
||||||
|
include gc_common
|
||||||
|
|
||||||
|
proc prepareDealloc(cell: PCell) =
|
||||||
|
if cell.typ.finalizer != nil:
|
||||||
|
# the finalizer could invoke something that
|
||||||
|
# allocates memory; this could trigger a garbage
|
||||||
|
# collection. Since we are already collecting we
|
||||||
|
# prevend recursive entering here by a lock.
|
||||||
|
# XXX: we should set the cell's children to nil!
|
||||||
|
inc(gch.recGcLock)
|
||||||
|
(cast[Finalizer](cell.typ.finalizer))(cellToUsr(cell))
|
||||||
|
dec(gch.recGcLock)
|
||||||
|
decTypeSize cell, cell.typ
|
||||||
|
|
||||||
proc initGC() =
|
proc initGC() =
|
||||||
when not defined(useNimRtl):
|
when not defined(useNimRtl):
|
||||||
gch.cycleThreshold = InitialThreshold
|
gch.cycleThreshold = InitialThreshold
|
||||||
|
|
@ -235,6 +238,7 @@ proc forAllChildren(cell: PCell, op: WalkOp) =
|
||||||
|
|
||||||
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
|
||||||
|
incTypeSize typ, size
|
||||||
acquire(gch)
|
acquire(gch)
|
||||||
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
|
||||||
collectCT(gch)
|
collectCT(gch)
|
||||||
|
|
@ -300,6 +304,7 @@ proc growObj(old: pointer, newsize: int, gch: var GcHeap): pointer =
|
||||||
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
var res = cast[PCell](rawAlloc(gch.region, newsize + sizeof(Cell)))
|
||||||
var elemSize = 1
|
var elemSize = 1
|
||||||
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
if ol.typ.kind != tyString: elemSize = ol.typ.base.size
|
||||||
|
incTypeSize ol.typ, newsize
|
||||||
|
|
||||||
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
|
||||||
copyMem(res, ol, oldsize + sizeof(Cell))
|
copyMem(res, ol, oldsize + sizeof(Cell))
|
||||||
|
|
@ -414,8 +419,6 @@ proc gcMark(gch: var GcHeap, p: pointer) {.inline.} =
|
||||||
if objStart != nil:
|
if objStart != nil:
|
||||||
mark(gch, objStart)
|
mark(gch, objStart)
|
||||||
|
|
||||||
include gc_common
|
|
||||||
|
|
||||||
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
proc markStackAndRegisters(gch: var GcHeap) {.noinline, cdecl.} =
|
||||||
forEachStackSlot(gch, gcMark)
|
forEachStackSlot(gch, gcMark)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue