Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5f442ba
CLJD and Dart compilation of the whole codebase pass (no guarantee on…
cgrand Oct 4, 2023
d237e38
first test namespace passing!
cgrand Oct 5, 2023
e54a9fb
disable transit
cgrand Oct 5, 2023
08dacf2
test.conn passes
cgrand Oct 9, 2023
ac5f9d2
index, query and transact do pass
cgrand Oct 10, 2023
a796d75
pull tests pss except one
cgrand Oct 13, 2023
3f55eda
almost all test passing but serialize, quert_v3 and datafy
cgrand Oct 17, 2023
c40dbcc
add dummy storage.cljd
cgrand Nov 3, 2023
e9b49a0
Making transit tests pass
dupuchba Nov 6, 2023
a4237ec
transit tests
dupuchba Nov 6, 2023
7c6164a
fix lots of clj errors
panterarocks49 Dec 20, 2024
ad24e2d
entity fixes
panterarocks49 Dec 20, 2024
5d59df0
clj tests almost compile
panterarocks49 Dec 20, 2024
a42b5cd
cljd tests pass
panterarocks49 Dec 20, 2024
6516099
clj tests pass other than entity file
panterarocks49 Dec 20, 2024
96dd6b6
cljs tests pass other than entity file
panterarocks49 Dec 20, 2024
c684f1b
all tests pass!
panterarocks49 Dec 23, 2024
db5eafe
cljd pss
panterarocks49 Jan 6, 2025
4cfdf84
reduce cljd memory
panterarocks49 Jan 6, 2025
923536d
Add CLJD support for datascript
ianffcs Feb 24, 2026
a58c401
Fix CLJ storage regression and update storage tests for new conn stru…
ianffcs Mar 23, 2026
6c4a533
Bump PSS to 0688b58 with CLJD static dispatch optimizations
ianffcs Mar 23, 2026
499be64
Fix CLJS regression: add raise to :require-macros :refer list
ianffcs Mar 23, 2026
0f5acb6
Switch CLJD storage to me.tonsky.persistent-sorted-set.async
ianffcs Mar 29, 2026
f69ea35
Apply CLJD static dispatch optimizations and add libdbm storage
ianffcs Apr 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions bench/datascript/bench/bench.cljc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns datascript.bench.bench
(:require
#?(:clj [clj-async-profiler.core :as clj-async-profiler]))
#?(:cljd nil :clj [clj-async-profiler.core :as clj-async-profiler]))
#?(:cljs (:require-macros datascript.bench.bench)))

; Measure time
Expand All @@ -12,7 +12,8 @@
(def ^:dynamic *profile* false)

#?(:cljs (defn ^number now [] (js/performance.now))
:clj (defn now ^double [] (/ (System/nanoTime) 1000000.0)))
:cljd (defn now [] (/ (.-microsecondsSinceEpoch (DateTime/now)) 1000.0))
:clj (defn now ^double [] (/ (System/nanoTime) 1000000.0)))

#?(:clj
(defmacro dotime
Expand All @@ -27,15 +28,13 @@
(recur (+ *batch* iterations#))
(double (/ (- now# start-t#) iterations#))))))))

(defn- if-cljs [env then else]
(if (:ns env) then else))

(defn median [xs]
(nth (sort xs) (quot (count xs) 2)))

(defn to-fixed [n places]
#?(:cljs (.toFixed n places)
:clj (String/format java.util.Locale/ROOT (str "%." places "f") (to-array [(double n)]))))
:cljd (.toStringAsFixed (double n) places)
:clj (String/format java.util.Locale/ROOT (str "%." places "f") (to-array [(double n)]))))

(defn round [n]
(cond
Expand All @@ -60,13 +59,22 @@
(let [[title body] (if (string? title)
[title body]
["unknown-bench" (cons title body)])]
(if-cljs &env
(cond
#?(:cljd/clj-host true :default false)
`(let [_# (dart/await (dotime *warmup-ms* ~@body))
times# (loop [i# (int 0) acc# []]
(if (< i# *samples*)
(recur (inc i#) (conj acc# (dart/await (dotime *bench-ms* ~@body))))
acc#))]
{:mean-ms (median times#)})
(:ns &env)
`(let [_# (dotime *warmup-ms* ~@body)
times# (mapv
(fn [_#]
(dotime *bench-ms* ~@body))
(range *samples*))]
{:mean-ms (median times#)})
:else
`(let [_# (dotime *warmup-ms* ~@body)
_# (when *profile* (clj-async-profiler/start {}))
times# (mapv
Expand Down Expand Up @@ -115,7 +123,7 @@
└ 15"
[id depth width]
(if (pos? depth)
(let [children (map #(+ (* id width) %) (range width))]
(let [children (mapv #(+ (* id width) %) (range width))]
(cons
(assoc (random-man)
:db/id (str id)
Expand Down
157 changes: 119 additions & 38 deletions bench/datascript/bench/datascript.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
(:require
[datascript.core :as d]
[datascript.bench.bench :as bench]
#?(:clj [jsonista.core :as jsonista])))
#?@(:cljd [["dart:convert" :as dart:convert]
[datascript.db :as ddb]
[me.tonsky.persistent-sorted-set.async :as async-set]]
:clj [[jsonista.core :as jsonista]])))

#?(:cljs (enable-console-print!))

Expand Down Expand Up @@ -54,7 +57,7 @@
(defn bench-init []
(let [datoms (into []
(for [p @bench/*people20k
:let [id (#?(:clj Integer/parseInt :cljs js/parseInt) (:db/id p))]
:let [id (#?(:clj Integer/parseInt :cljs js/parseInt :cljd int/parse) (:db/id p))]
[k v] p
:when (not= k :db/id)]
(d/datom id k v)))]
Expand Down Expand Up @@ -219,66 +222,144 @@
(com.fasterxml.jackson.databind.ObjectMapper.)))

(defn bench-freeze []
(bench/bench
(-> @*serialize-db (d/serializable) #?(:clj (jsonista/write-value-as-string mapper) :cljs js/JSON.stringify))))
#?(:cljd
(bench/bench
(-> @*serialize-db d/serializable dart:convert/json.encode))
:default
(bench/bench
(-> @*serialize-db (d/serializable) #?(:clj (jsonista/write-value-as-string mapper) :cljs js/JSON.stringify)))))

(defn bench-thaw []
(let [json (-> @*serialize-db (d/serializable) #?(:clj (jsonista/write-value-as-string mapper) :cljs js/JSON.stringify))]
(bench/bench
(-> json #?(:clj (jsonista/read-value mapper) :cljs js/JSON.parse) d/from-serializable))))
#?(:cljd
(let [json (-> @*serialize-db d/serializable dart:convert/json.encode)]
(bench/bench
(-> json dart:convert/json.decode d/from-serializable)))
:default
(let [json (-> @*serialize-db (d/serializable) #?(:clj (jsonista/write-value-as-string mapper) :cljs js/JSON.stringify))]
(bench/bench
(-> json #?(:clj (jsonista/read-value mapper) :cljs js/JSON.parse) d/from-serializable)))))

#?(:cljd
(do
(def *async-datoms
(delay
(into []
(for [p @bench/*people20k
:let [id (int/parse (:db/id p))]
[k v] p
:when (not= k :db/id)]
(d/datom id k v)))))

(defn bench-async-init []
(bench/bench
(dart/await (async-set/async-from-sequential ddb/cmp-datoms-eavt-cmp @*async-datoms))))

(defn bench-async-add-1 []
(bench/bench
(loop [s (async-set/async-sorted-set ddb/cmp-datoms-eavt-cmp)
ps (seq @bench/*people20k)]
(if ps
(let [p (first ps)
id (int/parse (:db/id p))
s1 (dart/await (async-set/async-conj s (d/datom id :name (:name p)) ddb/cmp-datoms-eavt-cmp))
s2 (dart/await (async-set/async-conj s1 (d/datom id :last-name (:last-name p)) ddb/cmp-datoms-eavt-cmp))
s3 (dart/await (async-set/async-conj s2 (d/datom id :sex (:sex p)) ddb/cmp-datoms-eavt-cmp))
s4 (dart/await (async-set/async-conj s3 (d/datom id :age (:age p)) ddb/cmp-datoms-eavt-cmp))
s5 (dart/await (async-set/async-conj s4 (d/datom id :salary (:salary p)) ddb/cmp-datoms-eavt-cmp))]
(recur s5 (next ps)))
s))))

(defn bench-async-add-all []
(bench/bench
(loop [s (async-set/async-sorted-set ddb/cmp-datoms-eavt-cmp)
ds (seq @*async-datoms)]
(if ds
(recur (dart/await (async-set/async-conj s (first ds) ddb/cmp-datoms-eavt-cmp)) (next ds))
s))))

(defn bench-async-retract []
(let [s (dart/await (async-set/async-from-sequential ddb/cmp-datoms-eavt-cmp @*async-datoms))]
(bench/bench
(loop [set s
ds (seq @*async-datoms)]
(if ds
(recur (dart/await (async-set/async-disj set (first ds) ddb/cmp-datoms-eavt-cmp)) (next ds))
set)))))

(defn bench-async-slice []
(let [s (dart/await (async-set/async-from-sequential ddb/cmp-datoms-eavt-cmp @*async-datoms))]
(bench/bench
(dart/await (async-set/async-slice s
(ddb/min-datom (d/datom 9000 nil nil ddb/tx0))
(ddb/max-datom (d/datom 11000 nil nil ddb/txmax))
ddb/cmp-datoms-eavt-cmp)))))

))

(def benches
{"add-1" bench-add-1
"add-5" bench-add-5
"add-all" bench-add-all
"init" bench-init
"find-datoms" bench-find-datoms
"find-datom" bench-find-datom
"retract-5" bench-retract-5
"q1" bench-q1
"q2" bench-q2
"q3" bench-q3
"q4" bench-q4
"q5-shortcircuit" bench-q5-shortcircuit
"qpred1" bench-qpred1
"qpred2" bench-qpred2
"pull-one-entities" bench-pull-one-entities
"pull-one" bench-pull-one
"pull-many-entities" bench-pull-many-entities
"pull-many" bench-pull-many
"pull-wildcard" bench-pull-wildcard
"rules-wide-3x3" bench-rules-wide-3x3
"rules-wide-5x3" bench-rules-wide-5x3
"rules-wide-7x3" bench-rules-wide-7x3
"rules-wide-4x6" bench-rules-wide-4x6
"rules-long-10x3" bench-rules-long-10x3
"rules-long-30x3" bench-rules-long-30x3
"rules-long-30x5" bench-rules-long-30x5
"freeze" bench-freeze
"thaw" bench-thaw})
(merge
{"add-1" bench-add-1
"add-5" bench-add-5
"add-all" bench-add-all
"init" bench-init
"find-datoms" bench-find-datoms
"find-datom" bench-find-datom
"retract-5" bench-retract-5
"q1" bench-q1
"q2" bench-q2
"q3" bench-q3
"q4" bench-q4
"q5-shortcircuit" bench-q5-shortcircuit
"qpred1" bench-qpred1
"qpred2" bench-qpred2
"pull-one-entities" bench-pull-one-entities
"pull-one" bench-pull-one
"pull-many-entities" bench-pull-many-entities
"pull-many" bench-pull-many
"pull-wildcard" bench-pull-wildcard
"rules-wide-3x3" bench-rules-wide-3x3
"rules-wide-5x3" bench-rules-wide-5x3
"rules-wide-7x3" bench-rules-wide-7x3
"rules-wide-4x6" bench-rules-wide-4x6
"rules-long-10x3" bench-rules-long-10x3
"rules-long-30x3" bench-rules-long-30x3
"rules-long-30x5" bench-rules-long-30x5
"freeze" bench-freeze
"thaw" bench-thaw}
#?(:cljd
{"async-init" bench-async-init
"async-add-1" bench-async-add-1
"async-add-all" bench-async-add-all
"async-retract" bench-async-retract
"async-slice" bench-async-slice}
:default {})))

(defn ^:export -main
"clj -A:bench -M -m datascript.bench.datascript [--profile] (add-1 | add-5 | ...)*"
[& args]
(let [args (or args ())
profile? (.contains ^java.util.List args "--profile")
profile? (boolean (some #{"--profile"} args))
args (remove #{"--profile"} args)
names (or (not-empty args) (sort (keys benches)))
_ (apply println #?(:clj "CLJ:" :cljs "CLJS:") names)
_ (apply println #?(:clj "CLJ:" :cljs "CLJS:" :cljd "CLJD:") names)
longest (last (sort-by count names))]
(binding [bench/*profile* profile?]
(doseq [name names
:let [fn (benches name)]]
(if (nil? fn)
(println "Unknown benchmark:" name)
(let [{:keys [mean-ms file]} (fn)]
(let [{:keys [mean-ms file]} #?(:cljd (dart/await (fn)) :default (fn))]
(println
(bench/right-pad name (count longest))
" "
(bench/left-pad (bench/round mean-ms) 6) "ms/op"
" " (or file ""))))))
#?(:clj (shutdown-agents))))

#?(:cljd
(defn ^:export main [args]
(apply -main args)))

(comment
(require 'datascript.bench.datascript :reload-all)

Expand Down
11 changes: 7 additions & 4 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
{:deps
{persistent-sorted-set/persistent-sorted-set {:mvn/version "0.3.0"}
{persistent-sorted-set/persistent-sorted-set
{:git/url "https://github.com/ianffcs/persistent-sorted-set.git"
:git/branch "cljd-support"
:git/sha "43e57ffac13851de46533957a4a96a234ff8a223"}
io.github.tonsky/extend-clj {:mvn/version "0.1.0"}}

:aliases
{:cljs
{:extra-paths ["test"]
:extra-deps
{org.clojure/clojurescript {:mvn/version "1.11.132"}}}

:1.9
{:override-deps
{org.clojure/clojure {:mvn/version "1.9.0"}}}

:1.10
{:override-deps
{org.clojure/clojure {:mvn/version "1.10.2"}}}
Expand Down
3 changes: 2 additions & 1 deletion script/bench_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ cd "`dirname $0`/.."

./script/bench_clj.sh $@
./script/bench_cljs.sh $@
./script/bench_datomic.sh $@
./script/bench_datomic.sh $@
./script/bench_cljd.sh $@
25 changes: 25 additions & 0 deletions script/bench_cljd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

#!/bin/bash
set -o errexit -o nounset -o pipefail
cd "`dirname $0`/.."
PATH="$PWD/.fvm/flutter_sdk/bin:$PATH"

rm -rf tmp/cljdbench
mkdir -p tmp/cljdbench/src/cljd
cat > tmp/cljdbench/deps.edn <<EOF
{:paths ["src" "../../bench"]
:deps {org.clojure/clojure {:mvn/version "1.11.1"}
tensegritics/clojuredart
{:git/url "https://github.com/tensegritics/ClojureDart.git"
:sha "1a8c70ab4e8901a4c68ed4507f43966e9337b5fb"}
io.github.wevre/transit-cljd {:git/url "https://github.com/Roam-Research/transit-cljd.git"
:sha "9d4511f0ef50705641b084f432bab726c64a8832"}
datascript/datascript {:local/root "../../"}}
:cljd/opts {:main datascript.bench.datascript
:kind :dart}}
EOF

cd tmp/cljdbench
clojure -M -m cljd.build init
clojure -M -m cljd.build compile datascript.bench.datascript
dart run bin/cljdbench.dart $@
Loading