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

52 lines
2.2 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.node.files
"Filesystem paths and storage for benchmark artifacts."
(:require
["fs" :as fs]
["path" :as path]
[benches.render-wasm.errors :as errors :refer-macros [attempt]]
[clojure.string :as str]))
(defn contained?
"True when `file` is `root` or a path below it."
[root file]
(let [relative (path/relative root file)]
(and (not (path/isAbsolute relative))
(not= relative "..")
(not (str/starts-with? relative (str ".." path/sep))))))
(defn get-real-path
"Resolves symlink ancestors even when the final path does not exist yet."
[file]
(let [file (path/resolve file)]
(if (fs/existsSync file)
(fs/realpathSync file)
(path/join (get-real-path (path/dirname file)) (path/basename file)))))
(defn atomic-write
"Writes (UTF-8) content to a temporary file and renames it over `file`,
so readers see either the previous complete file or the new one. The parent
directory must exist.
A failed write or rename leaves the previous file untouched and attempts to
remove the temporary file. Failures retain operation context in order."
[file content]
(let [temporary (str file "." (random-uuid) ".tmp")
written (attempt :catch-fatal
(fs/writeFileSync temporary content #js {:encoding "utf8" :flag "wx"})
nil)
renamed (when-not written
(attempt :catch-fatal (fs/renameSync temporary file) nil))
removed (when (or written renamed)
(attempt :catch-fatal (fs/rmSync temporary #js {:force true}) nil))]
(when-let [failure (errors/combine
[{:phase "storage" :operation :write-temporary :path file :error written}
{:phase "storage" :operation :rename-temporary :path file :error renamed}
{:phase "storage" :operation :remove-temporary :path temporary :error removed}])]
(throw failure))))