Skip to content

Commit

Permalink
Optimize hot-path methods
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-yakushev committed Aug 5, 2024
1 parent 5ab004c commit fefe427
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 38 deletions.
4 changes: 3 additions & 1 deletion src/methodical/impl/cache/simple.clj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[methodical.util.describe :as describe]
[pretty.core :as pretty])
(:import
(clojure.lang IPersistentMap IDeref)
(methodical.interface Cache)))

(set! *warn-on-reflection* true)
Expand All @@ -21,7 +22,8 @@

Cache
(cached-method [_ dispatch-value]
(get @atomm dispatch-value))
;; This code is very hot, hence direct interop makes a difference here.
(.valAt ^IPersistentMap (.deref ^IDeref atomm) dispatch-value))

(cache-method! [_ dispatch-value method]
(swap! atomm assoc dispatch-value method))
Expand Down
18 changes: 1 addition & 17 deletions src/methodical/impl/combo/threaded.clj
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,7 @@
;; If there is only the combined primary method, skip the wrapping dance and just return it.
primary

(let [methods (concat before [primary] (reverse after))
threaded-fn-0 (reduce (fn [current wrapping]
(fn threaded-fn-0 [] (current) (wrapping)))
methods)
threaded-fn-1 (reduce (fn [current wrapping]
(fn threaded-fn-1 [a] (wrapping (current a))))
methods)
threaded-fn-2 (reduce (fn [current wrapping]
(fn threaded-fn-2 [a b] (wrapping a (current a b))))
methods)
threaded-fn-3 (reduce (fn [current wrapping]
(fn threaded-fn-3 [a b c] (wrapping a b (current a b c))))
methods)
threaded-fn-n (reduce (fn [current wrapping]
(fn threaded-fn-n [a b c & more]
(apply wrapping a b c (concat (butlast more) [(apply current a b c more)]))))
methods)]
(let [methods (concat before [primary] (reverse after))]
(-> (reduce
(fn [current next]
(fn combined-method-thread-last
Expand Down
40 changes: 20 additions & 20 deletions src/methodical/impl/multifn/cached.clj
Original file line number Diff line number Diff line change
Expand Up @@ -54,26 +54,26 @@
(CachedMultiFnImpl. new-impl (i/empty-copy cache)))))

(effective-method [_ dispatch-value]
(or
(.cached-method cache dispatch-value)
;; just like vanilla multimethods, we will add a new entry for every unique dispatch value we encounter, so
;; there's an implicit assumption that dispatch values are bounded
;;
;; build the effective method for dispatch value. We may end up throwing this out, but we currently need to build
;; it to determine the effective dispatch value.
(let [method (i/effective-method impl dispatch-value)
effective-dispatch-value (:dispatch-value (meta method))
;; If a method with the same effective dispatch value is already cached, add the existing method to the
;; cache for dispatch value. This way we don't end up with a bunch of duplicate methods impls for various
;; dispatch values that have the same effective dispatch value
cached-effective-dv-method (.cached-method cache effective-dispatch-value)
method (or cached-effective-dv-method method)]
;; Make sure the method was cached for the effective dispatch value as well, that way if some less-specific
;; dispatch value comes along with the same effective dispatch value we can use the existing method
(when-not cached-effective-dv-method
(i/cache-method! cache effective-dispatch-value method))
(i/cache-method! cache dispatch-value method)
method)))
(if-some [cached (.cached-method cache dispatch-value)]
cached
;; just like vanilla multimethods, we will add a new entry for every unique dispatch value we encounter, so
;; there's an implicit assumption that dispatch values are bounded
;;
;; build the effective method for dispatch value. We may end up throwing this out, but we currently need to build
;; it to determine the effective dispatch value.
(let [method (i/effective-method impl dispatch-value)
effective-dispatch-value (:dispatch-value (meta method))
;; If a method with the same effective dispatch value is already cached, add the existing method to the
;; cache for dispatch value. This way we don't end up with a bunch of duplicate methods impls for various
;; dispatch values that have the same effective dispatch value
cached-effective-dv-method (.cached-method cache effective-dispatch-value)
method (or cached-effective-dv-method method)]
;; Make sure the method was cached for the effective dispatch value as well, that way if some less-specific
;; dispatch value comes along with the same effective dispatch value we can use the existing method
(when-not cached-effective-dv-method
(i/cache-method! cache effective-dispatch-value method))
(i/cache-method! cache dispatch-value method)
method)))

clojure.protocols/Datafiable
(datafy [this]
Expand Down

0 comments on commit fefe427

Please sign in to comment.