mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 06:20:32 +00:00
🔧 Add the engine bench probe and the :advanced corruption reproducer
frontend/src/bench carries the datascript half of the same-session V8 A/B (core.cljs body shared verbatim with the datahike worktree) and debug.cljs, the minimal reproducer for the :advanced query-layer corruption: storage reads correct, full-scan values replaced by hash-like integers, bound-value queries empty. The ab-bench shadow build pins :optimizations :simple because of exactly that corruption. Owned by mirror:ds-advanced-corruption. AI-assisted-by: claude-fable-5
This commit is contained in:
parent
0d11aa3f01
commit
6f537eb82e
@ -160,6 +160,17 @@
|
||||
{:test {:init-fn frontend-tests.runner/init
|
||||
:prepend-js ";if (typeof globalThis.navigator?.userAgent === 'undefined') { globalThis.navigator = {userAgent: ''}; };"}}}
|
||||
|
||||
:ab-bench
|
||||
{:target :node-script
|
||||
:output-to "target/ab-bench.js"
|
||||
:output-dir "target/ab-bench/"
|
||||
:main bench.core/-main
|
||||
|
||||
:compiler-options
|
||||
{:optimizations :simple
|
||||
:output-wrapper false
|
||||
:warnings {:fn-deprecated false}}}
|
||||
|
||||
:bench
|
||||
{:target :node-script
|
||||
:output-to "target/bench.js"
|
||||
|
||||
80
frontend/src/bench/core.cljs
Normal file
80
frontend/src/bench/core.cljs
Normal file
@ -0,0 +1,80 @@
|
||||
(ns bench.core
|
||||
"Engine-parameterized V8 bench: same body as the browser probes, node runtime.
|
||||
The engine ns is aliased at compile time via a reader switch on the classpath:
|
||||
exactly one of datascript/datahike is present per compilation."
|
||||
(:require [bench.engine :as e]))
|
||||
|
||||
(def n-shapes 20000)
|
||||
|
||||
(def rules
|
||||
'[[(child-of ?c ?p) [?c :shape/parent ?p]]
|
||||
[(descendant-of-walk ?d ?a) (child-of ?d ?a)]
|
||||
[(descendant-of-walk ?d ?a) (child-of ?d ?x) (descendant-of-walk ?x ?a)]])
|
||||
|
||||
(defn- median [xs] (nth (vec (sort xs)) (quot (count xs) 2)))
|
||||
(defn- timed [f] (let [t0 (js/performance.now) r (f)] [(- (js/performance.now) t0) r]))
|
||||
(defn- medians [n f] (median (mapv (fn [_] (first (timed f))) (range n))))
|
||||
|
||||
(defn run []
|
||||
(let [component-id (random-uuid)
|
||||
file-id (random-uuid)
|
||||
shape-ids (into [] (map (fn [_] (random-uuid))) (range n-shapes))
|
||||
tx (into [{:db/id -1 :shape/id (random-uuid) :shape/type :frame
|
||||
:shape/name "root"}]
|
||||
(map-indexed
|
||||
(fn [i sid]
|
||||
(cond-> {:db/id (- -2 i)
|
||||
:shape/id sid
|
||||
:shape/type :rect
|
||||
:shape/name (str "rect-" i)
|
||||
:shape/parent -1}
|
||||
(zero? (mod i 25))
|
||||
(assoc :shape/component-id component-id
|
||||
:shape/component-file file-id))))
|
||||
shape-ids)
|
||||
schema {:shape/id {:db/index true}
|
||||
:shape/name {:db/index true}
|
||||
:shape/component-id {:db/index true}
|
||||
:shape/parent {:db/valueType :db.type/ref}}
|
||||
_ (e/build schema tx) ;; warm-up build
|
||||
build-ms (medians 3 #(do (e/build schema tx) nil))
|
||||
db (e/build schema tx)
|
||||
reverse-ms (medians 40 #(e/q '[:find [?id ...]
|
||||
:in $ ?cid ?fid
|
||||
:where
|
||||
[?e :shape/component-id ?cid]
|
||||
[?e :shape/component-file ?fid]
|
||||
[?e :shape/id ?id]]
|
||||
db component-id file-id))
|
||||
name-ms (medians 40 #(e/q '[:find ?id .
|
||||
:in $ ?n
|
||||
:where [?e :shape/name ?n] [?e :shape/id ?id]]
|
||||
db "rect-19999"))
|
||||
desc-ms (medians 5 (fn []
|
||||
(e/q '[:find [?id ...]
|
||||
:in $ % ?rn
|
||||
:where
|
||||
[?root :shape/name ?rn]
|
||||
(descendant-of-walk ?d ?root)
|
||||
[?d :shape/id ?id]]
|
||||
db rules "root")))
|
||||
rev-rows (count (e/q '[:find [?id ...] :in $ ?cid ?fid
|
||||
:where [?e :shape/component-id ?cid]
|
||||
[?e :shape/component-file ?fid]
|
||||
[?e :shape/id ?id]]
|
||||
db component-id file-id))
|
||||
desc-rows (count (e/q '[:find [?id ...] :in $ % ?rn
|
||||
:where [?root :shape/name ?rn]
|
||||
(descendant-of-walk ?d ?root)
|
||||
[?d :shape/id ?id]]
|
||||
db rules "root"))
|
||||
fmt #(.toFixed % 2)]
|
||||
(println (pr-str {:engine e/engine
|
||||
:build-ms (fmt build-ms)
|
||||
:reverse-ms (fmt reverse-ms)
|
||||
:name-ms (fmt name-ms)
|
||||
:desc-ms (fmt desc-ms)
|
||||
:rev-rows rev-rows :desc-rows desc-rows
|
||||
:heap-mb (fmt (/ (.-heapUsed (js/process.memoryUsage)) 1e6))}))))
|
||||
|
||||
(defn -main [& _] (run))
|
||||
10
frontend/src/bench/debug.cljs
Normal file
10
frontend/src/bench/debug.cljs
Normal file
@ -0,0 +1,10 @@
|
||||
(ns bench.debug
|
||||
(:require [datascript.core :as d]))
|
||||
(defn -main [& _]
|
||||
(let [db (d/db-with (d/empty-db {:x/id {:db/index true}})
|
||||
[{:db/id -1 :x/id 7 :x/name "a"}])]
|
||||
(println :scan-q (pr-str (d/q '[:find ?e ?v :where [?e :x/name ?v]] db)))
|
||||
(println :bound-q (pr-str (d/q '[:find ?e :in $ ?n :where [?e :x/name ?n]] db "a")))
|
||||
(println :avet-part (pr-str (vec (d/datoms db :avet :x/name "a"))))
|
||||
(println :eavt-part (pr-str (vec (d/datoms db :eavt 1 :x/name))))
|
||||
(println :seek (pr-str (first (d/seek-datoms db :avet :x/name))))))
|
||||
4
frontend/src/bench/engine.cljs
Normal file
4
frontend/src/bench/engine.cljs
Normal file
@ -0,0 +1,4 @@
|
||||
(ns bench.engine (:require [datascript.core :as d]))
|
||||
(def engine :datascript)
|
||||
(defn build [schema tx] (d/db-with (d/empty-db schema) tx))
|
||||
(def q d/q)
|
||||
Loading…
x
Reference in New Issue
Block a user