Liking cljdoc? Tell your friends :D

com.fulcrologic.fulcro.tui.perf

A tiny, babashka-compatible profiler — the core of Tufte (p profile points, a profile scope, and a println report) reimplemented with only plain atoms / volatiles / dynamic vars so it runs under SCI. (Real Tufte does NOT load under babashka: its encore dependency uses a defrecord implementing clojure.lang.Counted, which SCI rejects.)

Design goals:

  • Truly zero overhead unless explicitly built in. p and profile are compile-time gated on the fulcro.tui.perf system property: unless it is set when the calling code is macro-expanded, both expand to just (do body...) — no runtime check, no volatile read, no trace of profiling in the compiled code. So these points are safe to leave in shipped render code, and the shipped library (compiled without the property) carries no profiling at all.
  • No new dependencies. Lives in src/main (the shipped render code calls p directly), but pulls in nothing.
  • Self-time accounting. Each p records both total (inclusive) and self (exclusive of nested ps) time, so it is safe to instrument recursive code (e.g. the paint walker) and read a meaningful per-id breakdown.

Usage — first build the instrumentation IN by setting the property (JVM: -Dfulcro.tui.perf=1; babashka: bb -Dfulcro.tui.perf=1 ...), then while running the TUI:

(perf/start!) ; enable + reset ;; ... exercise the code / interact with the app ... (perf/report) ; print the per-id table (self-time ranked) (perf/stop!) ; disable

Or scope it: (perf/profile {} (render! app)) enables for the dynamic extent, prints a report, and returns the body value. Without the property set, start!/stop!/report still work but have nothing to measure, since no p points were compiled in.

A tiny, babashka-compatible profiler — the core of Tufte (`p` profile points, a `profile`
scope, and a println report) reimplemented with only plain atoms / volatiles / dynamic vars so
it runs under SCI. (Real Tufte does NOT load under babashka: its `encore` dependency uses a
`defrecord` implementing `clojure.lang.Counted`, which SCI rejects.)

Design goals:

* **Truly zero overhead unless explicitly built in.** `p` and `profile` are *compile-time*
  gated on the `fulcro.tui.perf` system property: unless it is set when the calling code is
  macro-expanded, both expand to just `(do body...)` — no runtime check, no volatile read, no
  trace of profiling in the compiled code. So these points are safe to leave in shipped render
  code, and the shipped library (compiled without the property) carries no profiling at all.
* **No new dependencies.** Lives in `src/main` (the shipped render code calls `p` directly), but
  pulls in nothing.
* **Self-time accounting.** Each `p` records both *total* (inclusive) and *self* (exclusive of
  nested `p`s) time, so it is safe to instrument recursive code (e.g. the paint walker) and read
  a meaningful per-id breakdown.

Usage — first build the instrumentation IN by setting the property (JVM: `-Dfulcro.tui.perf=1`;
babashka: `bb -Dfulcro.tui.perf=1 ...`), then while running the TUI:

  (perf/start!)        ; enable + reset
  ;; ... exercise the code / interact with the app ...
  (perf/report)        ; print the per-id table (self-time ranked)
  (perf/stop!)         ; disable

Or scope it: `(perf/profile {} (render! app))` enables for the dynamic extent, prints a report,
and returns the body value. Without the property set, `start!`/`stop!`/`report` still work but
have nothing to measure, since no `p` points were compiled in.
raw docstring

*children*clj

When inside a p, a volatile! accumulating the total (inclusive) ns of this point's DIRECT children, so the enclosing point can subtract it to get self time. nil at the top level.

When inside a `p`, a `volatile!` accumulating the total (inclusive) ns of this point's DIRECT
children, so the enclosing point can subtract it to get self time. `nil` at the top level.
sourceraw docstring

cacheclj

(cache f)
(cache {:keys [ttl-ms gc-every] :or {gc-every 1000}} f)

Returns a cached (memoized) version of referentially-transparent f.

Called with just f, entries are cached forever. Called with an options map, supports time-based expiry. The options are:

  • :ttl-ms - Expire each entry this many milliseconds after it was computed. Omitted or 0 means no expiry.
  • :gc-every - Sweep expired entries roughly once per this many calls (default 1000). Only relevant when :ttl-ms is set.

Like clojure.core/memoize but de-raced: concurrent first-calls for the same args run f exactly once (the loser's delay is discarded unforced), so it is safe under contention.

The returned fn also reads a command keyword as its FIRST argument:

  • :cache/del - Drop the entry for the remaining args; returns nil. Pass :cache/all as the next arg — (cached :cache/del :cache/all) — to clear everything.
  • :cache/fresh - Force a recompute (and re-store) for the remaining args; returns the new value.

Mirrors the call shape of taoensso.encore/cache (:mem/del/:mem/fresh/:mem/all are accepted as aliases) but is intentionally a small subset: no LRU/LFU size eviction.

Returns a cached (memoized) version of referentially-transparent `f`.

Called with just `f`, entries are cached forever. Called with an options map, supports
time-based expiry. The options are:

  * `:ttl-ms` - Expire each entry this many milliseconds after it was computed. Omitted or
    0 means no expiry.
  * `:gc-every` - Sweep expired entries roughly once per this many calls (default 1000).
    Only relevant when `:ttl-ms` is set.

Like `clojure.core/memoize` but de-raced: concurrent first-calls for the same args run `f`
exactly once (the loser's `delay` is discarded unforced), so it is safe under contention.

The returned fn also reads a command keyword as its FIRST argument:

  * `:cache/del`   - Drop the entry for the remaining args; returns nil. Pass
    `:cache/all` as the next arg — `(cached :cache/del :cache/all)` — to clear everything.
  * `:cache/fresh` - Force a recompute (and re-store) for the remaining args; returns the
    new value.

Mirrors the call shape of `taoensso.encore/cache` (`:mem/del`/`:mem/fresh`/`:mem/all` are
accepted as aliases) but is intentionally a small subset: no LRU/LFU size eviction.
sourceraw docstring

enabled?clj

(enabled?)

Returns true when profiling is currently capturing.

Returns true when profiling is currently capturing.
sourceraw docstring

memoizeclj

(memoize f)
(memoize ttl-ms f)

Encore-familiar wrapper over cache. (memoize f) caches forever; (memoize ttl-ms f) expires entries ttl-ms milliseconds after they are computed.

Encore-familiar wrapper over `cache`. `(memoize f)` caches forever; `(memoize ttl-ms f)`
expires entries `ttl-ms` milliseconds after they are computed.
sourceraw docstring

pcljmacro

(p id & body)

Profile point: times body under id (any value — keyword or syntax-quoted symbol) and returns its value.

Gated at compile time on the fulcro.tui.perf system property (see instrument?): when the property is unset this expands to just (do body...) — zero overhead, nothing compiled in. When it is set, this compiles in instrumentation that is still gated at RUNTIME by enabled?, so captured timing only accrues between start! and stop!. Records total (inclusive) and self (exclusive of nested ps) time.

Profile point: times `body` under `id` (any value — keyword or syntax-quoted symbol) and returns
its value.

Gated at compile time on the `fulcro.tui.perf` system property (see `instrument?`): when the
property is unset this expands to just `(do body...)` — zero overhead, nothing compiled in. When
it is set, this compiles in instrumentation that is still gated at RUNTIME by `enabled?`, so
captured timing only accrues between `start!` and `stop!`. Records total (inclusive) and self
(exclusive of nested `p`s) time.
sourceraw docstring

profilecljmacro

(profile _opts & body)

Brackets body with start!/stop!, prints a report, and returns the body's value. opts is accepted for Tufte-API familiarity but currently ignored.

Like p, gated at compile time on the fulcro.tui.perf system property: when it is unset this expands to just (do body...) (no start/stop/report), so it is a true no-op in a build without the property.

Brackets `body` with `start!`/`stop!`, prints a `report`, and returns the body's value.
`opts` is accepted for Tufte-API familiarity but currently ignored.

Like `p`, gated at compile time on the `fulcro.tui.perf` system property: when it is unset this
expands to just `(do body...)` (no start/stop/report), so it is a true no-op in a build without
the property.
sourceraw docstring

record!clj

(record! id total-ns self-ns)

Folds one observation for id (total-ns inclusive, self-ns exclusive) into stats. Public because the p macro expands to a call here, but normally only called via p.

Folds one observation for `id` (`total-ns` inclusive, `self-ns` exclusive) into `stats`.
Public because the `p` macro expands to a call here, but normally only called via `p`.
sourceraw docstring

reportclj

(report)

Prints report-string to stdout and returns nil.

Prints `report-string` to stdout and returns nil.
sourceraw docstring

report-stringclj

(report-string)

Returns the formatted profiling report as a string (rows sorted by self time, descending). Percentages are share of total SELF time across all ids — i.e. where CPU time actually went.

Returns the formatted profiling report as a string (rows sorted by self time, descending).
Percentages are share of total SELF time across all ids — i.e. where CPU time actually went.
sourceraw docstring

reset!clj

(reset!)

Clears all accumulated stats and restarts the wall-clock bracket.

Clears all accumulated stats and restarts the wall-clock bracket.
sourceraw docstring

snapshotclj

(snapshot)

Returns the current raw stats map (id -> aggregate), without printing.

Returns the current raw stats map (id -> aggregate), without printing.
sourceraw docstring

start!clj

(start!)

Enables profiling and clears prior stats. Call before exercising the code to measure.

Enables profiling and clears prior stats. Call before exercising the code to measure.
sourceraw docstring

stop!clj

(stop!)

Disables profiling and freezes the wall-clock elapsed.

Disables profiling and freezes the wall-clock elapsed.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close