2023-09-25 15:45:09 +00:00
|
|
|
(ns taoensso.nippy-benchmarks
|
2023-08-01 10:19:25 +00:00
|
|
|
(:require
|
2023-09-25 13:16:48 +00:00
|
|
|
[clojure.data.fressian :as fress]
|
|
|
|
|
[taoensso.encore :as enc]
|
|
|
|
|
[taoensso.nippy :as nippy]
|
|
|
|
|
[taoensso.nippy.compression :as compr]))
|
2012-07-06 19:12:59 +00:00
|
|
|
|
2023-08-01 10:19:25 +00:00
|
|
|
;;;; Reader
|
2012-07-12 08:35:12 +00:00
|
|
|
|
2023-08-01 10:19:25 +00:00
|
|
|
(defn- freeze-reader [x] (enc/pr-edn x))
|
|
|
|
|
(defn- thaw-reader [edn] (enc/read-edn edn))
|
|
|
|
|
|
|
|
|
|
;;;; Fressian
|
|
|
|
|
|
|
|
|
|
(defn- freeze-fress [x]
|
|
|
|
|
(let [^java.nio.ByteBuffer bb (fress/write x)
|
2014-01-21 07:44:53 +00:00
|
|
|
len (.remaining bb)
|
|
|
|
|
ba (byte-array len)]
|
|
|
|
|
(.get bb ba 0 len)
|
2023-08-01 10:19:25 +00:00
|
|
|
(do ba)))
|
|
|
|
|
|
|
|
|
|
(defn- thaw-fress [^bytes ba]
|
|
|
|
|
(let [bb (java.nio.ByteBuffer/wrap ba)]
|
|
|
|
|
(fress/read bb)))
|
|
|
|
|
|
|
|
|
|
(comment (-> data freeze-fress thaw-fress))
|
2014-01-21 07:44:53 +00:00
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
;;;; Bench data
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
(def default-bench-data
|
2024-01-11 16:46:14 +00:00
|
|
|
"Subset of stress data suitable for benching."
|
|
|
|
|
(let [sd (nippy/stress-data {:comparable? true})]
|
|
|
|
|
(reduce-kv
|
|
|
|
|
(fn [m k v]
|
|
|
|
|
(try
|
|
|
|
|
(-> v freeze-reader thaw-reader)
|
|
|
|
|
(-> v freeze-fress thaw-fress)
|
|
|
|
|
m
|
|
|
|
|
(catch Throwable _ (dissoc m k))))
|
|
|
|
|
sd sd)))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
|
|
|
|
(comment
|
|
|
|
|
(clojure.set/difference
|
2024-01-11 16:46:14 +00:00
|
|
|
(set (keys (nippy/stress-data {:comparable? true})))
|
2024-01-15 11:45:21 +00:00
|
|
|
(set (keys default-bench-data))))
|
2014-01-21 07:44:53 +00:00
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
;;;; Serialization
|
|
|
|
|
|
|
|
|
|
(defn- bench1-serialization
|
|
|
|
|
[freezer thawer sizer
|
|
|
|
|
{:keys [laps warmup bench-data]
|
|
|
|
|
:or
|
|
|
|
|
{laps 1e4
|
|
|
|
|
warmup 25e3
|
|
|
|
|
bench-data default-bench-data}}]
|
2014-01-21 07:44:53 +00:00
|
|
|
|
2024-01-11 16:46:14 +00:00
|
|
|
(let [data-frozen (freezer bench-data)
|
|
|
|
|
time-freeze (enc/bench laps {:warmup-laps warmup} (freezer bench-data))
|
2023-08-01 10:19:25 +00:00
|
|
|
time-thaw (enc/bench laps {:warmup-laps warmup} (thawer data-frozen))
|
|
|
|
|
data-size (sizer data-frozen)]
|
|
|
|
|
|
|
|
|
|
{:round (+ time-freeze time-thaw)
|
|
|
|
|
:freeze time-freeze
|
|
|
|
|
:thaw time-thaw
|
|
|
|
|
:size data-size}))
|
|
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
(comment (bench1-serialization nippy/freeze nippy/thaw count {}))
|
|
|
|
|
|
|
|
|
|
(defn- printed-results [results]
|
|
|
|
|
(println "\nBenchmark results:")
|
|
|
|
|
(doseq [[k v] results] (println k " " v))
|
|
|
|
|
(do results))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
(defn bench-serialization
|
|
|
|
|
[{:keys [all? reader? fressian? fressian? lzma2? laps warmup bench-data]
|
|
|
|
|
:as opts
|
|
|
|
|
:or
|
|
|
|
|
{laps 1e4
|
|
|
|
|
warmup 25e3}}]
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-02-12 16:45:20 +00:00
|
|
|
(println "\nRunning benchmarks...")
|
2023-08-01 10:19:25 +00:00
|
|
|
|
|
|
|
|
(let [results_ (atom {})]
|
|
|
|
|
(when (or all? reader?)
|
2024-02-12 16:45:20 +00:00
|
|
|
(println " With Reader...")
|
2023-08-01 10:19:25 +00:00
|
|
|
(swap! results_ assoc :reader
|
2024-01-15 11:45:21 +00:00
|
|
|
(bench1-serialization freeze-reader thaw-reader
|
|
|
|
|
(fn [^String s] (count (.getBytes s "UTF-8")))
|
|
|
|
|
(assoc opts :laps laps, :warmup warmup))))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
|
|
|
|
(when (or all? fressian?)
|
2024-02-12 16:45:20 +00:00
|
|
|
(println " With Fressian...")
|
2024-01-15 11:45:21 +00:00
|
|
|
(swap! results_ assoc :fressian
|
|
|
|
|
(bench1-serialization freeze-fress thaw-fress count
|
|
|
|
|
(assoc opts :laps laps, :warmup warmup))))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
|
|
|
|
(when (or all? lzma2?)
|
2024-02-12 16:45:20 +00:00
|
|
|
(println " With Nippy/LZMA2...")
|
2023-08-01 10:19:25 +00:00
|
|
|
(swap! results_ assoc :nippy/lzma2
|
2024-01-15 11:45:21 +00:00
|
|
|
(bench1-serialization
|
2023-08-01 10:19:25 +00:00
|
|
|
#(nippy/freeze % {:compressor nippy/lzma2-compressor})
|
|
|
|
|
#(nippy/thaw % {:compressor nippy/lzma2-compressor})
|
2024-01-15 11:45:21 +00:00
|
|
|
count
|
|
|
|
|
(assoc opts :laps laps, :warmup warmup))))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-02-12 16:45:20 +00:00
|
|
|
(println " With Nippy/encrypted...")
|
2023-08-01 10:19:25 +00:00
|
|
|
(swap! results_ assoc :nippy/encrypted
|
2024-01-15 11:45:21 +00:00
|
|
|
(bench1-serialization
|
2023-08-01 10:19:25 +00:00
|
|
|
#(nippy/freeze % {:password [:cached "p"]})
|
|
|
|
|
#(nippy/thaw % {:password [:cached "p"]})
|
2024-01-15 11:45:21 +00:00
|
|
|
count
|
|
|
|
|
(assoc opts :laps laps, :warmup warmup)))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-02-12 16:45:20 +00:00
|
|
|
(println " With Nippy/default...")
|
2024-01-15 11:45:21 +00:00
|
|
|
(swap! results_ assoc :nippy/default
|
|
|
|
|
(bench1-serialization nippy/freeze nippy/thaw count
|
|
|
|
|
(assoc opts :laps laps, :warmup warmup)))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-02-12 16:45:20 +00:00
|
|
|
(println " With Nippy/fast...")
|
2024-01-15 11:45:21 +00:00
|
|
|
(swap! results_ assoc :nippy/fast
|
|
|
|
|
(bench1-serialization nippy/fast-freeze nippy/fast-thaw count
|
|
|
|
|
(assoc opts :laps laps, :warmup warmup)))
|
2023-08-01 10:19:25 +00:00
|
|
|
|
2024-02-12 16:45:20 +00:00
|
|
|
(println "\nBenchmarks done:")
|
2024-01-15 11:45:21 +00:00
|
|
|
(printed-results @results_)))
|
|
|
|
|
|
|
|
|
|
;;;; Compression
|
|
|
|
|
|
|
|
|
|
(defn- bench1-compressor
|
|
|
|
|
[compressor
|
|
|
|
|
{:keys [laps warmup bench-data]
|
|
|
|
|
:or
|
|
|
|
|
{laps 1e4
|
|
|
|
|
warmup 2e4
|
|
|
|
|
bench-data default-bench-data}}]
|
|
|
|
|
|
|
|
|
|
(let [data-frozen (nippy/freeze bench-data {:compressor nil})
|
|
|
|
|
data-compressed (compr/compress compressor data-frozen)
|
|
|
|
|
time-compress (enc/bench laps {:warmup-laps warmup} (compr/compress compressor data-frozen))
|
|
|
|
|
time-decompress (enc/bench laps {:warmup-laps warmup} (compr/decompress compressor data-compressed))]
|
|
|
|
|
|
|
|
|
|
{:round (+ time-compress time-decompress)
|
|
|
|
|
:compress time-compress
|
|
|
|
|
:decompress time-decompress
|
|
|
|
|
:ratio (enc/round2 (/ (count data-compressed) (count data-frozen)))}))
|
|
|
|
|
|
|
|
|
|
(defn bench-compressors [opts lzma-opts]
|
|
|
|
|
(printed-results
|
2023-09-25 13:16:48 +00:00
|
|
|
(merge
|
2024-01-15 11:45:21 +00:00
|
|
|
(let [bench1 #(bench1-compressor % opts)]
|
2023-09-25 13:16:48 +00:00
|
|
|
{:zstd/prepended (bench1 (compr/->ZstdCompressor true))
|
|
|
|
|
:zstd/unprepended (bench1 (compr/->ZstdCompressor false))
|
|
|
|
|
:lz4 (bench1 (compr/->LZ4Compressor))
|
|
|
|
|
:lzo (bench1 (compr/->LZOCompressor))
|
|
|
|
|
:snappy/prepended (bench1 (compr/->SnappyCompressor true))
|
|
|
|
|
:snappy/unprepended (bench1 (compr/->SnappyCompressor false))})
|
|
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
(let [bench1 #(bench1-compressor % (merge opts lzma-opts))]
|
2023-09-25 13:16:48 +00:00
|
|
|
{:lzma2/level0 (bench1 (compr/->LZMA2Compressor 0))
|
|
|
|
|
:lzma2/level3 (bench1 (compr/->LZMA2Compressor 3))
|
|
|
|
|
:lzma2/level6 (bench1 (compr/->LZMA2Compressor 6))
|
|
|
|
|
:lzma2/level9 (bench1 (compr/->LZMA2Compressor 9))}))))
|
|
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
;;;; Results
|
|
|
|
|
|
2023-09-25 13:16:48 +00:00
|
|
|
(comment
|
2024-01-15 11:45:21 +00:00
|
|
|
{:last-updated "2024-01-16"
|
2024-02-12 16:45:20 +00:00
|
|
|
:system "2020 Macbook Pro M1, 16 GB memory"
|
2024-01-15 11:45:21 +00:00
|
|
|
:clojure-version "1.11.1"
|
|
|
|
|
:java-version "OpenJDK 21"
|
|
|
|
|
:deps
|
|
|
|
|
'[[com.taoensso/nippy "3.4.0-beta1"]
|
|
|
|
|
[org.clojure/tools.reader "1.3.7"]
|
|
|
|
|
[org.clojure/data.fressian "1.0.0"]
|
|
|
|
|
[org.tukaani/xz "1.9"]
|
|
|
|
|
[io.airlift/aircompressor "0.25"]]}
|
|
|
|
|
|
|
|
|
|
(bench-serialization {:all? true})
|
|
|
|
|
|
|
|
|
|
{:reader {:round 13496, :freeze 5088, :thaw 8408, :size 15880}
|
|
|
|
|
:fressian {:round 3898, :freeze 2350, :thaw 1548, :size 12222}
|
|
|
|
|
:nippy/lzma2 {:round 12341, :freeze 7809, :thaw 4532, :size 3916}
|
|
|
|
|
:nippy/encrypted {:round 2939, :freeze 1505, :thaw 1434, :size 8547}
|
|
|
|
|
:nippy/default {:round 2704, :freeze 1330, :thaw 1374, :size 8519}
|
|
|
|
|
:nippy/fast {:round 2425, :freeze 1117, :thaw 1308, :size 17088}}
|
|
|
|
|
|
|
|
|
|
(enc/round2 (/ 2704 13496)) ; 0.20 of reader roundtrip time
|
|
|
|
|
(enc/round2 (/ 2704 3898)) ; 0.69 of fressian roundtrip time
|
|
|
|
|
|
|
|
|
|
(enc/round2 (/ 8519 15880)) ; 0.54 of reader output size
|
|
|
|
|
(enc/round2 (/ 8519 12222)) ; 0.70 of fressian output size
|
|
|
|
|
|
2023-09-25 13:16:48 +00:00
|
|
|
(bench-compressors
|
|
|
|
|
{:laps 1e4 :warmup 2e4}
|
|
|
|
|
{:laps 1e2 :warmup 2e2})
|
|
|
|
|
|
2024-01-15 11:45:21 +00:00
|
|
|
;; Note that ratio depends on compressibility of stress data
|
|
|
|
|
{:lz4 {:round 293, :compress 234, :decompress 59, :ratio 0.5}
|
|
|
|
|
:lzo {:round 483, :compress 349, :decompress 134, :ratio 0.46}
|
|
|
|
|
:snappy/prepended {:round 472, :compress 296, :decompress 176, :ratio 0.43}
|
|
|
|
|
:snappy/unprepended {:round 420, :compress 260, :decompress 160, :ratio 0.43}
|
|
|
|
|
:zstd/prepended {:round 2105, :compress 1419, :decompress 686, :ratio 0.3}
|
|
|
|
|
:zstd/unprepended {:round 1261, :compress 921, :decompress 340, :ratio 0.3}
|
|
|
|
|
:lzma2/level0 {:round 158, :compress 121, :decompress 37, :ratio 0.24}
|
|
|
|
|
:lzma2/level3 {:round 536, :compress 436, :decompress 100, :ratio 0.22}
|
|
|
|
|
:lzma2/level6 {:round 1136, :compress 1075, :decompress 61, :ratio 0.21}
|
|
|
|
|
:lzma2/level9 {:round 2391, :compress 2096, :decompress 295, :ratio 0.21}})
|