From 9202a93cacb791716defaeb0bef2ad455cc9e54e Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 13 Mar 2023 14:27:25 +0200 Subject: [PATCH 1/3] re-run perf test --- perf/malli/perf/core.cljc | 6 ++--- perf/malli/perf/creation_perf_test.cljc | 32 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/perf/malli/perf/core.cljc b/perf/malli/perf/core.cljc index c23a00f20..b8bc3d55d 100644 --- a/perf/malli/perf/core.cljc +++ b/perf/malli/perf/core.cljc @@ -13,10 +13,10 @@ `(cc/quick-bench ~@body)) (defmacro profile [& body] - `(let [start# (System/currentTimeMillis)] + `(let [start# (System/nanoTime)] (dotimes [_# 10000] ~@body) - (let [ms# (- (System/currentTimeMillis) start#) - times# (int (/ 100000000 ms#))] + (let [ns# (- (System/nanoTime) start#) + times# (long (/ 100000000000000 ns#))] (println "invoking" times# "times") (time (prof/profile (dotimes [_# times#] ~@body)))))) diff --git a/perf/malli/perf/creation_perf_test.cljc b/perf/malli/perf/creation_perf_test.cljc index a98daf9a9..7025bef5a 100644 --- a/perf/malli/perf/creation_perf_test.cljc +++ b/perf/malli/perf/creation_perf_test.cljc @@ -17,13 +17,16 @@ ;; 2.5µs (...) ;; 2.3µs (-vmap, don't check children) ;; 1.1µs + ;; 270ns (M1-JDK17) (p/bench (m/validate [:or :int :string] 42)) ;; 2.6µs ;; 1.3µs + ;; 380ns (M1-JDK17) (p/bench (m/validate (m/from-ast {:type :or, :children [{:type :int} {:type :string}]}) 42)) ;; 15ns + ;; 7.2ns (M1-JDK17) (let [schema (m/schema [:or :int :string])] (p/bench (m/validate schema 42))) @@ -37,9 +40,11 @@ ;; 1.1µs (mapv childs) ;; 750ns (...) ;; 680ns (-vmap, don't check children) + ;; 180ns (M1-JDK17) (p/bench (m/schema [:or :int :string])) ;; 730ns + ;; 230ns (M1-JDK17) (p/bench (m/from-ast {:type :or, :children [{:type :int} {:type :string}]})) ;; 1.7µs @@ -50,23 +55,28 @@ ;; 1.1µs (mapv childs) ;; 750ns (...) ;; 680ns (-vmap, don't check children) + ;; 190ns (M1-JDK17) (p/bench (m/schema [:and :int :string])) ;; 730ns + ;; 240ns (M1-JDK17) (p/bench (m/from-ast {:type :and, :children [{:type :int} {:type :string}]})) ;; 1.7µs ;; 1.5µs (fast parse) ;; 540ns (non-distinct) ;; 13ns (-cache) + ;; 6.5ns (M1-JDK17) (let [schema (m/schema [:or :int :string])] (p/bench (m/validator schema))) ;; 16ns + ;; 7.0ns (M1-JDK17) (let [schema (m/schema [:or :int :string])] (p/bench (m/validate schema 42))) ;; 3ns + ;; 2.3ns (M1-JDK17) (let [validate (m/validator [:or :int :string])] (p/bench (validate 42)))) @@ -91,33 +101,42 @@ ;; ;; 480ns -> 400ns -> 340ns -> 280ns -> 240ns -> 170ns (registry) -> 160ns (recur) + ;; 55ns (M1-JDK17) (p/bench (m/schema :int)) ;; 180ns + ;; 78ns (M1-JDK17) (p/bench (m/from-ast {:type :int})) ;; 44µs -> 31µs -> 18µs -> 11µs -> 9.4µs -> 9.0µs -> 8.5µs -> 7.0µs -> 6.4µs (registry) -> 5.7µs ;; 3.4µs ;; 2.9µs (-entry-parser) ;; 2.5µs (no entries, object-arraus) + ;; 1.0µs (M1-JDK17) (p/bench (m/schema ?schema)) ;; 44µs -> 240ns + ;; 110ns (M1-JDK17) (p/bench (m/schema ?schema {::m/lazy-entries true})) ;; 147ns + ;; 84ns (M1-JDK17) (p/bench (m/from-ast ast)) ;; 3.7µs + ;; 1.4µs (M1-JDK17) (p/bench (m/validator (m/schema ?schema))) ;; 2.5µs + ;; 900ns (M1-JDK17) (p/bench (m/validator (m/from-ast ast))) ;; 1.6µs -> 64ns + ;; 40ns (M1-JDK17) (p/bench (m/validate schema {:x true, :z {:x true}})) ;; 1.6µs -> 450ns + ;; 120ns (M1-JDK17) (p/bench (m/explain schema {:x true, :z {:x true}})) ;; does not work with direct linking @@ -129,9 +148,11 @@ (comment ;; 14ns -> 5ns + ;; 3.3ns (M1-JDK17) (p/bench (m/deref ref-schema)) ;; 5µs -> 28ns + ;; 10ns (M1-JDK17) (p/bench (m/deref-all ref-schema))) (comment @@ -143,11 +164,13 @@ ;; 271ns ;; 14ns (-set-children, -set-properties) ;; 12ns (-entry-parser) + ;; 7.2ns (M1-JDK17) (p/bench (m/walk leaf-schema (m/schema-walker identity))) ;; 26µs ;; 1.3µs (-set-children, -set-properties) ;; 1.2µs (protocols, registry, recur) + ;; 700ns (M1-JDK17) (p/bench (m/walk schema (m/schema-walker identity))) ;; 51µs @@ -161,6 +184,7 @@ ;; 3.9µs (-parsed) ;; 3.6µs (-entry-parser) ;; 3.4µs (object-array) + ;; 1.4µs (M1-JDK17) (p/bench (mu/closed-schema schema)) ;; 3.8µs @@ -168,31 +192,37 @@ ;; 2.2µs (-set-entries) ;; 830ns (-update-parsed) ;; 560ns (-entry-parser) + ;; 190ns (M1-JDK17) (p/bench (mu/assoc schema :y :string)) ;; 4.2µs ;; 3.8µs (satisfies?) ;; 820ns (-update-parsed) ;; 540ns (-entry-parser) + ;; 180ns (M1-JDK17) (p/bench (mu/assoc schema :w :string)) ;; 205ns ;; 195ns + ;; 73ns (M1-JDK17) (p/bench (mu/get schema :y)) ;; 13µs ;; 2.4µs (satisfies?) ;; 1.8µs + ;; 690ns (M1-JDK17) (p/bench (mu/required-keys schema)) ;; 134µs ;; 15µs (satisfies?) ;; 9µs (fast merge) + ;; 2.7µs (M1-JDK17) (p/bench (mu/merge schema schema))) (comment ;; 119µs ;; 16µs (cache generator) + ;; 4.6µs (M1-JDK17) (p/bench (mg/generate schema))) (comment @@ -200,6 +230,7 @@ (let [t ::or, p {:a 1}, c (mapv m/schema [:int :int])] ;; 480ns ;; 221ns (faster impl) + ;; 120ns (M1-JDK17) (p/bench (m/-create-form t p c nil)))) (comment @@ -208,6 +239,7 @@ ;; 341ns (-create-form) ;; 150ns (delayed form) ;; 30ns (don't -check-children) + ;; 120ns (M1-JDK17) (p/bench (m/-val-schema s nil)))) (comment From 5df95f0230032fc15ad0f41568ac490ca5a40209 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Mon, 13 Mar 2023 14:49:16 +0200 Subject: [PATCH 2/3] m/-simple-schema caching --- perf/malli/perf/creation_perf_test.cljc | 6 ++++++ src/malli/core.cljc | 15 ++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/perf/malli/perf/creation_perf_test.cljc b/perf/malli/perf/creation_perf_test.cljc index 7025bef5a..71fc21366 100644 --- a/perf/malli/perf/creation_perf_test.cljc +++ b/perf/malli/perf/creation_perf_test.cljc @@ -41,6 +41,7 @@ ;; 750ns (...) ;; 680ns (-vmap, don't check children) ;; 180ns (M1-JDK17) + ;; 160ns (-type-cache) (p/bench (m/schema [:or :int :string])) ;; 730ns @@ -56,6 +57,7 @@ ;; 750ns (...) ;; 680ns (-vmap, don't check children) ;; 190ns (M1-JDK17) + ;; 160ns (-type-cache) (p/bench (m/schema [:and :int :string])) ;; 730ns @@ -102,6 +104,7 @@ ;; 480ns -> 400ns -> 340ns -> 280ns -> 240ns -> 170ns (registry) -> 160ns (recur) ;; 55ns (M1-JDK17) + ;; 34ns (-type-cache) (p/bench (m/schema :int)) ;; 180ns @@ -113,10 +116,12 @@ ;; 2.9µs (-entry-parser) ;; 2.5µs (no entries, object-arraus) ;; 1.0µs (M1-JDK17) + ;; 840ns (-type-cache) (p/bench (m/schema ?schema)) ;; 44µs -> 240ns ;; 110ns (M1-JDK17) + ;; 95ns (-type-cache) (p/bench (m/schema ?schema {::m/lazy-entries true})) ;; 147ns @@ -125,6 +130,7 @@ ;; 3.7µs ;; 1.4µs (M1-JDK17) + ;; 1.3ns (-type-cache) (p/bench (m/validator (m/schema ?schema))) ;; 2.5µs diff --git a/src/malli/core.cljc b/src/malli/core.cljc index d205539ac..9100b3c4b 100644 --- a/src/malli/core.cljc +++ b/src/malli/core.cljc @@ -619,8 +619,9 @@ ;; (defn -simple-schema [props] - (let [{:keys [type type-properties pred property-pred min max from-ast to-ast compile] - :or {min 0, max 0, from-ast -from-value-ast, to-ast -to-type-ast}} props] + (let [{:keys [type type-properties pred property-pred min max from-ast to-ast compile options] + :or {min 0, max 0, from-ast -from-value-ast, to-ast -to-type-ast}} props + type-cache (-create-cache options)] (if (fn? props) (do (-deprecated! "-simple-schema doesn't take fn-props, use :compiled property instead") @@ -629,6 +630,8 @@ (reify AST (-from-ast [parent ast options] (from-ast parent ast options)) + Cached + (-cache [_] type-cache) IntoSchema (-type [_] type) (-type-properties [_] type-properties) @@ -2003,9 +2006,9 @@ [x] (#?(:clj instance?, :cljs implements?) malli.core.Schema x)) (defn schema - "Creates a Schema object from any of the following: + "Creates a Schema instance from any of the following: - - Schema instance (just returns it) + - Schema instance - IntoSchema instance - Schema vector syntax, e.g. [:string {:min 1}] - Qualified Keyword or String, using a registry lookup" @@ -2014,7 +2017,9 @@ ([?schema options] (cond (schema? ?schema) ?schema - (into-schema? ?schema) (-into-schema ?schema nil nil options) + (into-schema? ?schema) (if (nil? options) + (-cached ?schema :schema #(-into-schema % nil nil nil)) + (-into-schema ?schema nil nil options)) (vector? ?schema) (let [v #?(:clj ^IPersistentVector ?schema, :cljs ?schema) t (-lookup! #?(:clj (.nth v 0), :cljs (nth v 0)) into-schema? true options) n #?(:bb (count v) :clj (.count v), :cljs (count v)) From 5a0c254aa2673cb590c459801ab25b395448bdbe Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Tue, 14 Mar 2023 16:27:33 +0200 Subject: [PATCH 3/3] memory metering --- deps.edn | 1 + perf/malli/perf/core.cljc | 5 ++++- perf/malli/perf/creation_perf_test.cljc | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/deps.edn b/deps.edn index e13550251..910364510 100644 --- a/deps.edn +++ b/deps.edn @@ -62,6 +62,7 @@ :perf {:extra-paths ["perf"] :extra-deps {criterium/criterium {:mvn/version "0.4.6"} org.clojure/clojure {:mvn/version "1.11.1"} + com.clojure-goes-fast/clj-memory-meter {:mvn/version "0.2.2"} com.clojure-goes-fast/clj-async-profiler {:mvn/version "1.0.3"}} :jvm-opts ["-server" "-Xmx4096m" diff --git a/perf/malli/perf/core.cljc b/perf/malli/perf/core.cljc index b8bc3d55d..82ac356f3 100644 --- a/perf/malli/perf/core.cljc +++ b/perf/malli/perf/core.cljc @@ -1,5 +1,6 @@ (ns malli.perf.core (:require [criterium.core :as cc] + [clj-memory-meter.core :as mm] [clj-async-profiler.core :as prof])) (defn serve! [] @@ -18,11 +19,13 @@ (let [ns# (- (System/nanoTime) start#) times# (long (/ 100000000000000 ns#))] (println "invoking" times# "times") - (time (prof/profile (dotimes [_# times#] ~@body)))))) + (time (prof/profile {:event :cpu} (dotimes [_# times#] ~@body)))))) (defmacro bench [& body] `(do (serve!) (-bench ~@body) (profile ~@body))) +(def measure mm/measure) + (comment (clear!)) (defmacro profile-for diff --git a/perf/malli/perf/creation_perf_test.cljc b/perf/malli/perf/creation_perf_test.cljc index 71fc21366..d513466a4 100644 --- a/perf/malli/perf/creation_perf_test.cljc +++ b/perf/malli/perf/creation_perf_test.cljc @@ -147,7 +147,12 @@ ;; does not work with direct linking (with-redefs [m/-check-children? (constantly false)] - (p/bench (m/schema ?schema)))) + (p/bench (m/schema ?schema))) + + ;; memory allocation, THIS IS NOT CORRECT as it follows parents, which are shared + (p/measure (m/schema ?schema)) ;; => 5.7KiB + + ) (def ref-schema (m/schema [:schema :int]))