ORC: API extensions (#16126)
* ORC: API extensions * ORC: exploit a common special case
This commit is contained in:
parent
e0b4f05053
commit
ae9fe2b2f9
1 changed files with 45 additions and 14 deletions
|
|
@ -71,7 +71,7 @@ type
|
||||||
when useJumpStack:
|
when useJumpStack:
|
||||||
jumpStack: CellSeq # Lins' jump stack in order to speed up traversals
|
jumpStack: CellSeq # Lins' jump stack in order to speed up traversals
|
||||||
toFree: CellSeq
|
toFree: CellSeq
|
||||||
freed, touched: int
|
freed, touched, edges, rcSum: int
|
||||||
|
|
||||||
proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
|
proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} =
|
||||||
if desc.traceImpl != nil:
|
if desc.traceImpl != nil:
|
||||||
|
|
@ -174,11 +174,14 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
||||||
if s.color != colGray:
|
if s.color != colGray:
|
||||||
s.setColor colGray
|
s.setColor colGray
|
||||||
inc j.touched
|
inc j.touched
|
||||||
|
# keep in mind that refcounts are zero based so add 1 here:
|
||||||
|
inc j.rcSum, (s.rc shr rcShift) + 1
|
||||||
orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty")
|
orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty")
|
||||||
trace(s, desc, j)
|
trace(s, desc, j)
|
||||||
while j.traceStack.len > 0:
|
while j.traceStack.len > 0:
|
||||||
let (t, desc) = j.traceStack.pop()
|
let (t, desc) = j.traceStack.pop()
|
||||||
dec t.rc, rcIncrement
|
dec t.rc, rcIncrement
|
||||||
|
inc j.edges
|
||||||
when useJumpStack:
|
when useJumpStack:
|
||||||
if (t.rc shr rcShift) >= 0 and (t.rc and jumpStackFlag) == 0:
|
if (t.rc shr rcShift) >= 0 and (t.rc and jumpStackFlag) == 0:
|
||||||
t.rc = t.rc or jumpStackFlag
|
t.rc = t.rc or jumpStackFlag
|
||||||
|
|
@ -188,6 +191,8 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
||||||
if t.color != colGray:
|
if t.color != colGray:
|
||||||
t.setColor colGray
|
t.setColor colGray
|
||||||
inc j.touched
|
inc j.touched
|
||||||
|
# we already decremented its refcount so account for that:
|
||||||
|
inc j.rcSum, (t.rc shr rcShift) + 2
|
||||||
trace(t, desc, j)
|
trace(t, desc, j)
|
||||||
|
|
||||||
proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
||||||
|
|
@ -254,8 +259,10 @@ when false:
|
||||||
cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n",
|
cfprintf(cstderr, "%s %p root index: %ld; RC: %ld; color: %ld\n",
|
||||||
msg, s, s.rootIdx, s.rc shr rcShift, s.color)
|
msg, s, s.rootIdx, s.rc shr rcShift, s.color)
|
||||||
|
|
||||||
proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
proc collectColor(s: Cell; desc: PNimTypeV2; col: int; j: var GcEnv) =
|
||||||
#[
|
#[
|
||||||
|
was: 'collectWhite'.
|
||||||
|
|
||||||
proc collectWhite(s: Cell) =
|
proc collectWhite(s: Cell) =
|
||||||
if s.color == colWhite and not buffered(s):
|
if s.color == colWhite and not buffered(s):
|
||||||
s.setColor(colBlack)
|
s.setColor(colBlack)
|
||||||
|
|
@ -263,7 +270,7 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
||||||
collectWhite(t)
|
collectWhite(t)
|
||||||
free(s) # watch out, a bug here!
|
free(s) # watch out, a bug here!
|
||||||
]#
|
]#
|
||||||
if s.color == colWhite and s.rootIdx == 0:
|
if s.color == col and s.rootIdx == 0:
|
||||||
orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty")
|
orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty")
|
||||||
|
|
||||||
s.setColor(colBlack)
|
s.setColor(colBlack)
|
||||||
|
|
@ -271,12 +278,12 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
|
||||||
trace(s, desc, j)
|
trace(s, desc, j)
|
||||||
while j.traceStack.len > 0:
|
while j.traceStack.len > 0:
|
||||||
let (t, desc) = j.traceStack.pop()
|
let (t, desc) = j.traceStack.pop()
|
||||||
if t.color == colWhite and t.rootIdx == 0:
|
if t.color == col and t.rootIdx == 0:
|
||||||
j.toFree.add(t, desc)
|
j.toFree.add(t, desc)
|
||||||
t.setColor(colBlack)
|
t.setColor(colBlack)
|
||||||
trace(t, desc, j)
|
trace(t, desc, j)
|
||||||
|
|
||||||
proc collectCyclesBacon(j: var GcEnv) =
|
proc collectCyclesBacon(j: var GcEnv; lowMark: int) =
|
||||||
# pretty direct translation from
|
# pretty direct translation from
|
||||||
# https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf
|
# https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon01Concurrent.pdf
|
||||||
# Fig. 2. Synchronous Cycle Collection
|
# Fig. 2. Synchronous Cycle Collection
|
||||||
|
|
@ -290,20 +297,27 @@ proc collectCyclesBacon(j: var GcEnv) =
|
||||||
s.buffered = false
|
s.buffered = false
|
||||||
collectWhite(s)
|
collectWhite(s)
|
||||||
]#
|
]#
|
||||||
|
let last = roots.len - 1
|
||||||
when logOrc:
|
when logOrc:
|
||||||
for i in 0 ..< roots.len:
|
for i in countdown(last, lowMark):
|
||||||
writeCell("root", roots.d[i][0], roots.d[i][1])
|
writeCell("root", roots.d[i][0], roots.d[i][1])
|
||||||
|
|
||||||
for i in 0 ..< roots.len:
|
for i in countdown(last, lowMark):
|
||||||
markGray(roots.d[i][0], roots.d[i][1], j)
|
markGray(roots.d[i][0], roots.d[i][1], j)
|
||||||
for i in 0 ..< roots.len:
|
|
||||||
scan(roots.d[i][0], roots.d[i][1], j)
|
var colToCollect = colWhite
|
||||||
|
if j.rcSum == j.edges:
|
||||||
|
# short-cut: we know everything is garbage:
|
||||||
|
colToCollect = colGray
|
||||||
|
else:
|
||||||
|
for i in countdown(last, lowMark):
|
||||||
|
scan(roots.d[i][0], roots.d[i][1], j)
|
||||||
|
|
||||||
init j.toFree
|
init j.toFree
|
||||||
for i in 0 ..< roots.len:
|
for i in 0 ..< roots.len:
|
||||||
let s = roots.d[i][0]
|
let s = roots.d[i][0]
|
||||||
s.rootIdx = 0
|
s.rootIdx = 0
|
||||||
collectWhite(s, roots.d[i][1], j)
|
collectColor(s, roots.d[i][1], colToCollect, j)
|
||||||
|
|
||||||
for i in 0 ..< j.toFree.len:
|
for i in 0 ..< j.toFree.len:
|
||||||
free(j.toFree.d[i][0], j.toFree.d[i][1])
|
free(j.toFree.d[i][0], j.toFree.d[i][1])
|
||||||
|
|
@ -320,6 +334,19 @@ when defined(nimStressOrc):
|
||||||
else:
|
else:
|
||||||
var rootsThreshold = defaultThreshold
|
var rootsThreshold = defaultThreshold
|
||||||
|
|
||||||
|
proc partialCollect(lowMark: int) =
|
||||||
|
if roots.len < 10 + lowMark: return
|
||||||
|
when logOrc:
|
||||||
|
cfprintf(cstderr, "[partialCollect] begin\n")
|
||||||
|
var j: GcEnv
|
||||||
|
init j.traceStack
|
||||||
|
collectCyclesBacon(j, lowMark)
|
||||||
|
when logOrc:
|
||||||
|
cfprintf(cstderr, "[partialCollect] end; freed %ld touched: %ld work: %ld\n", j.freed, j.touched,
|
||||||
|
roots.len - lowMark)
|
||||||
|
roots.len = lowMark
|
||||||
|
deinit j.traceStack
|
||||||
|
|
||||||
proc collectCycles() =
|
proc collectCycles() =
|
||||||
## Collect cycles.
|
## Collect cycles.
|
||||||
when logOrc:
|
when logOrc:
|
||||||
|
|
@ -329,14 +356,14 @@ proc collectCycles() =
|
||||||
init j.traceStack
|
init j.traceStack
|
||||||
when useJumpStack:
|
when useJumpStack:
|
||||||
init j.jumpStack
|
init j.jumpStack
|
||||||
collectCyclesBacon(j)
|
collectCyclesBacon(j, 0)
|
||||||
while j.jumpStack.len > 0:
|
while j.jumpStack.len > 0:
|
||||||
let (t, desc) = j.jumpStack.pop
|
let (t, desc) = j.jumpStack.pop
|
||||||
# not in jump stack anymore!
|
# not in jump stack anymore!
|
||||||
t.rc = t.rc and not jumpStackFlag
|
t.rc = t.rc and not jumpStackFlag
|
||||||
deinit j.jumpStack
|
deinit j.jumpStack
|
||||||
else:
|
else:
|
||||||
collectCyclesBacon(j)
|
collectCyclesBacon(j, 0)
|
||||||
|
|
||||||
deinit j.traceStack
|
deinit j.traceStack
|
||||||
deinit roots
|
deinit roots
|
||||||
|
|
@ -355,8 +382,8 @@ proc collectCycles() =
|
||||||
elif rootsThreshold < high(int) div 4:
|
elif rootsThreshold < high(int) div 4:
|
||||||
rootsThreshold = rootsThreshold * 3 div 2
|
rootsThreshold = rootsThreshold * 3 div 2
|
||||||
when logOrc:
|
when logOrc:
|
||||||
cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld\n", j.freed, rootsThreshold, j.touched,
|
cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld rcSum: %ld edges: %ld\n", j.freed, rootsThreshold, j.touched,
|
||||||
getOccupiedMem())
|
getOccupiedMem(), j.rcSum, j.edges)
|
||||||
|
|
||||||
proc registerCycle(s: Cell; desc: PNimTypeV2) =
|
proc registerCycle(s: Cell; desc: PNimTypeV2) =
|
||||||
s.rootIdx = roots.len+1
|
s.rootIdx = roots.len+1
|
||||||
|
|
@ -384,6 +411,10 @@ proc GC_disableOrc*() =
|
||||||
when not defined(nimStressOrc):
|
when not defined(nimStressOrc):
|
||||||
rootsThreshold = high(int)
|
rootsThreshold = high(int)
|
||||||
|
|
||||||
|
proc GC_prepareOrc*(): int {.inline.} = roots.len
|
||||||
|
|
||||||
|
proc GC_partialCollect*(limit: int) =
|
||||||
|
partialCollect(limit)
|
||||||
|
|
||||||
proc GC_fullCollect* =
|
proc GC_fullCollect* =
|
||||||
## Forces a full garbage collection pass. With ``--gc:orc`` triggers the cycle
|
## Forces a full garbage collection pass. With ``--gc:orc`` triggers the cycle
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue