Miguel de Benito Delgado 756541939a
🔧 Add renderer benchmark runner (#12756)
Add a CLI under frontend/performance/benches/render_wasm that builds the
renderer, runs seeded scenes (rects, plus, paths, masks) in headless
Chromium and saves per-case timings.

- build, run: prepare or reuse builds; measure cases with warmups,
  repetitions, deadlines
- ab: build and compare Cargo feature configurations
- compare, merge: median changes with bootstrap CIs between saved runs,
  guarded by scene, build and settings checks
- purge: delete managed builds, runs or comparisons
- GPU runs through `run-devenv --gpu`

Lint, format and pnpm scripts now cover performance/ and its tests.

AI-assisted-by: gpt-6.1-sol, deepseek-flash, muse-spark, glm-5.3, gpt6-astra, claude-5.5-sonnet, claude-haiku-5.5
2026-11-12 11:02:34 +01:00

74 lines
2.5 KiB
Clojure

;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS SUBSIDIARY SL
(ns benches.render-wasm.random
"Seeded numbers for reproducible scene construction and report resampling.
A seed is an integer from 0 through 4294967295. Each call to `create` owns a
separate Mulberry32 state. Calling the returned function advances that state
and returns a number in [0,1). Equal seeds and equal numbers of calls produce
equal sequences, including seed zero."
(:require
[app.common.types.color :as clr]
[app.common.uuid :as uuid]))
(defn seed?
"Returns true for integers from 0 through 4294967295, inclusive."
[value]
(and (integer? value) (<= 0 value 4294967295)))
(defn create
"Returns a function that draws seeded numbers from [0, 1) using Mulberry32.
Each function owns its state. A seed outside the uint32 range throws
::invalid-seed; uint32 means an integer from 0 through 4294967295."
[seed]
(when-not (seed? seed)
(throw (ex-info "random seed must be an integer in [0, 2^32)"
{:type ::invalid-seed :seed seed})))
(let [state (volatile! (bit-or seed 0))]
(fn []
(let [s (bit-or (+ @state 0x6d2b79f5) 0)
_ (vreset! state s)
v (js/Math.imul (bit-xor s (unsigned-bit-shift-right s 15))
(bit-or s 1))
v (bit-xor v (+ v (js/Math.imul (bit-xor v (unsigned-bit-shift-right v 7))
(bit-or v 61))))
v (bit-xor v (unsigned-bit-shift-right v 14))]
(/ (unsigned-bit-shift-right v 0) 4294967296)))))
(defn round3
"Rounds to 3 decimal places"
[value]
(/ (js/Math.round (* 1000 value)) 1000))
(defn rng-float
"Draws a float in `[min, max)` from the random source."
[rng min max]
(+ min (* (rng) (- max min))))
(defn rng-int
"Draws an integer in `[min, max)` from the random source."
[rng min max]
(js/Math.floor (rng-float rng min max)))
(defn rng-uuid
"Draws a deterministic uuid from two 32-bit values of the random source."
[rng]
(uuid/custom (rng-int rng 0 4294967296)
(rng-int rng 0 4294967296)))
(defn rng-hex-color
"Draws a hex color from three RGB channels in [0,256)."
[rng]
(clr/rgb->hex [(rng-int rng 0 256) (rng-int rng 0 256) (rng-int rng 0 256)]))
(defn rng-opacity
"Draws opacity in [0.1,0.999], rounded to three decimal places."
[rng]
(min 0.999 (round3 (rng-float rng 0.1 1))))