Much faster without transients

This commit is contained in:
Tommi Reiman 2019-02-09 15:05:31 +02:00
parent 81b9bdceef
commit 659aac7fd0
4 changed files with 12 additions and 17 deletions

View file

@ -3,7 +3,6 @@ package reitit;
// https://www.codeproject.com/Tips/1190293/Iteration-Over-Java-Collections-with-High-Performa // https://www.codeproject.com/Tips/1190293/Iteration-Over-Java-Collections-with-High-Performa
import clojure.lang.IPersistentMap; import clojure.lang.IPersistentMap;
import clojure.lang.ITransientMap;
import clojure.lang.Keyword; import clojure.lang.Keyword;
import clojure.lang.PersistentArrayMap; import clojure.lang.PersistentArrayMap;
@ -35,26 +34,20 @@ public class Trie {
case '+': case '+':
hasPlus = true; hasPlus = true;
break; break;
default:
break;
} }
} }
return decode(chars, begin, end, hasPercent, hasPlus); return decode(chars, begin, end, hasPercent, hasPlus);
} }
public static class Match { public static class Match {
final ITransientMap params = PersistentArrayMap.EMPTY.asTransient(); public IPersistentMap params = PersistentArrayMap.EMPTY;
public Object data; public Object data;
public IPersistentMap parameters() {
return params.persistent();
}
@Override @Override
public String toString() { public String toString() {
Map<Object, Object> m = new HashMap<>(); Map<Object, Object> m = new HashMap<>();
m.put(Keyword.intern("data"), data); m.put(Keyword.intern("data"), data);
m.put(Keyword.intern("params"), parameters()); m.put(Keyword.intern("params"), params);
return m.toString(); return m.toString();
} }
} }
@ -165,8 +158,6 @@ public class Trie {
@Override @Override
public Match match(int i, int max, char[] path, Match match) { public Match match(int i, int max, char[] path, Match match) {
if (i < max && path[i] != end) { if (i < max && path[i] != end) {
boolean hasPercent = false;
boolean hasPlus = false;
int stop = max; int stop = max;
for (int j = i; j < max; j++) { for (int j = i; j < max; j++) {
final char c = path[j]; final char c = path[j];
@ -174,12 +165,10 @@ public class Trie {
stop = j; stop = j;
break; break;
} }
hasPercent = hasPercent || c == '%';
hasPlus = hasPlus || c == '+';
} }
final Match m = child.match(stop, max, path, match); final Match m = child.match(stop, max, path, match);
if (m != null) { if (m != null) {
m.params.assoc(key, decode(path, i, stop, hasPercent, hasPlus)); m.params = m.params.assoc(key, decode(path, i, stop));
} }
return m; return m;
} }
@ -218,7 +207,7 @@ public class Trie {
@Override @Override
public Match match(int i, int max, char[] path, Match match) { public Match match(int i, int max, char[] path, Match match) {
if (i < max) { if (i < max) {
match.params.assoc(parameter, decode(path, i, max)); match.params = match.params.assoc(parameter, decode(path, i, max));
match.data = data; match.data = data;
return match; return match;
} }

View file

@ -226,7 +226,7 @@
(defn lookup [matcher path] (defn lookup [matcher path]
#?(:clj (if-let [match ^Trie$Match (Trie/lookup ^Trie$Matcher matcher ^String path)] #?(:clj (if-let [match ^Trie$Match (Trie/lookup ^Trie$Matcher matcher ^String path)]
(->Match (.data match) (.parameters match))) (->Match (.data match) (.params match)))
:cljs (if-let [match (match matcher 0 (count path) path)] :cljs (if-let [match (match matcher 0 (count path) path)]
(let [params (if-let [path-params (:path-params match)] (let [params (if-let [path-params (:path-params match)]
(persistent! path-params) (persistent! path-params)

View file

@ -348,6 +348,7 @@
;; 64µs (trie-router, no injects, optimized) - 124µs (clojure) ;; 64µs (trie-router, no injects, optimized) - 124µs (clojure)
;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure) ;; 63µs (trie-router, no injects, switch-case) - 124µs (clojure)
;; 63ns (trie-router, no injects, direct-data) ;; 63ns (trie-router, no injects, direct-data)
;; 54ns (trie-router, non-transient params)
(let [requests (mapv route->req routes)] (let [requests (mapv route->req routes)]
(title "all") (title "all")
(cc/quick-bench (cc/quick-bench

View file

@ -572,6 +572,7 @@
;; 326ns (java-segment-router) ;; 326ns (java-segment-router)
;; 194ns (trie) ;; 194ns (trie)
;; 160ns (trie, prioritized) ;; 160ns (trie, prioritized)
;; 130ns (trie, non-transient, direct-data)
(b! "reitit" reitit-f) (b! "reitit" reitit-f)
;; 2845ns ;; 2845ns
@ -585,16 +586,18 @@
;; 373ns (trie) ;; 373ns (trie)
;; 323ns (trie, prioritized) ;; 323ns (trie, prioritized)
;; 289ns (trie, prioritized, zero-copy) ;; 289ns (trie, prioritized, zero-copy)
;; 266ns (trie, non-transient, direct-data)
(b! "reitit-ring" reitit-ring-f) (b! "reitit-ring" reitit-ring-f)
;; 385ns (java-segment-router, no injects) ;; 385ns (java-segment-router, no injects)
;; 271ms (trie) ;; 271ms (trie)
;; 240ns (trie, prioritized) ;; 240ns (trie, prioritized)
;; 214ns (trie, non-transient, direct-data)
(b! "reitit-ring-fast" reitit-ring-fast-f) (b! "reitit-ring-fast" reitit-ring-fast-f)
;; 240ns (trie, prioritized, zero-copy)
;; 2553ns (linear-router) ;; 2553ns (linear-router)
;; 630ns (segment-router-backed) ;; 630ns (segment-router-backed)
;; 464ns (trie, non-transient, direct-data)
(b! "reitit-ring-linear" reitit-ring-linear-f) (b! "reitit-ring-linear" reitit-ring-linear-f)
;; 2137ns ;; 2137ns
@ -627,6 +630,7 @@
;; 629ms (arraylist) ;; 629ms (arraylist)
;; 409ns (transient) ;; 409ns (transient)
;; 409ns (staticMultiMatcher) ;; 409ns (staticMultiMatcher)
;; 305ns (non-persistent-params)
(let [app (ring/ring-handler (ring/router opensensors-routes) {:inject-match? false, :inject-router? false}) (let [app (ring/ring-handler (ring/router opensensors-routes) {:inject-match? false, :inject-router? false})
request {:uri "/v1/users/1/devices/1", :request-method :get}] request {:uri "/v1/users/1/devices/1", :request-method :get}]
(doseq [[p r] (-> app (ring/get-router) (r/routes))] (doseq [[p r] (-> app (ring/get-router) (r/routes))]
@ -638,6 +642,7 @@
(prof/start {}) (prof/start {})
; "Elapsed time: 9183.657012 msecs" ; "Elapsed time: 9183.657012 msecs"
; "Elapsed time: 8674.70132 msecs" ; "Elapsed time: 8674.70132 msecs"
; "Elapsed time: 6714.434915 msecs"
(time (time
(dotimes [_ 20000000] (dotimes [_ 20000000]
(app request))) (app request)))