From a61c659221eb3e1b21c2707178c8a1f01be19947 Mon Sep 17 00:00:00 2001 From: Miguel de Benito Delgado Date: Tue, 10 Nov 2026 23:45:56 +0100 Subject: [PATCH] :recycle: Share renderer benchmark error handling Share construction of comparison storage failures and browser phase errors. Preserve occurrence order, operation context, causes and stale propagation. Use shared GPU setup guidance in command validation and runtime checks. Document how supplied outcome fields override default errors, exit codes and log paths. AI-assisted-by: gpt-6.1-sol --- .../benches/render_wasm/browser/bridge.cljs | 25 +++++------ .../render_wasm/node/cli/execution.cljs | 3 +- .../benches/render_wasm/node/outcome.cljs | 11 ++++- .../node/runner/feature_comparison.cljs | 41 +++++++++++-------- .../benches/render_wasm/node/runner/run.cljs | 3 +- .../benches/render_wasm/node/settings.cljs | 5 ++- 6 files changed, 51 insertions(+), 37 deletions(-) diff --git a/frontend/performance/benches/render_wasm/browser/bridge.cljs b/frontend/performance/benches/render_wasm/browser/bridge.cljs index 208aaab464..64f2857a47 100644 --- a/frontend/performance/benches/render_wasm/browser/bridge.cljs +++ b/frontend/performance/benches/render_wasm/browser/bridge.cljs @@ -594,6 +594,10 @@ {:epoch epoch :dims viewport}))) +(defn- phase-error + [phase message cause] + (ex-info message {:phase phase} cause)) + (defn- load-module "Loads and instantiates the renderer. @@ -609,9 +613,9 @@ [epoch params] (-> (ensure-module! (or (:module-url params) "./render-wasm.js") (or (:wasm-url params) "./render-wasm.wasm")) - (.catch #(throw (ex-info (str "module init failed: " (or (ex-message %) %)) - {:phase "module-init"} - %))) + (.catch #(throw (phase-error "module-init" + (str "module init failed: " (or (ex-message %) %)) + %))) (.then (fn [installed] (guard-current! epoch "module-init") installed)))) @@ -653,12 +657,9 @@ :browser (sr/translate-browser :chrome) :params {}}) (catch :default cause - (throw (ex-info "graphics init failed" - {:phase "graphics-init"} - cause))))] + (throw (phase-error "graphics-init" "graphics init failed" cause))))] (when (nil? ctx) - (throw (ex-info "WebGL2 context unavailable" - {:phase "graphics-init"}))) + (throw (phase-error "graphics-init" "WebGL2 context unavailable" nil))) (set! wasm/gl-context-handle (:handle ctx)) (set! wasm/gl-context (:context ctx)) (set! wasm/canvas canvas) @@ -666,9 +667,7 @@ (try (h/call wasm/internal-module "_resize_viewbox" width height) (catch :default cause - (throw (ex-info "resize viewbox failed" - {:phase "graphics-init"} - cause)))) + (throw (phase-error "graphics-init" "resize viewbox failed" cause)))) (install-listeners! canvas epoch) {:module-ms factory-ms :graphics-ms (- (now) g0) @@ -706,9 +705,7 @@ (catch :default cause (if (errors/stale? cause) (throw cause) - (throw (ex-info "scene build failed" - {:phase "scene-build"} - cause)))))) + (throw (phase-error "scene-build" "scene build failed" cause)))))) (defn- upload-scene! "Sets the initial view and uploads prepared shapes inside the upload timer. diff --git a/frontend/performance/benches/render_wasm/node/cli/execution.cljs b/frontend/performance/benches/render_wasm/node/cli/execution.cljs index 80cd213271..db3d45aa4b 100644 --- a/frontend/performance/benches/render_wasm/node/cli/execution.cljs +++ b/frontend/performance/benches/render_wasm/node/cli/execution.cljs @@ -24,6 +24,7 @@ [benches.render-wasm.node.cli.request :as request] [benches.render-wasm.node.log :as log] [benches.render-wasm.node.outcome :as outcome] + [benches.render-wasm.node.settings :as settings] [benches.render-wasm.report.format :as format])) (defn on-signals @@ -96,7 +97,7 @@ (or (= command "run") (and (= command "ab") (not (:dry-run options)))) (not= "1" (.-PENPOT_GPU (.-env js/process)))) - (throw (ex-info "--require-gpu needs PENPOT_GPU=1. Start the container with ./manage.sh run-devenv --gpu and use pnpm run render-bench." + (throw (ex-info (str "--require-gpu needs PENPOT_GPU=1. " settings/gpu-guidance) {:type ::gpu-required})))) (defn- log-failures diff --git a/frontend/performance/benches/render_wasm/node/outcome.cljs b/frontend/performance/benches/render_wasm/node/outcome.cljs index c0af9d1341..0f630f8668 100644 --- a/frontend/performance/benches/render_wasm/node/outcome.cljs +++ b/frontend/performance/benches/render_wasm/node/outcome.cljs @@ -25,8 +25,15 @@ (merge {:exit-code 0 :errors [] :log-path nil} data)) (defn failed - "Returns an outcome with exit code 1 for `cause`. The log path comes from - the ex-data of `cause`. `data` adds more keys." + "Returns an outcome for `cause` with defaults for errors, exit code and log. + + Args: + cause: Failure supplying the default error and log path. + data: Outcome fields that override defaults, including :errors, + :exit-code and :log-path. + + Returns: + An outcome with exit code 1 and the failure's log path as defaults." [cause data] (merge {:errors [cause] :exit-code 1 diff --git a/frontend/performance/benches/render_wasm/node/runner/feature_comparison.cljs b/frontend/performance/benches/render_wasm/node/runner/feature_comparison.cljs index 21120ca473..4e04f071b4 100644 --- a/frontend/performance/benches/render_wasm/node/runner/feature_comparison.cljs +++ b/frontend/performance/benches/render_wasm/node/runner/feature_comparison.cljs @@ -207,12 +207,25 @@ (mark-edge state edge :unattempted {:reason reason})) (mark-edges-unattempted state pending reason)))) +(defn- storage-failure + "Combines earlier failures with a failed comparison-storage operation. + + Args: + operation: Operation that failed while saving comparison evidence. + causes: Earlier failures in occurrence order. + cause: Failure of the storage operation. + + Returns: + An Error retaining earlier failures followed by the storage failure." + [operation causes cause] + (errors/combine (conj (mapv #(hash-map :error %) causes) + {:phase "comparison-storage" :operation operation :error cause}))) + (defn- finish [state status exit-code causes] (let [saved (attempt :catch-fatal (persist state #(assoc % :status status :ended-at (time/now)))) failure (when (failure? saved) - (errors/combine (conj (mapv #(hash-map :error %) causes) - {:phase "comparison-storage" :operation :finish-comparison :error saved})))] + (storage-failure :finish-comparison causes saved))] {:comparison (if failure @(:saved-ref state) saved) :home (:home state) :log-path (get-in state [:home :log-path]) @@ -244,8 +257,7 @@ nil)] (if (failure? recorded) (failure-outcome state signal - (errors/combine [{:error error} - {:phase "comparison-storage" :operation :record-interruption :error recorded}])) + (storage-failure :record-interruption [error] recorded)) (finish state :interrupted (outcome/interruption-code signal) [error])))) (defn- record-created-build @@ -282,8 +294,7 @@ (interrupt-configuration state slug signal phase cause) (fail-configuration state slug phase (str (name phase) " failure") cause)) (catch :default recorded - (throw (errors/combine [{:error cause} - {:phase "comparison-storage" :operation :record-configuration-failure :error recorded}]))))) + (throw (storage-failure :record-configuration-failure [cause] recorded))))) (defn- begin-configuration [state configuration] @@ -468,8 +479,7 @@ (try (record-run-result state slug evidence) (catch :default cause - (throw (errors/combine [{:error (:error evidence)} - {:phase "comparison-storage" :operation :record-run-result :error cause}])))) + (throw (storage-failure :record-run-result [(:error evidence)] cause)))) (config-run-outcome slug evidence))) (defn- get-missing-run-cause @@ -609,8 +619,7 @@ nil)] (cond (failure? recorded) - (throw (errors/combine [{:error analyzed} - {:phase "comparison-storage" :operation :record-edge :error recorded}])) + (throw (storage-failure :record-edge [analyzed] recorded)) fatal? (throw analyzed) :else analyzed))) @@ -623,8 +632,7 @@ (try (mark-edges-unattempted state (str "interrupted by " signal)) (catch :default cause - (throw (errors/combine [{:error error} - {:phase "comparison-storage" :operation :record-interruption :error cause}])))) + (throw (storage-failure :record-interruption [error] cause)))) {:interrupted signal :error error}) (if-let [[edge & pending] (seq edges)] (analyze-edges state pending (record-edge-outcome state edge (analyze-edge state edge) error)) @@ -644,8 +652,7 @@ nil)] (if (failure? recorded) (failure-outcome state (process/signal-name (:signal state)) - (errors/combine [{:error error} - {:phase "comparison-storage" :operation :skip-comparisons :error recorded}])) + (storage-failure :skip-comparisons [error] recorded)) (finish state :failed 1 [error])))) (defn- ^:async run-edges @@ -659,8 +666,7 @@ (try (create-comparison-directory state) (catch :default cause - (throw (errors/combine [{:error error} - {:phase "comparison-storage" :operation :create-comparison-directory :error cause}])))) + (throw (storage-failure :create-comparison-directory [error] cause)))) (let [analyzed (attempt :catch-fatal (await (analyze-edges state (:edges @(:record-ref state)) error)))] (cond @@ -686,8 +692,7 @@ (try (mark-configs-unattempted state pending (:reason step)) (catch :default cause - (throw (errors/combine [{:error (:error step)} - {:phase "comparison-storage" :operation :stop-configurations :error cause}])))) + (throw (storage-failure :stop-configurations [(:error step)] cause)))) (run-edges state (:error step))) :else (run-comparisons state pending))) diff --git a/frontend/performance/benches/render_wasm/node/runner/run.cljs b/frontend/performance/benches/render_wasm/node/runner/run.cljs index 9848c1afaf..47bcc0fc0b 100644 --- a/frontend/performance/benches/render_wasm/node/runner/run.cljs +++ b/frontend/performance/benches/render_wasm/node/runner/run.cljs @@ -34,6 +34,7 @@ [benches.render-wasm.node.runner.browser :as browser] [benches.render-wasm.node.runner.build :as build] [benches.render-wasm.node.runner.server :as server] + [benches.render-wasm.node.settings :as settings] [benches.render-wasm.node.storage.artifacts :as artifacts] [benches.render-wasm.node.storage.runs :as runs] [benches.render-wasm.node.time :as time] @@ -324,7 +325,7 @@ {:status "failed" :phase "gpu" :message (str "GPU check failed; renderer: " (pr-str (:renderer graphics)) ". Hardware WebGL2 with a usable vendor and renderer is required." - " Start the container with ./manage.sh run-devenv --gpu and use pnpm run render-bench.") + " " settings/gpu-guidance) :partial {:graphics graphics}}) (reset! (:abort-run? state) true) :abort) diff --git a/frontend/performance/benches/render_wasm/node/settings.cljs b/frontend/performance/benches/render_wasm/node/settings.cljs index b669cecb25..100d8ac791 100644 --- a/frontend/performance/benches/render_wasm/node/settings.cljs +++ b/frontend/performance/benches/render_wasm/node/settings.cljs @@ -5,7 +5,10 @@ ;; Copyright (c) KALEIDOS SUBSIDIARY SL (ns benches.render-wasm.node.settings - "Shared operational defaults.") + "Shared operational settings and guidance.") (def default-build-timeout-ms 300000) (def default-startup-timeout-ms 30000) + +(def gpu-guidance + "Start the container with ./manage.sh run-devenv --gpu and use pnpm run render-bench.")