summary refs log tree commit diff stats
path: root/lib/system/orc.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/system/orc.nim')
-rw-r--r--lib/system/orc.nim37
1 files changed, 31 insertions, 6 deletions
diff --git a/lib/system/orc.nim b/lib/system/orc.nim
index 4ba462c1f..5deed1d14 100644
--- a/lib/system/orc.nim
+++ b/lib/system/orc.nim
@@ -41,6 +41,7 @@ proc nimIncRefCyclic(p: pointer) {.compilerRtl, inl.} =
   let h = head(p)
   inc h.rc, rcIncrement
   #h.setColor colPurple # mark as potential cycle!
+  h.setColor colBlack
 
 const
   useJumpStack = false # for thavlak the jump stack doesn't improve the performance at all
@@ -101,6 +102,11 @@ proc nimTraceRefDyn(q: pointer; env: pointer) {.compilerRtl.} =
     var j = cast[ptr GcEnv](env)
     j.traceStack.add(head p[], cast[ptr PNimTypeV2](p[])[])
 
+template orcAssert(cond, msg) =
+  if not cond:
+    cfprintf(cstderr, "[Bug!] %s\n", msg)
+    quit 1
+
 var
   roots {.threadvar.}: CellSeq
 
@@ -115,6 +121,11 @@ proc unregisterCycle(s: Cell) =
   roots.d[idx][0].rootIdx = idx
   dec roots.len
 
+when false:
+  proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) =
+    cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld\n",
+      msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color)
+
 proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   #[
   proc scanBlack(s: Cell) =
@@ -126,14 +137,17 @@ proc scanBlack(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   ]#
   debug "scanBlack", s
   s.setColor colBlack
+  let until = j.traceStack.len
   trace(s, desc, j)
-  while j.traceStack.len > 0:
+  #writeCell("root still alive", s, desc)
+  while j.traceStack.len > until:
     let (t, desc) = j.traceStack.pop()
     inc t.rc, rcIncrement
     debug "incRef", t
     if t.color != colBlack:
       t.setColor colBlack
       trace(t, desc, j)
+      #writeCell("child still alive", t, desc)
 
 proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   #[
@@ -148,6 +162,7 @@ proc markGray(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
   if s.color != colGray:
     s.setColor colGray
     inc j.touched
+    orcAssert(j.traceStack.len == 0, "markGray: trace stack not empty")
     trace(s, desc, j)
     while j.traceStack.len > 0:
       let (t, desc) = j.traceStack.pop()
@@ -195,6 +210,7 @@ proc scan(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
             when traceCollector:
               cprintf("[jump stack] %p %ld\n", t, t.rc shr rcShift)
 
+      orcAssert(j.traceStack.len == 0, "scan: trace stack not empty")
       s.setColor(colWhite)
       trace(s, desc, j)
       while j.traceStack.len > 0:
@@ -236,6 +252,8 @@ proc collectWhite(s: Cell; desc: PNimTypeV2; j: var GcEnv) =
       free(s) # watch out, a bug here!
   ]#
   if s.color == colWhite and (s.rc and isCycleCandidate) == 0:
+    orcAssert(j.traceStack.len == 0, "collectWhite: trace stack not empty")
+
     s.setColor(colBlack)
     j.toFree.add(s, desc)
     trace(s, desc, j)
@@ -261,6 +279,7 @@ proc collectCyclesBacon(j: var GcEnv) =
       collectWhite(s)
   ]#
   for i in 0 ..< roots.len:
+    #writeCell("root", roots.d[i][0], roots.d[i][1])
     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)
@@ -279,7 +298,7 @@ proc collectCyclesBacon(j: var GcEnv) =
   #roots.len = 0
 
 const
-  defaultThreshold = 10_000
+  defaultThreshold = when defined(nimAdaptiveOrc): 128 else: 10_000
 
 var
   rootsThreshold = defaultThreshold
@@ -309,11 +328,16 @@ proc collectCycles() =
   # we're effective when we collected 50% or more of the nodes
   # we touched. If we're effective, we can reset the threshold:
   if j.freed * 2 >= j.touched:
-    rootsThreshold = defaultThreshold
+    when defined(nimAdaptiveOrc):
+      rootsThreshold = max(rootsThreshold div 2, 16)
+    else:
+      rootsThreshold = defaultThreshold
+    #cfprintf(cstderr, "[collectCycles] freed %ld, touched %ld new threshold %ld\n", j.freed, j.touched, rootsThreshold)
   elif rootsThreshold < high(int) div 4:
     rootsThreshold = rootsThreshold * 3 div 2
   when false:
-    cfprintf(cstderr, "[collectCycles] freed %ld new threshold %ld\n", j.freed, rootsThreshold)
+    cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld\n", j.freed, rootsThreshold, j.touched,
+      getOccupiedMem())
 
 proc registerCycle(s: Cell; desc: PNimTypeV2) =
   if roots.len >= rootsThreshold:
@@ -328,10 +352,10 @@ proc GC_fullCollect* =
   ## collector.
   collectCycles()
 
-proc GC_enableMarkAndSweep() =
+proc GC_enableMarkAndSweep*() =
   rootsThreshold = defaultThreshold
 
-proc GC_disableMarkAndSweep() =
+proc GC_disableMarkAndSweep*() =
   rootsThreshold = high(int)
 
 proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.} =
@@ -345,6 +369,7 @@ proc rememberCycle(isDestroyAction: bool; s: Cell; desc: PNimTypeV2) {.noinline.
     #s.setColor colGreen  # XXX This is wrong!
     if (s.rc and isCycleCandidate) == 0:
       s.rc = s.rc or isCycleCandidate
+      s.setColor colBlack
       registerCycle(s, desc)
 
 proc nimDecRefIsLastCyclicDyn(p: pointer): bool {.compilerRtl, inl.} =