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.")