summary refs log tree commit diff stats
path: root/lib/system
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-10-10 00:41:34 +0200
committerAraq <rumpf_a@web.de>2012-10-10 00:41:34 +0200
commitd43febf81e78ac79894ab136717c6100a5492b08 (patch)
tree451569132c56fb42c39313f81e7a8e895fff6376 /lib/system
parentcf06131decb2d46304874bd243c29267876e0076 (diff)
downloadNim-d43febf81e78ac79894ab136717c6100a5492b08.tar.gz
first version of a memory profiler
Diffstat (limited to 'lib/system')
-rwxr-xr-xlib/system/gc.nim13
-rwxr-xr-xlib/system/profiler.nim69
2 files changed, 54 insertions, 28 deletions
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index a95319e51..ec656e0ef 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -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)
diff --git a/lib/system/profiler.nim b/lib/system/profiler.nim
index eafa010ef..8e4c51dd9 100755
--- a/lib/system/profiler.nim
+++ b/lib/system/profiler.nim
@@ -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.}