modified the integrated profiler to hopefully produce more reliable results

This commit is contained in:
Andreas Rumpf 2015-12-18 01:47:39 +01:00
commit f75d11193a
2 changed files with 35 additions and 28 deletions

View file

@ -1,7 +1,7 @@
# #
# #
# Nim's Runtime Library # Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2015 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -117,24 +117,38 @@ when defined(memProfiler):
var var
gTicker {.threadvar.}: int gTicker {.threadvar.}: int
proc hook(st: StackTrace, size: int) {.nimcall.} = proc requestedHook(): bool {.nimcall.} =
if gTicker == 0: if gTicker == 0:
gTicker = -1 gTicker = SamplingInterval
result = true
dec gTicker
proc hook(st: StackTrace, size: int) {.nimcall.} =
when defined(ignoreAllocationSize): when defined(ignoreAllocationSize):
hookAux(st, 1) hookAux(st, 1)
else: else:
hookAux(st, size) hookAux(st, size)
gTicker = SamplingInterval
dec gTicker
else: else:
var var
t0 {.threadvar.}: Ticks t0 {.threadvar.}: Ticks
gTicker: int # we use an additional counter to
# avoid calling 'getTicks' too frequently
proc requestedHook(): bool {.nimcall.} =
if interval == 0: result = true
elif gTicker == 0:
gTicker = 500
if getTicks() - t0 > interval:
result = true
else:
dec gTicker
proc hook(st: StackTrace) {.nimcall.} = proc hook(st: StackTrace) {.nimcall.} =
#echo "profiling! ", interval
if interval == 0: if interval == 0:
hookAux(st, 1) hookAux(st, 1)
elif int64(t0) == 0 or getTicks() - t0 > interval: else:
hookAux(st, 1) hookAux(st, 1)
t0 = getTicks() t0 = getTicks()
@ -145,9 +159,10 @@ proc cmpEntries(a, b: ptr ProfileEntry): int =
result = b.getTotal - a.getTotal result = b.getTotal - a.getTotal
proc `//`(a, b: int): string = proc `//`(a, b: int): string =
result = format("$1/$2 = $3%", a, b, formatFloat(a / b * 100.0, ffDefault, 2)) result = format("$1/$2 = $3%", a, b, formatFloat(a / b * 100.0, ffDecimal, 2))
proc writeProfile() {.noconv.} = proc writeProfile() {.noconv.} =
system.profilingRequestedHook = nil
when declared(system.StackTrace): when declared(system.StackTrace):
system.profilerHook = nil system.profilerHook = nil
const filename = "profile_results.txt" const filename = "profile_results.txt"
@ -193,12 +208,12 @@ var
proc disableProfiling*() = proc disableProfiling*() =
when declared(system.StackTrace): when declared(system.StackTrace):
atomicDec disabled atomicDec disabled
system.profilerHook = nil system.profilingRequestedHook = nil
proc enableProfiling*() = proc enableProfiling*() =
when declared(system.StackTrace): when declared(system.StackTrace):
if atomicInc(disabled) >= 0: if atomicInc(disabled) >= 0:
system.profilerHook = hook system.profilingRequestedHook = requestedHook
when declared(system.StackTrace): when declared(system.StackTrace):
system.profilerHook = hook system.profilerHook = hook

View file

@ -50,10 +50,15 @@ proc captureStackTrace(f: PFrame, st: var StackTrace) =
inc(i) inc(i)
b = b.prev b = b.prev
var
profilingRequestedHook*: proc (): bool {.nimcall, benign.}
## set this variable to provide a procedure that implements a profiler in
## user space. See the `nimprof` module for a reference implementation.
when defined(memProfiler): when defined(memProfiler):
type type
MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, benign.} MemProfilerHook* = proc (st: StackTrace, requestedSize: int) {.nimcall, benign.}
{.deprecated: [TMemProfilerHook: MemProfilerHook].}
var var
profilerHook*: MemProfilerHook profilerHook*: MemProfilerHook
## set this variable to provide a procedure that implements a profiler in ## set this variable to provide a procedure that implements a profiler in
@ -65,17 +70,13 @@ when defined(memProfiler):
hook(st, requestedSize) hook(st, requestedSize)
proc nimProfile(requestedSize: int) = proc nimProfile(requestedSize: int) =
if not isNil(profilerHook): if not isNil(profilingRequestedHook) and profilingRequestedHook():
callProfilerHook(profilerHook, requestedSize) callProfilerHook(profilerHook, requestedSize)
else: else:
const
SamplingInterval = 50_000
# set this to change the default sampling interval
var var
profilerHook*: ProfilerHook profilerHook*: ProfilerHook
## set this variable to provide a procedure that implements a profiler in ## set this variable to provide a procedure that implements a profiler in
## user space. See the `nimprof` module for a reference implementation. ## user space. See the `nimprof` module for a reference implementation.
gTicker {.threadvar.}: int
proc callProfilerHook(hook: ProfilerHook) {.noinline.} = proc callProfilerHook(hook: ProfilerHook) {.noinline.} =
# 'noinline' so that 'nimProfile' does not perform the stack allocation # 'noinline' so that 'nimProfile' does not perform the stack allocation
@ -86,16 +87,7 @@ else:
proc nimProfile() = proc nimProfile() =
## This is invoked by the compiler in every loop and on every proc entry! ## This is invoked by the compiler in every loop and on every proc entry!
if gTicker == 0: if not isNil(profilingRequestedHook) and profilingRequestedHook():
gTicker = -1 callProfilerHook(profilerHook)
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.} {.pop.}