first version of a memory profiler
This commit is contained in:
parent
cf06131dec
commit
d43febf81e
8 changed files with 115 additions and 54 deletions
|
|
@ -28,6 +28,8 @@ const
|
|||
|
||||
when withRealTime and not defined(getTicks):
|
||||
include "system/timers"
|
||||
when defined(memProfiler):
|
||||
proc nimProfile(requestedSize: int)
|
||||
|
||||
const
|
||||
rcIncrement = 0b1000 # so that lowest 3 bits are not touched
|
||||
|
|
@ -431,12 +433,15 @@ proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
|
|||
proc newObj(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
result = rawNewObj(typ, size, gch)
|
||||
zeroMem(result, size)
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
# `newObj` already uses locks, so no need for them here.
|
||||
result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||
result = newObj(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
||||
# generates a new object and sets its reference counter to 1
|
||||
|
|
@ -463,11 +468,14 @@ proc newObjRC1(typ: PNimType, size: int): pointer {.compilerRtl.} =
|
|||
result = cellToUsr(res)
|
||||
zeroMem(result, size)
|
||||
sysAssert(allocInv(gch.region), "newObjRC1 end")
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc newSeqRC1(typ: PNimType, len: int): pointer {.compilerRtl.} =
|
||||
result = newObjRC1(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
|
||||
let size = addInt(mulInt(len, typ.base.size), GenericSeqSize)
|
||||
result = newObjRC1(typ, size)
|
||||
cast[PGenericSeq](result).len = len
|
||||
cast[PGenericSeq](result).reserved = len
|
||||
when defined(memProfiler): nimProfile(size)
|
||||
|
||||
proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
||||
acquire(gch)
|
||||
|
|
@ -512,6 +520,7 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
|
|||
release(gch)
|
||||
result = cellToUsr(res)
|
||||
sysAssert(allocInv(gch.region), "growObj end")
|
||||
when defined(memProfiler): nimProfile(newsize-oldsize)
|
||||
|
||||
proc growObj(old: pointer, newsize: int): pointer {.rtl.} =
|
||||
result = growObj(old, newsize, gch)
|
||||
|
|
|
|||
|
|
@ -49,34 +49,51 @@ proc captureStackTrace(f: PFrame, st: var TStackTrace) =
|
|||
inc(i)
|
||||
b = b.prev
|
||||
|
||||
const
|
||||
SamplingInterval = 50_000
|
||||
# set this to change the default sampling interval
|
||||
var
|
||||
profilerHook*: TProfilerHook
|
||||
## set this variable to provide a procedure that implements a profiler in
|
||||
## user space. See the `nimprof` module for a reference implementation.
|
||||
gTicker {.threadvar.}: int
|
||||
when defined(memProfiler):
|
||||
type
|
||||
TMemProfilerHook* = proc (st: TStackTrace, requestedSize: int) {.nimcall.}
|
||||
var
|
||||
profilerHook*: TMemProfilerHook
|
||||
## set this variable to provide a procedure that implements a profiler in
|
||||
## user space. See the `nimprof` module for a reference implementation.
|
||||
|
||||
proc callProfilerHook(hook: TProfilerHook) {.noinline.} =
|
||||
# 'noinline' so that 'nimProfile' does not perform the stack allocation
|
||||
# in the common case.
|
||||
var st: TStackTrace
|
||||
captureStackTrace(framePtr, st)
|
||||
hook(st)
|
||||
proc callProfilerHook(hook: TMemProfilerHook, requestedSize: int) =
|
||||
var st: TStackTrace
|
||||
captureStackTrace(framePtr, st)
|
||||
hook(st, requestedSize)
|
||||
|
||||
proc nimProfile() =
|
||||
## This is invoked by the compiler in every loop and on every proc entry!
|
||||
if gTicker == 0:
|
||||
gTicker = -1
|
||||
proc nimProfile(requestedSize: int) =
|
||||
if not isNil(profilerHook):
|
||||
# disable recursive calls: XXX should use try..finally,
|
||||
# but that's too expensive!
|
||||
let oldHook = profilerHook
|
||||
profilerHook = nil
|
||||
callProfilerHook(oldHook)
|
||||
profilerHook = oldHook
|
||||
gTicker = SamplingInterval
|
||||
dec gTicker
|
||||
callProfilerHook(profilerHook, requestedSize)
|
||||
else:
|
||||
const
|
||||
SamplingInterval = 50_000
|
||||
# set this to change the default sampling interval
|
||||
var
|
||||
profilerHook*: TProfilerHook
|
||||
## set this variable to provide a procedure that implements a profiler in
|
||||
## user space. See the `nimprof` module for a reference implementation.
|
||||
gTicker {.threadvar.}: int
|
||||
|
||||
proc callProfilerHook(hook: TProfilerHook) {.noinline.} =
|
||||
# 'noinline' so that 'nimProfile' does not perform the stack allocation
|
||||
# in the common case.
|
||||
var st: TStackTrace
|
||||
captureStackTrace(framePtr, st)
|
||||
hook(st)
|
||||
|
||||
proc nimProfile() =
|
||||
## This is invoked by the compiler in every loop and on every proc entry!
|
||||
if gTicker == 0:
|
||||
gTicker = -1
|
||||
if not isNil(profilerHook):
|
||||
# disable recursive calls: XXX should use try..finally,
|
||||
# but that's too expensive!
|
||||
let oldHook = profilerHook
|
||||
profilerHook = nil
|
||||
callProfilerHook(oldHook)
|
||||
profilerHook = oldHook
|
||||
gTicker = SamplingInterval
|
||||
dec gTicker
|
||||
|
||||
{.pop.}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue