Where a settle spends its wall clock, attributed to the four cost centres — one switch, off by default, free when off.
vaelii.impl.profile counts what the index is asked; this is its wall-clock twin
for belief. The question a parallelism study asks is which phase of a bulk settle
owns the time, and the four centres a settle divides into are:
:belief — the belief fixpoint: clear-defeats!, the revival reconcile, the
defeat!/refresh-after-defeat relabel inside resolve-contradictions, and the
add-justification replay recovery/rebuild-tms composes. The relabel is the work
settle-parallelism.md's partition-relabel candidate would divide.:discovery — the nogood scans constraint-nogoods, negation-nogoods and
preserving-nogoods, the read-only clash-finding a clash-discovery candidate would
run in parallel.:resolution — the decision resolve-contradictions takes over the nogoods it
was handed: decide-nogood and the edge solver, minus the discovery and the relabel
the decision drives (those are charged to their own centres).:chaining — the generative join chain / chain-all runs, the forward
inference a parallel-chaining candidate would divide. A bulk load fires it per
assert; a recover does not fire it at all.Two sentinels catch the time no centre names: :finish is settle-finish's
cache reconcile and exposure sweeps, :glue is settle-loop bookkeeping between
the spans, and :outside is everything between one settle and the next — the
assert path's canonicalization, checks, index and minting.
The centres nest: resolve-contradictions calls the discovery scans and drives the
relabel, chain drives its own add-justification. So a phase is charged only its
self-time — the interval while its span is on top of the stack. Entering a nested
span charges the parent up to that instant and pauses it; leaving resumes it. The six
buckets therefore partition the whole run and sum to it, which an inclusive reading
(parent time counting its children twice) does not.
The switch and the store are one atom, nil when off, so with-phase off a timing run
is a deref and a nil? check, which is what vaelii.impl.profile costs its call
sites. add-justification is not wrapped — it is charged through the :belief span
its driver opens (defeat!, rebuild-tms) or the :chaining span its driver opens
(chain) — so the per-assert JTMS path carries no probe at all.
On, it is two System/nanoTime reads and two mutations of an unsynchronized
ArrayDeque/HashMap per span. A settle is single-writer (docs/nmtms.md), so the
store is mutated in place with no lock, and a run under the instrument answers the
same belief as one without it, more slowly — the bargain profile already takes.
stop returns plain data: the run totals per centre, and a per-settle record carrying
each centre's self-time, the settle's relabelled region size and its pass count. The
region size is what a mean over settles hides — one root-edge retraction moves the
whole graph and a leaf edge moves nothing — so the record is per settle and the
percentiles are the caller's to take. vaelii.bench.settle-phases is the caller that
has an opinion; nothing here formats.
Where a settle spends its **wall clock**, attributed to the four cost centres — one switch, off by default, free when off. `vaelii.impl.profile` counts what the index is *asked*; this is its wall-clock twin for belief. The question a parallelism study asks is which phase of a bulk settle owns the time, and the four centres a settle divides into are: * **`:belief`** — the belief fixpoint: `clear-defeats!`, the revival reconcile, the `defeat!`/`refresh-after-defeat` relabel inside `resolve-contradictions`, and the `add-justification` replay `recovery/rebuild-tms` composes. The relabel is the work `settle-parallelism.md`'s partition-relabel candidate would divide. * **`:discovery`** — the nogood scans `constraint-nogoods`, `negation-nogoods` and `preserving-nogoods`, the read-only clash-finding a clash-discovery candidate would run in parallel. * **`:resolution`** — the decision `resolve-contradictions` takes over the nogoods it was handed: `decide-nogood` and the edge solver, minus the discovery and the relabel the decision drives (those are charged to their own centres). * **`:chaining`** — the generative join `chain` / `chain-all` runs, the forward inference a parallel-chaining candidate would divide. A bulk load fires it per assert; a `recover` does not fire it at all. Two sentinels catch the time no centre names: **`:finish`** is `settle-finish`'s cache reconcile and exposure sweeps, **`:glue`** is settle-loop bookkeeping between the spans, and **`:outside`** is everything between one settle and the next — the assert path's canonicalization, checks, index and minting. ## Self-time, not inclusive time The centres nest: `resolve-contradictions` calls the discovery scans and drives the relabel, `chain` drives its own `add-justification`. So a phase is charged only its **self-time** — the interval while its span is on top of the stack. Entering a nested span charges the parent up to that instant and pauses it; leaving resumes it. The six buckets therefore partition the whole run and sum to it, which an inclusive reading (parent time counting its children twice) does not. ## Off by default, and free when off The switch and the store are one atom, nil when off, so `with-phase` off a timing run is a deref and a `nil?` check, which is what `vaelii.impl.profile` costs its call sites. `add-justification` is not wrapped — it is charged through the `:belief` span its driver opens (`defeat!`, `rebuild-tms`) or the `:chaining` span its driver opens (`chain`) — so the per-assert JTMS path carries no probe at all. On, it is two `System/nanoTime` reads and two mutations of an unsynchronized `ArrayDeque`/`HashMap` per span. A settle is single-writer (docs/nmtms.md), so the store is mutated in place with no lock, and a run under the instrument answers the same belief as one without it, more slowly — the bargain `profile` already takes. ## Reading it `stop` returns plain data: the run totals per centre, and a per-settle record carrying each centre's self-time, the settle's relabelled region size and its pass count. The region size is what a mean over settles hides — one root-edge retraction moves the whole graph and a leaf edge moves nothing — so the record is per settle and the percentiles are the caller's to take. `vaelii.bench.settle-phases` is the caller that has an opinion; nothing here formats.
(begin-settle!)Bracket the start of one settle: charge the pre-settle interval to :outside, then
start a fresh per-settle tally.
Bracket the start of one settle: charge the pre-settle interval to `:outside`, then start a fresh per-settle tally.
(end-settle!)Bracket the end of one settle: charge the tail, file the per-settle record, and mark the instrument outside a settle again.
Bracket the end of one settle: charge the tail, file the per-settle record, and mark the instrument outside a settle again.
(enter! p)Open a span for centre p: charge the parent up to now, then push p. A deref and a
nil? check when the instrument is off.
Open a span for centre `p`: charge the parent up to now, then push `p`. A deref and a `nil?` check when the instrument is off.
(leave!)Close the current span: charge it up to now, then pop. Guards an empty stack so a span entered while the instrument was off (and toggled on mid-span) cannot underflow.
Close the current span: charge it up to now, then pop. Guards an empty stack so a span entered while the instrument was off (and toggled on mid-span) cannot underflow.
(note-passes! n)Record this settle's pass count.
Record this settle's pass count.
(note-region! n)Record this settle's relabelled region size, read once at the finish.
Record this settle's relabelled region size, read once at the finish.
(profiling?)Is the instrument collecting?
Is the instrument collecting?
(snapshot)The tallies so far as plain data, or nil when the instrument is off:
{:run {centre nanos} whole-run self-time per centre
:settles [{:nanos {centre nanos} :total :region :passes} …]}
A read, not a stop — the run keeps collecting.
The tallies so far as plain data, or nil when the instrument is off:
{:run {centre nanos} whole-run self-time per centre
:settles [{:nanos {centre nanos} :total :region :passes} …]}
A read, not a stop — the run keeps collecting.(start)Begin collecting, dropping whatever a previous run left. Bare, not !: the tally is
derived from a workload nobody stored, so re-running the workload recomputes it.
Begin collecting, dropping whatever a previous run left. Bare, not `!`: the tally is derived from a workload nobody stored, so re-running the workload recomputes it.
(stop)Charge the final interval, return the snapshot, and clear the instrument.
Charge the final interval, return the snapshot, and clear the instrument.
(with-phase p & body)Run body inside a span for centre p. Off a timing run this is a deref, a nil?
check and the body; on one it brackets the body with enter!/leave! so the centre is
charged its self-time even if body throws.
Run `body` inside a span for centre `p`. Off a timing run this is a deref, a `nil?` check and the body; on one it brackets the body with `enter!`/`leave!` so the centre is charged its self-time even if `body` throws.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |