mirror of
https://github.com/penpot/penpot.git
synced 2026-11-02 16:10:42 +00:00
♻️ Syntactic sugar for the benchmarks
AI-assisted-by: deepseek-flash
This commit is contained in:
parent
c6c4b78bb1
commit
a50e234b10
@ -28,7 +28,9 @@
|
||||
clojure.core/let hooks.core/check-let
|
||||
cljs.core/let hooks.core/check-let
|
||||
benches.render-wasm.declarations/defscene hooks.benches/defscene
|
||||
benches.render-wasm.declarations/defcase hooks.benches/defcase}}
|
||||
benches.render-wasm.declarations/defcase hooks.benches/defcase
|
||||
benches.render-wasm.runtime.protocol/resolve-or-reject hooks.benches/resolve-or-reject
|
||||
benches.render-wasm.runtime.protocol/resolve-or-reject-with hooks.benches/resolve-or-reject-with}}
|
||||
|
||||
:output
|
||||
{:exclude-files
|
||||
|
||||
@ -24,3 +24,21 @@
|
||||
{:node (api/list-node [(api/token-node (quote do)) opts
|
||||
(api/list-node (into [(api/token-node (quote fn)) argv] body))])}
|
||||
{:node node})))
|
||||
|
||||
(defn resolve-or-reject
|
||||
"Analyzes the body of a Promise-returning form."
|
||||
[{:keys [node]}]
|
||||
(let [[_ & body] (:children node)]
|
||||
{:node (api/list-node (into [(api/token-node (quote do))] body))}))
|
||||
|
||||
(defn resolve-or-reject-with
|
||||
"Analyzes the cause handler and body. Binds `cause` in the handler only."
|
||||
[{:keys [node]}]
|
||||
(let [[_ cause on-error & body] (:children node)]
|
||||
{:node (api/list-node
|
||||
(into [(api/token-node (quote do))
|
||||
(api/list-node
|
||||
[(api/token-node (quote let))
|
||||
(api/vector-node [cause (api/token-node nil)])
|
||||
on-error])]
|
||||
body))}))
|
||||
|
||||
@ -10,5 +10,6 @@
|
||||
:extra-indents {rumext.v2/fnc [[:inner 0]]
|
||||
cljs.test/async [[:inner 0]]
|
||||
promesa.exec/thread [[:inner 0]]
|
||||
specify! [[:inner 0] [:inner 1]]}
|
||||
specify! [[:inner 0] [:inner 1]]
|
||||
benches.render-wasm.runtime.protocol/resolve-or-reject-with [[:inner 0]]}
|
||||
}
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
;; 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.runtime.protocol)
|
||||
|
||||
(defmacro resolve-or-reject
|
||||
"Evaluates `body` and returns a Promise. A synchronous throw rejects the
|
||||
returned promise."
|
||||
[& body]
|
||||
`(try
|
||||
(js/Promise.resolve (do ~@body))
|
||||
(catch :default cause#
|
||||
(js/Promise.reject cause#))))
|
||||
|
||||
(defmacro resolve-or-reject-with
|
||||
"Evaluates `body` and returns a Promise. A synchronous throw rejects with the
|
||||
result of `on-error`, evaluated with `cause` bound to the thrown value."
|
||||
[cause on-error & body]
|
||||
`(try
|
||||
(js/Promise.resolve (do ~@body))
|
||||
(catch :default cause#
|
||||
(let [~cause cause#]
|
||||
(js/Promise.reject ~on-error)))))
|
||||
@ -80,6 +80,8 @@
|
||||
boundaries, renamed at the interaction level.
|
||||
- `:last-input-to-full-ms` from the clock read before the last view update
|
||||
to the clock read after the final drain promise resolves."
|
||||
(:require-macros
|
||||
[benches.render-wasm.runtime.protocol :refer [resolve-or-reject resolve-or-reject-with]])
|
||||
(:require
|
||||
[app.common.render-wasm.wasm :as wasm]
|
||||
[benches.render-wasm.errors :as errors]))
|
||||
@ -200,75 +202,66 @@
|
||||
retrying."
|
||||
[{:keys [check] :as hooks}
|
||||
{:keys [flags origin immediate]}]
|
||||
(try
|
||||
(check)
|
||||
(letfn [(step [state immediate?]
|
||||
(-> (next-render-timestamp hooks immediate?)
|
||||
(.then ;; recurse or drain
|
||||
(fn [timestamp]
|
||||
(let [{:keys [frame-type ended-ms] :as rendered}
|
||||
(render-slice hooks state timestamp)
|
||||
next-state
|
||||
(advance-drain-state (:state rendered)
|
||||
frame-type
|
||||
ended-ms
|
||||
origin)]
|
||||
(resolve-or-reject
|
||||
(check)
|
||||
(letfn [(step [state immediate?]
|
||||
(-> (next-render-timestamp hooks immediate?)
|
||||
(.then ;; recurse or drain
|
||||
(fn [timestamp]
|
||||
(let [{:keys [frame-type ended-ms] :as rendered}
|
||||
(render-slice hooks state timestamp)
|
||||
next-state
|
||||
(advance-drain-state (:state rendered)
|
||||
frame-type
|
||||
ended-ms
|
||||
origin)]
|
||||
|
||||
(if (drain-complete? frame-type)
|
||||
(drain-result next-state ended-ms origin)
|
||||
(step next-state false)))))
|
||||
(.catch (fn [cause]
|
||||
(throw (partial-error cause (select-keys state [:slices :viewport-ready-ms])))))))]
|
||||
|
||||
(step {:flags flags
|
||||
:slices []
|
||||
:viewport-ready-ms nil}
|
||||
immediate))
|
||||
|
||||
(catch :default cause
|
||||
(js/Promise.reject cause))))
|
||||
(if (drain-complete? frame-type)
|
||||
(drain-result next-state ended-ms origin)
|
||||
(step next-state false)))))
|
||||
(.catch (fn [cause]
|
||||
(throw (partial-error cause (select-keys state [:slices :viewport-ready-ms])))))))]
|
||||
(step {:flags flags
|
||||
:slices []
|
||||
:viewport-ready-ms nil}
|
||||
immediate))))
|
||||
|
||||
(defn restore
|
||||
"Puts the camera back to `view` (`{:scale :x :y}`) and drains with the
|
||||
SyncTiles flag immediately. Resolves what `drain` resolves. Callers run
|
||||
this outside timing: the reset itself is never scored."
|
||||
[{:keys [now check set-view set-view-start set-view-end] :as hooks} view]
|
||||
(try
|
||||
(check)
|
||||
(set-view-start)
|
||||
(set-view view)
|
||||
(set-view-end)
|
||||
(drain hooks {:flags wasm/RENDER_FLAG_SYNC_TILES
|
||||
:origin (now)
|
||||
:immediate true})
|
||||
(catch :default cause
|
||||
(js/Promise.reject cause))))
|
||||
(resolve-or-reject
|
||||
(check)
|
||||
(set-view-start)
|
||||
(set-view view)
|
||||
(set-view-end)
|
||||
(drain hooks {:flags wasm/RENDER_FLAG_SYNC_TILES
|
||||
:origin (now)
|
||||
:immediate true})))
|
||||
|
||||
(defn start-camera!
|
||||
"Starts a measured camera session after the caller's untimed preparation.
|
||||
`rtx` supplies `:hooks` and the current full `:view`."
|
||||
[{:keys [hooks view]} {:keys [settle-ms]}]
|
||||
(try
|
||||
(when-not (and (number? settle-ms)
|
||||
(js/Number.isFinite settle-ms)
|
||||
(<= 0 settle-ms))
|
||||
(throw (ex-info "settle-ms must be a nonnegative finite number"
|
||||
{:type ::invalid-settle-ms :settle-ms settle-ms})))
|
||||
(let [{:keys [now check set-view-start]} hooks]
|
||||
(check)
|
||||
(let [started-ms (now)]
|
||||
(set-view-start)
|
||||
(js/Promise.resolve
|
||||
{:hooks hooks
|
||||
:view view
|
||||
:settle-ms settle-ms
|
||||
:started-ms started-ms
|
||||
:last-input-ms started-ms
|
||||
:active-end-ms (now)
|
||||
:cached-slices []
|
||||
:authored-sleeps []})))
|
||||
(catch :default cause
|
||||
(js/Promise.reject cause))))
|
||||
(resolve-or-reject
|
||||
(when-not (and (number? settle-ms)
|
||||
(js/Number.isFinite settle-ms)
|
||||
(<= 0 settle-ms))
|
||||
(throw (ex-info "settle-ms must be a nonnegative finite number"
|
||||
{:type ::invalid-settle-ms :settle-ms settle-ms})))
|
||||
(let [{:keys [now check set-view-start]} hooks]
|
||||
(check)
|
||||
(let [started-ms (now)]
|
||||
(set-view-start)
|
||||
{:hooks hooks
|
||||
:view view
|
||||
:settle-ms settle-ms
|
||||
:started-ms started-ms
|
||||
:last-input-ms started-ms
|
||||
:active-end-ms (now)
|
||||
:cached-slices []
|
||||
:authored-sleeps []}))))
|
||||
|
||||
(defn preview-view!
|
||||
"Awaits a session and submits one cached preview after exactly one rAF.
|
||||
@ -279,7 +272,8 @@
|
||||
(.then (fn [{:keys [hooks] :as session}]
|
||||
(let [{:keys [now frame check render-from-cache set-view]} hooks
|
||||
evidence (select-keys session [:cached-slices :authored-sleeps])]
|
||||
(try
|
||||
(resolve-or-reject-with cause
|
||||
(partial-error cause evidence)
|
||||
(check)
|
||||
(-> (frame)
|
||||
(.then (fn [timestamp]
|
||||
@ -300,9 +294,7 @@
|
||||
(throw (partial-error cause (assoc evidence :cached-slices slices)))))
|
||||
(assoc session :view view :last-input-ms input-ms
|
||||
:active-end-ms (now) :cached-slices slices))))))
|
||||
(.catch (fn [cause] (throw (partial-error cause evidence)))))
|
||||
(catch :default cause
|
||||
(js/Promise.reject (partial-error cause evidence)))))))))
|
||||
(.catch (fn [cause] (throw (partial-error cause evidence)))))))))))
|
||||
|
||||
(defn animate-view!
|
||||
"Submits exactly `steps` serial, linearly interpolated full views.
|
||||
@ -331,7 +323,8 @@
|
||||
(.then (fn [{:keys [hooks] :as session}]
|
||||
(let [{:keys [now sleep check]} hooks
|
||||
evidence (select-keys session [:cached-slices :authored-sleeps])]
|
||||
(try
|
||||
(resolve-or-reject-with cause
|
||||
(partial-error cause evidence)
|
||||
(when-not (and (number? requested-ms)
|
||||
(js/Number.isFinite requested-ms)
|
||||
(<= 0 requested-ms))
|
||||
@ -348,9 +341,7 @@
|
||||
(update :authored-sleeps conj
|
||||
{:requested-ms requested-ms
|
||||
:actual-ms (- ended-ms started-ms)})))))
|
||||
(.catch (fn [cause] (throw (partial-error cause evidence))))))
|
||||
(catch :default cause
|
||||
(js/Promise.reject (partial-error cause evidence)))))))))
|
||||
(.catch (fn [cause] (throw (partial-error cause evidence))))))))))))
|
||||
|
||||
(defn- finish-interaction
|
||||
"Ends the camera and returns final metrics, retaining trace evidence on failure."
|
||||
@ -392,10 +383,9 @@
|
||||
(-> (js/Promise.resolve session-p)
|
||||
(.then (fn [{:keys [hooks settle-ms] :as session}]
|
||||
(let [evidence (select-keys session [:cached-slices :authored-sleeps])]
|
||||
(try
|
||||
(resolve-or-reject-with cause
|
||||
(partial-error cause evidence)
|
||||
((:check hooks))
|
||||
(-> ((:sleep hooks) settle-ms)
|
||||
(.then (fn [_] (finish-interaction hooks session)))
|
||||
(.catch (fn [cause] (throw (partial-error cause evidence)))))
|
||||
(catch :default cause
|
||||
(js/Promise.reject (partial-error cause evidence)))))))))
|
||||
(.catch (fn [cause] (throw (partial-error cause evidence)))))))))))
|
||||
|
||||
@ -361,3 +361,30 @@
|
||||
(.catch (fn [cause]
|
||||
(t/is (= "cache failed" (ex-message cause)))
|
||||
(done)))))))
|
||||
|
||||
(t/deftest invalid-settle-ms-rejects
|
||||
(t/async done
|
||||
(let [hooks (drain-hooks {:clock (fake-clock 0) :script [2] :calls (atom [])})]
|
||||
(-> (protocol/start-camera! {:hooks hooks :view {:scale 1 :x 0 :y 0}}
|
||||
{:settle-ms -1})
|
||||
(.then (fn [_]
|
||||
(t/is false "invalid settle-ms must reject")
|
||||
(done)))
|
||||
(.catch (fn [cause]
|
||||
(t/is (= ::protocol/invalid-settle-ms (:type (ex-data cause))))
|
||||
(done)))))))
|
||||
|
||||
(t/deftest invalid-sleep-rejects-with-camera-evidence
|
||||
(t/async done
|
||||
(let [hooks (drain-hooks {:clock (fake-clock 0) :script [2] :calls (atom [])})]
|
||||
(-> (protocol/start-camera! {:hooks hooks :view {:scale 1 :x 0 :y 0}}
|
||||
{:settle-ms 0})
|
||||
(protocol/sleep! -1)
|
||||
(.then (fn [_]
|
||||
(t/is false "invalid sleep must reject")
|
||||
(done)))
|
||||
(.catch (fn [cause]
|
||||
(t/is (= ::protocol/invalid-sleep (:type (ex-data cause))))
|
||||
(t/is (= {:cached-slices [] :authored-sleeps []}
|
||||
(:partial (ex-data cause))))
|
||||
(done)))))))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user