Skip to content

Commit b0cd78f

Browse files
committed
Testing code for IConvertList
1 parent 9253041 commit b0cd78f

8 files changed

Lines changed: 331 additions & 1 deletion

File tree

bin/lc-stress-tests.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
3+
struct_sizes=(0 1 8 16 32 64 256 1024)
4+
5+
for size in "${struct_sizes[@]}"; do
6+
case $JOB_COMPLETION_INDEX in
7+
0|1)
8+
if (( JOB_COMPLETION_INDEX == 0)); then
9+
lein with-profile +bench,+fressian-old run -- "vec" ${size} false
10+
else
11+
lein with-profile +bench,+fressian-old run -- "map" ${size} false
12+
fi
13+
;;
14+
2|3)
15+
if (( JOB_COMPLETION_INDEX == 2)); then
16+
lein with-profile +bench,+fressian-new run -- "vec" ${size} false
17+
else
18+
lein with-profile +bench,+fressian-new run -- "map" ${size} false
19+
fi
20+
;;
21+
4|5)
22+
if (( JOB_COMPLETION_INDEX == 4)); then
23+
lein with-profile +bench,+fressian-new run -- "vec" ${size} true
24+
else
25+
lein with-profile +bench,+fressian-new run -- "map" ${size} true
26+
fi
27+
;;
28+
esac
29+
done

dev/aux.clj

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
(ns aux
2+
(:require [clojure.string :as str])
3+
(:import [org.slf4j LoggerFactory]))
4+
5+
(defn get-fressian-version []
6+
(let [libs (-> (System/getProperty "java.class.path")
7+
(str/split #":"))
8+
jar (->> libs
9+
(filter #(str/includes? % "org/fressian"))
10+
(first))]
11+
(->> jar
12+
(re-find #".*fressian-(.*)\.jar")
13+
(second))))
14+
15+
16+
17+
(defn- log [level msg]
18+
`(let [logger# (LoggerFactory/getLogger "fressian")]
19+
(. logger# ~level (str ~msg))))
20+
21+
(defmacro debug [msg]
22+
(log 'debug msg))
23+
24+
(defmacro info [msg]
25+
(log 'info msg))
26+
27+
(defmacro warn [msg]
28+
(log 'warn msg))
29+
30+
(defmacro error [msg]
31+
(log 'error msg))

dev/metrics.clj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
(ns metrics
2+
(:require [aux :as a]
3+
[clojure.core.async :as async])
4+
(:import [io.prometheus.metrics.core.metrics Summary]
5+
[io.prometheus.metrics.exporter.httpserver HTTPServer]
6+
[io.prometheus.metrics.instrumentation.jvm JvmMetrics]
7+
[io.prometheus.metrics.model.snapshots Labels Unit]))
8+
9+
(defn initialize-and-return-metrics []
10+
(.register (JvmMetrics/builder))
11+
(let [fressian-version nil #_(a/get-fressian-version)
12+
metric-map nil #_{:test-metric (-> (Summary/builder)
13+
(.name "defressian_1000structs_seconds")
14+
(.unit Unit/SECONDS)
15+
(.quantile 0.5 0.01)
16+
(.quantile 0.9 0.01)
17+
(.constLabels (Labels/of (into-array ["fressian_version" fressian-version])))
18+
(.labelNames (into-array ["struct_type" "struct_size" "list_conversion"]))
19+
(.register))}]
20+
(async/thread (-> (HTTPServer/builder)
21+
(.port 9000)
22+
(.buildAndStart)))
23+
(a/info {:event :initialized-metrics})
24+
#_metric-map))

dev/simple_stress_test.clj

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
(ns simple-stress-test
2+
(:require [aux :as a]
3+
[clojure.core.async :as async]
4+
[clojure.edn :as edn]
5+
[metrics :as m])
6+
(:import [java.io ByteArrayInputStream ByteArrayOutputStream]
7+
[org.fressian FressianReader FressianWriter]
8+
[org.fressian.handlers ConvertList ILookup]))
9+
10+
(def custom-read-handlers
11+
(reify ILookup
12+
(valAt [_ k]
13+
(get {"fressian/list"
14+
(reify ConvertList
15+
(convertList [_ items]
16+
(vec items)))}
17+
k))))
18+
19+
(defn gen-vec [size]
20+
(into [] (for [_ (range size)]
21+
(str (random-uuid)))))
22+
23+
(defn gen-map [size]
24+
(into {} (for [_ (range size)]
25+
{(str (random-uuid)) (str (random-uuid))})))
26+
27+
(defn fressian [data]
28+
(with-open [baos (ByteArrayOutputStream.)
29+
fw (FressianWriter. baos)]
30+
(.writeObject fw data)
31+
(.toByteArray baos)))
32+
33+
(defn defressian [data & [handlers]]
34+
(with-open [bais (ByteArrayInputStream. data)
35+
fr (FressianReader. bais handlers)]
36+
(.readObject fr)))
37+
38+
(defmacro measure-duration [& body]
39+
`(let [st# (System/currentTimeMillis)]
40+
~@body
41+
(- (System/currentTimeMillis) st#)))
42+
43+
(defn stress-test [{:keys [struct-type struct-size convert-list?] :as argmap}]
44+
(let [gen-struct-fn (case (str struct-type)
45+
"map" gen-map
46+
"vec" gen-vec)
47+
fr-handlers (when convert-list? custom-read-handlers)]
48+
(a/info (merge {:event :starting-stress-test} argmap))
49+
(let [work-chan (async/chan 1)
50+
timeout-chan (async/timeout (* 1000 60 20))]
51+
(loop [runs 0
52+
proc-time 0]
53+
(let [structs (repeatedly 1000 #(gen-struct-fn struct-size))
54+
; put generated structs fressianed into the work channel as a single coll
55+
_ (async/put! work-chan (into [] (for [st structs] (fressian st))))
56+
[val port] (async/alts!! [work-chan timeout-chan])]
57+
(cond
58+
(= port timeout-chan)
59+
(a/info (merge {:event :stress-test-complete :runs runs :processing-time proc-time} argmap))
60+
61+
(= port work-chan)
62+
; measure time to read all structs in work chan
63+
(let [dur (measure-duration (doseq [fs val]
64+
(defressian fs fr-handlers)))]
65+
(recur (inc runs) (+ proc-time dur)))))))))
66+
67+
(defn -main [& args]
68+
(let [parsed-args (map edn/read-string args)
69+
argmap (zipmap [:struct-type :struct-size :convert-list?] parsed-args)]
70+
(m/initialize-and-return-metrics)
71+
(stress-test argmap)
72+
(System/exit 0)))

dev/stress_test.clj

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
(ns stress-test
2+
(:require [aux :as a]
3+
[clojure.core.async :as async]
4+
[clojure.data.fressian :as fr]
5+
[clojure.edn :as edn]
6+
[metrics :as m])
7+
(:import [io.prometheus.metrics.core.datapoints TimerApi]
8+
[org.fressian.handlers ConvertList]))
9+
10+
(def read-handlers
11+
{"fressian/list"
12+
(reify ConvertList
13+
(convertList [_ items]
14+
(vec items)))})
15+
16+
(defn gen-vec [size]
17+
(into [] (for [_ (range size)]
18+
(random-uuid))))
19+
20+
(defn gen-map [size]
21+
(into {} (for [_ (range size)]
22+
{(random-uuid) (random-uuid)})))
23+
24+
(defmacro with-duration [metric & body]
25+
`(let [t# (.startTimer ~metric)
26+
st# (System/currentTimeMillis)]
27+
(try
28+
~@body
29+
(- (System/currentTimeMillis) st#)
30+
(finally
31+
(.close t#)))))
32+
33+
(defn stress-test [{:keys [struct-type struct-size convert-list?] :as argmap}]
34+
(let [gen-struct-fn (case struct-type
35+
'map gen-map
36+
'vec gen-vec)
37+
metric ^TimerApi (-> (:test-metric (m/initialize-and-return-metrics))
38+
(.labelValues (into-array String (map str [struct-type struct-size
39+
(if convert-list?
40+
"enabled" "disabled")]))))
41+
; pass custom ConvertList or fallback to defualt read handlers in data.fressian
42+
fr-handlers (if convert-list?
43+
(-> fr/clojure-read-handlers (merge read-handlers) (fr/associative-lookup))
44+
(fr/associative-lookup fr/clojure-read-handlers))]
45+
; We need to wait for Prometheus to pick up monitoring
46+
(Thread/sleep ^long (* 1000 60 1))
47+
(a/info (merge {:event :starting-stress-test} argmap))
48+
(let [work-chan (async/chan 1)
49+
timeout-chan (async/timeout (* 1000 60 15))]
50+
(loop [runs 0
51+
proc-time 0]
52+
(let [structs (repeatedly 1000 #(gen-struct-fn struct-size))
53+
; put generated structs fressianed into the work channel as a single coll
54+
_ (async/put! work-chan (for [st structs] (fr/write st)))
55+
[val port] (async/alts!! [work-chan timeout-chan])]
56+
(cond
57+
(= port timeout-chan)
58+
(a/info (merge {:event :stress-test-complete :runs runs :processing-time proc-time} argmap))
59+
60+
(= port work-chan)
61+
; measure time to read all structs in work chan
62+
(let [dur (with-duration metric (doseq [fs val]
63+
(fr/read fs :handlers fr-handlers)))]
64+
(recur (inc runs) (+ proc-time dur)))))))))
65+
66+
(defn -main [& args]
67+
(let [parsed-args (map edn/read-string args)
68+
argmap (zipmap [:struct-type :struct-size :convert-list?] parsed-args)]
69+
(stress-test argmap)
70+
(System/exit 0)))

project.clj

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,30 @@
33
:url "https://github.com/clojure/data.fressian"
44
:license {:name "Eclipse Public License - v 1.0"
55
:url "http://www.eclipse.org/legal/epl-v10.html"}
6+
:source-paths ["src/main/clojure"]
67
:dependencies [[org.clojure/clojure "1.9.0"]
78
[org.fressian/fressian "0.6.8"]
89
[org.clojure/test.generative "1.1.0" :scope "test"]]
9-
:jvm-opts ["-Xmx2g" "-server"])
10+
:profiles {:fressian-dev {:source-paths ["dev"]
11+
:java-source-paths ["../fressian/src"]
12+
:dependencies [#_[org.fressian/fressian "0.6.9-SNAPSHOT"]
13+
[org.clojure/clojure "1.12.0"]
14+
[com.clojure-goes-fast/clj-memory-meter "0.3.0"]]
15+
:repl-options {:port 5555}
16+
:jvm-opts ["-Djdk.attach.allowAttachSelf"]}
17+
:bench {:source-paths ["dev"]
18+
:dependencies [[org.clojure/clojure "1.12.0"]
19+
[org.clojure/core.async "1.6.681"]
20+
[ch.qos.logback/logback-classic "1.5.16"]
21+
[io.prometheus/prometheus-metrics-core "1.3.5"]
22+
[io.prometheus/prometheus-metrics-instrumentation-jvm "1.3.5"]
23+
[io.prometheus/prometheus-metrics-exporter-httpserver "1.3.5"]]
24+
:jvm-opts ["-server"
25+
"-Xms8g" "-Xmx8g"
26+
"-XX:+UseZGC"]}
27+
:fressian-new {:dependencies [[org.fressian/fressian "0.6.9-SNAPSHOT"]]
28+
:main simple-stress-test}
29+
:fressian-old {:dependencies [[org.fressian/fressian "0.6.8"]]
30+
:main simple-stress-test}}
31+
32+
:jvm-opts ["-Xmx2g" "-server"])

resources/k8s.yaml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: fressian-test
5+
spec:
6+
completions: 6
7+
parallelism: 6
8+
completionMode: Indexed
9+
template:
10+
metadata:
11+
labels:
12+
app: fressian-test
13+
spec:
14+
nodeSelector:
15+
role: worker
16+
restartPolicy: Never
17+
containers:
18+
- name: fressian-test-clj
19+
image: clojure:temurin-21-lein
20+
ports:
21+
- name: metrics
22+
containerPort: 9000
23+
volumeMounts:
24+
- name: data-fressian
25+
mountPath: "/opt/data.fressian"
26+
- name: maven
27+
mountPath: "/root/.m2"
28+
workingDir: "/opt/data.fressian"
29+
command: ["bash", "-c"]
30+
args:
31+
- "bin/lc-stress-tests.sh"
32+
resources:
33+
limits:
34+
cpu: 3000m
35+
memory: 10Gi
36+
volumes:
37+
- name: data-fressian
38+
hostPath:
39+
path: "/home/k3s/dev/datomic/repos/data.fressian"
40+
- name: maven
41+
hostPath:
42+
path: "/home/k3s/.m2"
43+
---
44+
apiVersion: v1
45+
kind: Service
46+
metadata:
47+
name: fressian-test-http
48+
labels:
49+
app: fressian-test
50+
spec:
51+
ports:
52+
- port: 9000
53+
selector:
54+
app: fressian-test
55+
---
56+
apiVersion: monitoring.coreos.com/v1
57+
kind: ServiceMonitor
58+
metadata:
59+
name: fressian-test
60+
spec:
61+
endpoints:
62+
- interval: 30s
63+
targetPort: 9000
64+
path: /metrics
65+
namespaceSelector:
66+
matchNames:
67+
- default
68+
selector:
69+
matchLabels:
70+
app: fressian-test

resources/logback.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<configuration>
2+
<appender name="STDOUT_K8S" class="ch.qos.logback.core.ConsoleAppender">
3+
<encoder>
4+
<pattern>java_time=%d{yyyy-MM-dd'T'HH:mm:ss.SSS'000000'XXX} level=%level context=%contextName logger=%logger{36} - %msg%n</pattern>
5+
</encoder>
6+
</appender>
7+
8+
<root level="info">
9+
<appender-ref ref="STDOUT_K8S"/>
10+
</root>
11+
</configuration>

0 commit comments

Comments
 (0)