mirror of
https://github.com/nim-lang/Nim.git
synced 2026-08-30 18:41:45 +00:00
ORC: added -d:nimOrcStats switch and related API (#23272)
This commit is contained in:
@@ -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`
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user