Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port of the existing profiler to Chronos V4 #7

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f9909c4
futures profiling instrumentation
elcritch Oct 26, 2023
ac6c22c
futures profiling instrumentation
elcritch Oct 26, 2023
0a14f70
fix test timing
elcritch Oct 27, 2023
74e5eba
fix onFuturePause using template arg, not future object
elcritch Oct 31, 2023
bd656ab
fix onFuturePause using template arg, not future object
elcritch Oct 31, 2023
d0ed08c
non-procs
elcritch Nov 2, 2023
d4809d5
add harness and initial test
gmega Nov 22, 2023
8b5c6a4
add harness for simulating profiled time and basic profiler metric test
gmega Nov 24, 2023
81711f8
add support for blocking children
gmega Nov 24, 2023
ce1e03a
add test for simple non-blocking future
gmega Nov 27, 2023
a5fb393
add test for future with a single non-blocking child
gmega Nov 27, 2023
e65c48c
add tests for exceptions, cancellation, and multiple pauses
gmega Nov 27, 2023
d320e2a
change enable flag to "chronosProfiling"; add "enable" profiler proc;…
gmega Nov 27, 2023
d80fa15
add call count and max exec time; rename enable => enableProfiling to…
gmega Nov 27, 2023
128531c
add accessor to exec time + children, type aliases, minor refactor
gmega Nov 27, 2023
1d5d02c
add location info to assertions to make them easier to trace
gmega Nov 28, 2023
ade1f30
add failing test case for an async proc with children in its finally …
gmega Nov 28, 2023
b64014c
remove example file (included by accident)
gmega Nov 29, 2023
9f9b314
add zombie track test, strenghten zombie event spec test
gmega Nov 29, 2023
9883d7d
add zombie checks to run state too
gmega Nov 29, 2023
3f774a1
enable future ID; add extra debug info
gmega Dec 1, 2023
5d27b12
move instrumentation points for async future FSM into more correct lo…
gmega Dec 7, 2023
8ffe7f4
improve assertion error messages
gmega Dec 7, 2023
321b6c7
capitalize test suite names to make it consistent with the rest
gmega Dec 7, 2023
eb7cf1a
enable profiling on testprofiler; import/export profiler from chronos…
gmega Dec 7, 2023
7474c52
remove profiler export from main module; disable profiler in tests by…
gmega Dec 8, 2023
c960f96
rename states and callbacks to reflect current domain understanding
gmega Dec 8, 2023
4916381
Merge branch 'master' into feature/profiler-v4
gmega Jan 22, 2024
f007e1b
initial port of profiler to Chronos V4
gmega Jan 31, 2024
a68de9f
Merge branch 'master' into feature/profiler-v4
gmega Jan 31, 2024
c8899eb
remove profiler from Chronos, keep only instrumentation code
gmega Mar 1, 2024
03c221f
Merge branch 'master' into feature/profiler-v4
gmega Mar 1, 2024
b26b648
remove lines carried over from merge
gmega Mar 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions chronos.nimble
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ task test_libbacktrace, "test with libbacktrace":
run args & " --mm:refc", "tests/testall"
run args, "tests/testall"

task test_profiler, "test with profiler instrumentation":
var allArgs = @[
"-d:release -d:chronosFutureId -d:chronosProfiling",
]

for args in allArgs:
run args, "tests/testall"

task docs, "Generate API documentation":
exec "mdbook build docs"
exec nimc & " doc " & "--git.url:https://github.com/status-im/nim-chronos --git.commit:master --outdir:docs/book/api --project chronos"
7 changes: 6 additions & 1 deletion chronos/config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ const
chronosStackTrace* {.booldefine.}: bool = defined(chronosDebug)
## Include stack traces in futures for creation and completion points

chronosFutureId* {.booldefine.}: bool = defined(chronosDebug)
chronosProfiling* {.booldefine.} = defined(chronosProfiling)
## Enable instrumentation callbacks which are called at
## the start, pause, or end of a Future's lifetime.
## Useful for implementing metrics or other instrumentation.

chronosFutureId* {.booldefine.}: bool = defined(chronosDebug) or chronosProfiling
## Generate a unique `id` for every future - when disabled, the address of
## the future will be used instead

Expand Down
11 changes: 11 additions & 0 deletions chronos/futures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ when chronosFutureTracking:

var futureList* {.threadvar.}: FutureList

when chronosProfiling:
type AsyncFutureState* {.pure.} = enum
Running, Paused

var onBaseFutureEvent* {.threadvar.}: proc (fut: FutureBase, state: FutureState): void {.nimcall, gcsafe, raises: [].}
var onAsyncFutureEvent* {.threadvar.}: proc(fut: FutureBase, state: AsyncFutureState): void {.nimcall, gcsafe, raises: [].}

# Internal utilities - these are not part of the stable API
proc internalInitFutureBase*(fut: FutureBase, loc: ptr SrcLoc,
state: FutureState, flags: FutureFlags) =
Expand Down Expand Up @@ -144,6 +151,10 @@ proc internalInitFutureBase*(fut: FutureBase, loc: ptr SrcLoc,
futureList.head = fut
futureList.count.inc()

when chronosProfiling:
if not isNil(onBaseFutureEvent):
onBaseFutureEvent(fut, state)

# Public API
template init*[T](F: type Future[T], fromProc: static[string] = ""): Future[T] =
## Creates a new pending future.
Expand Down
13 changes: 13 additions & 0 deletions chronos/internal/asyncfutures.nim
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ proc finish(fut: FutureBase, state: FutureState) =
# 1. `finish()` is a private procedure and `state` is under our control.
# 2. `fut.state` is checked by `checkFinished()`.
fut.internalState = state

when chronosProfiling:
if not isNil(onBaseFutureEvent):
onBaseFutureEvent(fut, state)

fut.internalCancelcb = nil # release cancellation callback memory
for item in fut.internalCallbacks.mitems():
if not(isNil(item.function)):
Expand Down Expand Up @@ -376,6 +381,10 @@ proc futureContinue*(fut: FutureBase) {.raises: [], gcsafe.} =
#
# Every call to an `{.async.}` proc is redirected to call this function
# instead with its original body captured in `fut.closure`.
when chronosProfiling:
if not isNil(onAsyncFutureEvent):
onAsyncFutureEvent(fut, Running)

while true:
# Call closure to make progress on `fut` until it reaches `yield` (inside
# `await` typically) or completes / fails / is cancelled
Expand All @@ -393,6 +402,10 @@ proc futureContinue*(fut: FutureBase) {.raises: [], gcsafe.} =
GC_ref(fut)
next.addCallback(CallbackFunc(internalContinue), cast[pointer](fut))

when chronosProfiling:
if not isNil(onAsyncFutureEvent):
onAsyncFutureEvent(fut, Paused)

# return here so that we don't remove the closure below
return

Expand Down