diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2024-02-21 16:58:30 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-21 16:58:30 +0100 |
commit | 59c65009a57ba7f9677590c5066496bb85864ab8 (patch) | |
tree | b4df9a04a84f0c5506cedb46e916c5dc9ef97882 | |
parent | 773c066634d831a968bb464eab35b25a00026525 (diff) | |
download | Nim-59c65009a57ba7f9677590c5066496bb85864ab8.tar.gz |
ORC: added -d:nimOrcStats switch and related API (#23272)
-rw-r--r-- | changelog.md | 7 | ||||
-rw-r--r-- | lib/system.nim | 30 | ||||
-rw-r--r-- | lib/system/arc.nim | 17 | ||||
-rw-r--r-- | lib/system/excpt.nim | 6 | ||||
-rw-r--r-- | lib/system/orc.nim | 27 |
5 files changed, 67 insertions, 20 deletions
diff --git a/changelog.md b/changelog.md index f4a9d627c..e26e984e6 100644 --- a/changelog.md +++ b/changelog.md @@ -30,6 +30,9 @@ slots when enlarging a sequence. - Added `hasDefaultValue` to `std/typetraits` to check if a type has a valid default value. - Added Viewport API for the JavaScript targets in the `dom` module. - Added `toSinglyLinkedRing` and `toDoublyLinkedRing` to `std/lists` to convert from `openArray`s. +- ORC: To be enabled via `nimOrcStats` there is a new API called `GC_orcStats` that can be used to query how many + objects the cyclic collector did free. If the number is zero that is a strong indicator that you can use `--mm:arc` + instead of `--mm:orc`. [//]: # "Deprecations:" @@ -40,7 +43,7 @@ slots when enlarging a sequence. ## Language changes -- `noInit` can be used in types and fields to disable member initializers in the C++ backend. +- `noInit` can be used in types and fields to disable member initializers in the C++ backend. - C++ custom constructors initializers see https://nim-lang.org/docs/manual_experimental.htm#constructor-initializer - `member` can be used to attach a procedure to a C++ type. - C++ `constructor` now reuses `result` instead creating `this`. @@ -62,7 +65,7 @@ slots when enlarging a sequence. symbols in generic routine bodies to be replaced by symbols injected locally by templates/macros at instantiation time. `bind` may be used to keep the captured symbols over the injected ones regardless of enabling the option. - + Since this change may affect runtime behavior, the experimental switch `genericsOpenSym` needs to be enabled, and a warning is given in the case where an injected symbol would replace a captured symbol not bound by `bind` diff --git a/lib/system.nim b/lib/system.nim index b90d525b5..9b556d008 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -1703,8 +1703,24 @@ when not defined(nimscript): when not declared(sysFatal): include "system/fatal" +type + PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; + ## part of the debugger API. + # keep in sync with nimbase.h `struct TFrame_` + TFrame* {.importc, nodecl, final.} = object ## The frame itself. + prev*: PFrame ## Previous frame; used for chaining the call stack. + procname*: cstring ## Name of the proc that is currently executing. + line*: int ## Line number of the proc that is currently executing. + filename*: cstring ## Filename of the proc that is currently executing. + len*: int16 ## Length of the inspectable slots. + calldepth*: int16 ## Used for max call depth checking. + when NimStackTraceMsgs: + frameMsgLen*: int ## end position in frameMsgBuf for this frame. when defined(nimV2): + var + framePtr {.threadvar.}: PFrame + include system/arc template newException*(exceptn: typedesc, message: string; @@ -1849,20 +1865,6 @@ when notJSnotNims: ## writes an error message and terminates the program, except when ## using `--os:any` -type - PFrame* = ptr TFrame ## Represents a runtime frame of the call stack; - ## part of the debugger API. - # keep in sync with nimbase.h `struct TFrame_` - TFrame* {.importc, nodecl, final.} = object ## The frame itself. - prev*: PFrame ## Previous frame; used for chaining the call stack. - procname*: cstring ## Name of the proc that is currently executing. - line*: int ## Line number of the proc that is currently executing. - filename*: cstring ## Filename of the proc that is currently executing. - len*: int16 ## Length of the inspectable slots. - calldepth*: int16 ## Used for max call depth checking. - when NimStackTraceMsgs: - frameMsgLen*: int ## end position in frameMsgBuf for this frame. - when defined(js) or defined(nimdoc): proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = ## Appends `y` to `x` in place. diff --git a/lib/system/arc.nim b/lib/system/arc.nim index b788ac664..99c892676 100644 --- a/lib/system/arc.nim +++ b/lib/system/arc.nim @@ -26,6 +26,9 @@ else: rcMask = 0b111 rcShift = 3 # shift by rcShift to get the reference counter +const + orcLeakDetector = defined(nimOrcLeakDetector) + type RefHeader = object rc: int # the object header is now a single RC field. @@ -36,9 +39,21 @@ type # in O(1) without doubly linked lists when defined(nimArcDebug) or defined(nimArcIds): refId: int + when defined(gcOrc) and orcLeakDetector: + filename: cstring + line: int Cell = ptr RefHeader +template setFrameInfo(c: Cell) = + when orcLeakDetector: + if framePtr != nil and framePtr.prev != nil: + c.filename = framePtr.prev.filename + c.line = framePtr.prev.line + else: + c.filename = nil + c.line = 0 + template head(p: pointer): Cell = cast[Cell](cast[int](p) -% sizeof(RefHeader)) @@ -87,6 +102,7 @@ proc nimNewObj(size, alignment: int): pointer {.compilerRtl.} = cfprintf(cstderr, "[nimNewObj] %p %ld\n", result, head(result).count) when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) + setFrameInfo head(result) proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} = # Same as 'newNewObj' but do not initialize the memory to zero. @@ -109,6 +125,7 @@ proc nimNewObjUninit(size, alignment: int): pointer {.compilerRtl.} = when traceCollector: cprintf("[Allocated] %p result: %p\n", result -! sizeof(RefHeader), result) + setFrameInfo head(result) proc nimDecWeakRef(p: pointer) {.compilerRtl, inl.} = decrement head(p) diff --git a/lib/system/excpt.nim b/lib/system/excpt.nim index 210b1a525..dae5c4a4a 100644 --- a/lib/system/excpt.nim +++ b/lib/system/excpt.nim @@ -73,8 +73,12 @@ type when NimStackTraceMsgs: var frameMsgBuf* {.threadvar.}: string + +when not defined(nimV2): + var + framePtr {.threadvar.}: PFrame + var - framePtr {.threadvar.}: PFrame currException {.threadvar.}: ref Exception when not gotoBasedExceptions: diff --git a/lib/system/orc.nim b/lib/system/orc.nim index 335d49d0f..463c40c4d 100644 --- a/lib/system/orc.nim +++ b/lib/system/orc.nim @@ -81,10 +81,14 @@ proc trace(s: Cell; desc: PNimTypeV2; j: var GcEnv) {.inline.} = include threadids -when logOrc: +when logOrc or orcLeakDetector: proc writeCell(msg: cstring; s: Cell; desc: PNimTypeV2) = - cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld; thread: %ld\n", - msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color, getThreadId()) + when orcLeakDetector: + cfprintf(cstderr, "%s %s file: %s:%ld; color: %ld; thread: %ld\n", + msg, desc.name, s.filename, s.line, s.color, getThreadId()) + else: + cfprintf(cstderr, "%s %s %ld root index: %ld; RC: %ld; color: %ld; thread: %ld\n", + msg, desc.name, s.refId, s.rootIdx, s.rc shr rcShift, s.color, getThreadId()) proc free(s: Cell; desc: PNimTypeV2) {.inline.} = when traceCollector: @@ -338,6 +342,8 @@ proc collectCyclesBacon(j: var GcEnv; lowMark: int) = collectColor(s, roots.d[i][1], colToCollect, j) for i in 0 ..< j.toFree.len: + when orcLeakDetector: + writeCell("CYCLIC OBJECT FREED", j.toFree.d[i][0], j.toFree.d[i][1]) free(j.toFree.d[i][0], j.toFree.d[i][1]) inc j.freed, j.toFree.len @@ -352,6 +358,9 @@ when defined(nimStressOrc): else: var rootsThreshold {.threadvar.}: int +when defined(nimOrcStats): + var freedCyclicObjects {.threadvar.}: int + proc partialCollect(lowMark: int) = when false: if roots.len < 10 + lowMark: return @@ -365,6 +374,8 @@ proc partialCollect(lowMark: int) = roots.len - lowMark) roots.len = lowMark deinit j.traceStack + when defined(nimOrcStats): + inc freedCyclicObjects, j.freed proc collectCycles() = ## Collect cycles. @@ -405,6 +416,16 @@ proc collectCycles() = when logOrc: cfprintf(cstderr, "[collectCycles] end; freed %ld new threshold %ld touched: %ld mem: %ld rcSum: %ld edges: %ld\n", j.freed, rootsThreshold, j.touched, getOccupiedMem(), j.rcSum, j.edges) + when defined(nimOrcStats): + inc freedCyclicObjects, j.freed + +when defined(nimOrcStats): + type + OrcStats* = object ## Statistics of the cycle collector subsystem. + freedCyclicObjects*: int ## Number of freed cyclic objects. + proc GC_orcStats*(): OrcStats = + ## Returns the statistics of the cycle collector subsystem. + result = OrcStats(freedCyclicObjects: freedCyclicObjects) proc registerCycle(s: Cell; desc: PNimTypeV2) = s.rootIdx = roots.len+1 |