luv

Workshop wiki

tracy-capture-tests.lisp

hal/tracy-capture-tests.lisp

system luv/tracy-capture/test · 29 definitions · on GitHub

defpackage#:luv.tracy.capture.tests
:use#:cl#:rove
in-package#:luv.tracy.capture.tests
defclassscripted-tracy-process
role:initarg:role:readerscripted-process-role
pathname:initarg:pathname:initformnil:readerscripted-process-pathname
lock:initform
sb-thread:make-mutex:name"scripted Tracy process"
:readerscripted-process-lock
completion:initform
sb-thread:make-semaphore:name"scripted Tracy completion"
:readerscripted-process-completion
alive-p:initformt:accessorscripted-process-alive-p
exit-code:initarg:exit-code:initform0:accessorscripted-process-exit-code
wait-error:initarg:wait-error:initformnil:readerscripted-process-wait-error
interrupts:initform0:accessorscripted-process-interrupts
terminations:initform0:accessorscripted-process-terminations
closes:initform0:accessorscripted-process-closes
defclassscripted-tracy-runtime
lock:initform
sb-thread:make-mutex:name"scripted Tracy runtime"
:readerscripted-runtime-lock
now:initarg:now:initform
encode-universal-time5432120260
:accessorscripted-runtime-now
connected-p:initarg:connected-p:initformnil:accessorscripted-runtime-connected-p
prepare-error:initarg:prepare-error:initformnil:accessorscripted-runtime-prepare-error
prepare-count:initform0:accessorscripted-runtime-prepare-count
launch-error-role:initarg:launch-error-role:initformnil:accessorscripted-runtime-launch-error-role
capture-launch-gate:initarg:capture-launch-gate:initformnil:accessorscripted-runtime-capture-launch-gate
interrupt-gate:initarg:interrupt-gate:initformnil:accessorscripted-runtime-interrupt-gate
interrupt-failures:initarg:interrupt-failures:initform0:accessorscripted-runtime-interrupt-failures
auxiliary-launch-gate:initarg:auxiliary-launch-gate:initformnil:accessorscripted-runtime-auxiliary-launch-gate
capture-wait-error:initarg:capture-wait-error:initformnil:accessorscripted-runtime-capture-wait-error
capture-exit-code:initarg:capture-exit-code:initform0:accessorscripted-runtime-capture-exit-code
write-output-p:initarg:write-output-p:initformt:accessorscripted-runtime-write-output-p
existing-pathnames:initform
make-hash-table:test#'equal
:readerscripted-runtime-existing-pathnames
launches:initformnil:accessorscripted-runtime-launches
processes:initformnil:accessorscripted-runtime-processes
defmethodluv.tracy.capture:tracy-clock-now
scripted-runtime-nowruntime
defmethodluv.tracy.capture:tracy-path-exists-p
pathname
sb-thread:with-mutex
scripted-runtime-lockruntime
not
null
gethash
namestringpathname
scripted-runtime-existing-pathnamesruntime
defmethodluv.tracy.capture:prepare-tracy-client
application-name
declare
ignoreapplication-name
sb-thread:with-mutex
scripted-runtime-lockruntime
incf
scripted-runtime-prepare-countruntime
when
scripted-runtime-prepare-errorruntime
error
scripted-runtime-prepare-errorruntime
t
defmethodluv.tracy.capture:tracy-viewer-connected-p
scripted-runtime-connected-pruntime
defmethodluv.tracy.capture:resolve-tracy-program
declare
ignoreruntime
ecaserole
:capture#P"/scripted/tracy-capture"
:profiler#P"/scripted/tracy-profiler"
:reveal#P"/scripted/reveal"
defmethodluv.tracy.capture:launch-tracy-process
roleprogramarguments
let
gate
if
eqrole:capture
scripted-runtime-capture-launch-gateruntime
scripted-runtime-auxiliary-launch-gateruntime
whengate
unless
sb-thread:wait-on-semaphoregate:timeout1.0
error"Scripted Tracy launch gate timed out."
when
eqrole
scripted-runtime-launch-error-roleruntime
error"Scripted Tracy ~(~A~) launch failed."role
let
process
make-instance'scripted-tracy-process:rolerole:pathname
and
eqrole:capture
pathname
secondarguments
:exit-code
if
eqrole:capture
scripted-runtime-capture-exit-coderuntime
0
:wait-error
and
eqrole:capture
scripted-runtime-capture-wait-errorruntime
sb-thread:with-mutex
scripted-runtime-lockruntime
push
listroleprogram
copy-listarguments
scripted-runtime-launchesruntime
pushprocess
scripted-runtime-processesruntime
unless
eqrole:capture
setf
scripted-process-alive-pprocess
nil
sb-thread:signal-semaphore
scripted-process-completionprocess
process
defmethodluv.tracy.capture:tracy-process-alive-p
declare
ignoreruntime
sb-thread:with-mutex
scripted-process-lockprocess
scripted-process-alive-pprocess
defmethodluv.tracy.capture:interrupt-tracy-process
let
gate
scripted-runtime-interrupt-gateruntime
whengate
unless
sb-thread:wait-on-semaphoregate:timeout1.0
error"Scripted Tracy interrupt gate timed out."
sb-thread:with-mutex
scripted-process-lockprocess
incf
scripted-process-interruptsprocess
when
plusp
scripted-runtime-interrupt-failuresruntime
decf
scripted-runtime-interrupt-failuresruntime
error"Scripted Tracy interrupt failed."
when
scripted-process-alive-pprocess
setf
scripted-process-alive-pprocess
nil
when
and
scripted-runtime-write-output-pruntime
scripted-process-pathnameprocess
sb-thread:with-mutex
scripted-runtime-lockruntime
setf
gethash
namestring
scripted-process-pathnameprocess
scripted-runtime-existing-pathnamesruntime
t
sb-thread:signal-semaphore
scripted-process-completionprocess
t
defmethodluv.tracy.capture:terminate-tracy-process
declare
ignoreruntime
sb-thread:with-mutex
scripted-process-lockprocess
incf
scripted-process-terminationsprocess
setf
scripted-process-alive-pprocess
nil
sb-thread:signal-semaphore
scripted-process-completionprocess
t
defmethodluv.tracy.capture:wait-tracy-process
declare
ignoreruntime
when
scripted-process-wait-errorprocess
error
scripted-process-wait-errorprocess
unless
sb-thread:wait-on-semaphore
scripted-process-completionprocess
:timeout1.0
error"Scripted Tracy process did not finish."
process
defmethodluv.tracy.capture:tracy-process-exit-code
declare
ignoreruntime
scripted-process-exit-codeprocess
defmethodluv.tracy.capture:close-tracy-process
declare
ignoreruntime
sb-thread:with-mutex
scripted-process-lockprocess
incf
scripted-process-closesprocess
t
defunmake-scripted-controller
runtime&key
graceful-stop-seconds5.0d0
luv.tracy.capture:make-tracy-capture-controller:application-name"Test Game":directory
uiop:temporary-directory
:runtimeruntime:graceful-stop-secondsgraceful-stop-seconds:open-on-completion-pnil
defunwait-for-tracy-test
predicate&key
timeout1.0
loopwithdeadline=
+
get-internal-real-time
*timeoutinternal-time-units-per-second
when
funcallpredicate
returntwhen
>=
get-internal-real-time
deadline
returnnildo
sleep1/1000
defunscripted-capture-process
runtime
sb-thread:with-mutex
scripted-runtime-lockruntime
find:capture
scripted-runtime-processesruntime
:key#'scripted-process-role
defunscripted-launches
runtime
sb-thread:with-mutex
scripted-runtime-lockruntime
reverse
copy-tree
scripted-runtime-launchesruntime
deftesttracy-capture-launch-is-off-caller-and-uses-the-exact-program
let*
gate
sb-thread:make-semaphore:name"Tracy launch gate"
runtime
make-instance'scripted-tracy-runtime:capture-launch-gategate
controller
started
get-internal-real-time
elapsed
/
-
get-internal-real-time
started
coerceinternal-time-units-per-second'double-float
ok
<elapsed0.2d0
"START does not wait for the injected launcher"
ok
search"test-game-20260102-030405Z"
namestringpathname
sb-thread:signal-semaphoregate
destructuring-bind
roleprogramarguments
first
ok
eq:capturerole
ok
equal#P"/scripted/tracy-capture"program
ok
equal
list"-o"
namestringpathname
"-a""127.0.0.1"
arguments
deftesttracy-path-reservation-skips-an-existing-capture-at-the-same-clock
let*

Revisit serial zero at the identical injected clock. The first exact candidate now exists, so reservation must advance rather than spin or overwrite it.

sb-thread:with-mutex
luv.tracy.capture::tracy-capture-lockcontroller
setf
luv.tracy.capture::tracy-capture-serialcontroller
0
let*
started
get-internal-real-time
elapsed
/
-
get-internal-real-time
started
coerceinternal-time-units-per-second'double-float
ok
<elapsed0.2d0
ok
not
equalfirstsecond
ok
search"-1.tracy"
namestringsecond
deftestconcurrent-tracy-stops-emit-one-interrupt-and-one-close
let*
runtime
controller
let
threads
looprepeat12collect
sb-thread:make-thread
dolist
threadthreads
sb-thread:join-threadthread
let
ok
=1
scripted-process-interruptsprocess
ok
=1
scripted-process-closesprocess
deftestcapture-owner-retries-transient-interrupt-failures
let*
runtime
make-instance'scripted-tracy-runtime:interrupt-failures2
controller
let
ok
=3
scripted-process-interruptsprocess
ok
=0
scripted-process-terminationsprocess
ok
=1
scripted-process-closesprocess
ok
equal'
:stop:stop
mapcar#'luv.tracy.capture:tracy-capture-diagnostic-operation
deftestpersistent-interrupt-failure-cannot-orphan-a-released-capture
let*
runtime
make-instance'scripted-tracy-runtime:interrupt-failures20
controller

Model an application adapter dropping its last reference immediately. The generation-owning closure still retries and finally terminates its exact child before releasing the Lisp process handle.

ok
wait-for-tracy-test
lambda
let
andprocess
=1
scripted-process-terminationsprocess
=1
scripted-process-closesprocess
let
ok
=3
scripted-process-interruptsprocess
ng
scripted-process-alive-pprocess
ok
member:terminate
mapcar#'luv.tracy.capture:tracy-capture-diagnostic-operation
deftesttracy-stop-does-not-wait-for-interrupt-or-finalization
let*
gate
sb-thread:make-semaphore:name"Tracy interrupt gate"
runtime
make-instance'scripted-tracy-runtime:interrupt-gategate
controller
let
started
get-internal-real-time
ok
<
/
-
get-internal-real-time
started
coerceinternal-time-units-per-second'double-float
0.2d0
sb-thread:signal-semaphoregate
deftestfailed-tracy-launch-is-contained-and-controller-recovers
let*
runtime
make-instance'scripted-tracy-runtime:launch-error-role:capture
controller
let
ok
eq:start
luv.tracy.capture:tracy-capture-diagnostic-operationdiagnostic
ok
typep
luv.tracy.capture:tracy-capture-diagnostic-conditiondiagnostic
'error
setf
scripted-runtime-launch-error-roleruntime
nil
deftestfailed-tracy-finalizer-is-contained-and-closes-the-handle
let*
runtime
make-instance'scripted-tracy-runtime:capture-wait-error
make-condition'simple-error:format-control"scripted wait failure"
controller

The owner observes exit before it performs the injected failing reap. Request a normal stop so this test exercises that finalization edge rather than leaving the scripted capture intentionally alive.

let
ok
=1
scripted-process-closesprocess
ok
eq:finalize
luv.tracy.capture:tracy-capture-diagnostic-operationdiagnostic
deftesttracy-profiler-open-is-off-caller-and-failure-is-diagnostic
let*
runtime
controller
let
gate
sb-thread:make-semaphore:name"Tracy profiler gate"
setf
scripted-runtime-auxiliary-launch-gateruntime
gate
scripted-runtime-launch-error-roleruntime
:profiler
let
started
get-internal-real-time
ok
ok
<
/
-
get-internal-real-time
started
coerceinternal-time-units-per-second'double-float
0.2d0
sb-thread:signal-semaphoregate
ok
wait-for-tracy-test
lambda
let
anddiagnostic
eq:open
luv.tracy.capture:tracy-capture-diagnostic-operationdiagnostic
deftesttracy-controller-release-is-immediate-terminal-and-idempotent
let*
gate
sb-thread:make-semaphore:name"Tracy release launch gate"
runtime
make-instance'scripted-tracy-runtime:capture-launch-gategate
controller
let
started
get-internal-real-time
ok
<
/
-
get-internal-real-time
started
coerceinternal-time-units-per-second'double-float
0.2d0
sb-thread:signal-semaphoregate
ok
wait-for-tracy-test
lambda
let
andprocess
=1
scripted-process-interruptsprocess
=1
scripted-process-closesprocess