nippy/test/taoensso/nippy_benchmarks.clj
Peter Taoussanis c2770c6e99 [mod] Refactor stress data
BREAKING for the very small minority of folks that use `nippy/stress-data`.

Changes:

1. Make `nippy/stress-data` a function

   It's unnecessarily wasteful to generate and store all this data when it's not
   being used in the common case.

2. Make data deterministic

   The stress data will now generally be stable by default between different versions
   of Nippy, etc. This will help support an upcoming test for stable serialized output.
2024-02-06 14:30:59 +01:00

176 lines
6.6 KiB
Clojure

(ns taoensso.nippy-benchmarks
(:require
[clojure.data.fressian :as fress]
[taoensso.encore :as enc]
[taoensso.nippy :as nippy]
[taoensso.nippy.compression :as compr]))
;;;; Reader
(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)
len (.remaining bb)
ba (byte-array len)]
(.get bb ba 0 len)
(do ba)))
(defn- thaw-fress [^bytes ba]
(let [bb (java.nio.ByteBuffer/wrap ba)]
(fress/read bb)))
(comment (-> data freeze-fress thaw-fress))
;;;; Benchable data
(def bench-data
"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)))
(comment
(clojure.set/difference
(set (keys (nippy/stress-data {:comparable? true})))
(set (keys bench-data))))
;;;;
(defn- bench1
[{:keys [laps warmup] :or {laps 1e4, warmup 25e3}} freezer thawer sizer]
(let [data-frozen (freezer bench-data)
time-freeze (enc/bench laps {:warmup-laps warmup} (freezer bench-data))
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}))
(comment (bench1 {} nippy/freeze nippy/thaw count))
(defn bench
[{:keys [all? reader? fressian? fressian? lzma2? laps warmup]
:or {laps 1e4
warmup 25e3}}]
(println "\nStarting benchmarks")
(let [results_ (atom {})]
(when (or all? reader?)
(println "Benching Reader...")
(swap! results_ assoc :reader
(bench1 {:laps laps, :warmup warmup}
freeze-reader thaw-reader
(fn [^String s] (count (.getBytes s "UTF-8"))))))
(when (or all? fressian?)
(println "- Benching Fressian...")
(swap! results_ assoc :fressian (bench1 {:laps laps, :warmup warmup} freeze-fress thaw-fress count)))
(when (or all? lzma2?)
(println "- Benching Nippy/LZMA2...")
(swap! results_ assoc :nippy/lzma2
(bench1 {:laps laps, :warmup warmup}
#(nippy/freeze % {:compressor nippy/lzma2-compressor})
#(nippy/thaw % {:compressor nippy/lzma2-compressor})
count)))
(println "- Benching Nippy/encrypted...")
(swap! results_ assoc :nippy/encrypted
(bench1 {:laps laps, :warmup warmup}
#(nippy/freeze % {:password [:cached "p"]})
#(nippy/thaw % {:password [:cached "p"]})
count))
(println "- Benching Nippy/default...")
(swap! results_ assoc :nippy/default (bench1 {:laps laps, :warmup warmup} nippy/freeze nippy/thaw count))
(println "- Benching Nippy/fast...")
(swap! results_ assoc :nippy/fast (bench1 {:laps laps, :warmup warmup} nippy/fast-freeze nippy/fast-thaw count))
(println "- Benchmarks complete! (Time for cake?)")
(let [results @results_]
(println "\nBenchmark results:")
(doseq [[k v] results] (println k " " v))
(do results))))
(comment
(do
(set! *unchecked-math* false)
(bench {:all? true}))
;; 2023 Sep 25, 2020 Apple MBP M1
;; [com.taoensso/nippy "3.2.0"]
;; [org.clojure/tools.reader "1.3.6"]
;; [org.clojure/data.fressian "1.0.0"]
{:reader {:round 36756, :freeze 6567, :thaw 30189, :size 39374}
:fressian {:round 6579, :freeze 3720, :thaw 2859, :size 22850}
:nippy/lzma2 {:round 33645, :freeze 20411, :thaw 13234, :size 11420}
:nippy/encrypted {:round 3894, :freeze 2260, :thaw 1634, :size 16717}
:nippy/default {:round 2796, :freeze 1467, :thaw 1329, :size 16689}
:nippy/fast {:round 2516, :freeze 1271, :thaw 1245, :size 28454}})
;;;; Compressors
(let [bench-data (nippy/freeze (nippy/stress-data {:comparable? true}) {:compressor nil})]
(defn bench1-compressor
[{:keys [laps warmup] :or {laps 1e4, warmup 2e4}} compressor]
(let [data-compressed (compr/compress compressor bench-data)
time-compress (enc/bench laps {:warmup-laps warmup} (compr/compress compressor bench-data))
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 bench-data)))}))
(defn bench-compressors [bench1-opts lzma-opts]
(merge
(let [bench1 #(bench1-compressor bench1-opts %)]
{: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))})
(let [bench1 #(bench1-compressor (merge bench1-opts lzma-opts) %)]
{:lzma2/level0 (bench1 (compr/->LZMA2Compressor 0))
:lzma2/level3 (bench1 (compr/->LZMA2Compressor 3))
:lzma2/level6 (bench1 (compr/->LZMA2Compressor 6))
:lzma2/level9 (bench1 (compr/->LZMA2Compressor 9))}))))
(comment
(bench-compressors
{:laps 1e4 :warmup 2e4}
{:laps 1e2 :warmup 2e2})
;; 2023 Aug 1, 2020 Apple MBP M1
;; [org.tukaani/xz "1.9"]
;; [io.airlift/aircompressor "0.25"]
{:zstd/prepended {:round 1672, :compress 1279, :decompress 393, :ratio 0.53}
:zstd/unprepended {:round 1668, :compress 1271, :decompress 397, :ratio 0.53}
:lz4 {:round 269, :compress 238, :decompress 31, :ratio 0.58}
:lzo {:round 259, :compress 216, :decompress 43, :ratio 0.58}
:snappy/prepended {:round 339, :compress 205, :decompress 134, :ratio 0.58}
:snappy/unprepended {:round 340, :compress 206, :decompress 134, :ratio 0.58}
:lzma2/level0 {:round 30300, :compress 18500, :decompress 11800, :ratio 0.4}
:lzma2/level3 {:round 49200, :compress 35700, :decompress 13500, :ratio 0.4}
:lzma2/level6 {:round 102600, :compress 86700, :decompress 15900, :ratio 0.41}
:lzma2/level9 {:round 434800, :compress 394700, :decompress 40100, :ratio 0.41}})