_Comment made by: michalmarczyk_
This patch (0001-CLJ-1372-consistent-hasheq-for-java.util.-List-Map-M.patch) makes hasheq consistent with = for java.util.{List,Map,Map.Entry,Set}. Additionally it extends the special treatment of String (return hasheq of hashCode) to all types not otherwise handled (see below for a comment on this).
It is also available here:
https://github.com/michalmarczyk/clojure/tree/alien-hasheq-2
An earlier version is available here:
https://github.com/michalmarczyk/clojure/tree/alien-hasheq
If I understand correctly, what needs to be benchmarked is primarily the "dispatch time" for clojure.lang.Util/hasheq given a Clojure type. So, I ran a Criterium benchmark repeatedly hashing the same persistent hash map, on the theory that this will measure just the dispatch time on IHashEq instances. I then ran a separate benchmark hashing a PHM, a string and a long and adding up the results with unchecked-add. Hopefully this is a good start; I've no doubt additional benchmarks would be useful.
The results are somewhat surprising to me: hasheq on PHM is actually slightly faster in this benchmark on my build than on 1.6.0; the "add three hasheqs" benchmark is slightly faster on 1.6.0.
;;; 1.6.0
;;; NB. j.u.HM benchmark irrelevant
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (clojure.lang.Util/hasheq phm)) (c/bench (clojure.lang.Util/hasheq juhm)))
WARNING: Final GC required 1.24405836928592 % of runtime
Evaluation count : 5549560980 in 60 samples of 92492683 calls.
Execution time mean : 9.229881 ns
Execution time std-deviation : 0.156716 ns
Execution time lower quantile : 8.985994 ns ( 2.5%)
Execution time upper quantile : 9.574039 ns (97.5%)
Overhead used : 1.741068 ns
Found 2 outliers in 60 samples (3.3333 %)
low-severe 2 (3.3333 %)
Variance from outliers : 6.2652 % Variance is slightly inflated by outliers
Evaluation count : 35647680 in 60 samples of 594128 calls.
Execution time mean : 1.695145 µs
Execution time std-deviation : 20.186554 ns
Execution time lower quantile : 1.670049 µs ( 2.5%)
Execution time upper quantile : 1.740329 µs (97.5%)
Overhead used : 1.741068 ns
Found 2 outliers in 60 samples (3.3333 %)
low-severe 2 (3.3333 %)
Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
nil
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
WARNING: Final GC required 1.028614538339401 % of runtime
Evaluation count : 1029948300 in 60 samples of 17165805 calls.
Execution time mean : 56.797488 ns
Execution time std-deviation : 0.732221 ns
Execution time lower quantile : 55.856731 ns ( 2.5%)
Execution time upper quantile : 58.469940 ns (97.5%)
Overhead used : 1.836671 ns
Found 1 outliers in 60 samples (1.6667 %)
low-severe 1 (1.6667 %)
Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
nil
;;; patch applied
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] (assert (= (hash phm) (hash juhm))) (c/bench (clojure.lang.Util/hasheq phm)) (c/bench (clojure.lang.Util/hasheq juhm)))
Evaluation count : 5537698680 in 60 samples of 92294978 calls.
Execution time mean : 8.973200 ns
Execution time std-deviation : 0.157079 ns
Execution time lower quantile : 8.733544 ns ( 2.5%)
Execution time upper quantile : 9.289350 ns (97.5%)
Overhead used : 1.744772 ns
Evaluation count : 2481600 in 60 samples of 41360 calls.
Execution time mean : 24.287800 µs
Execution time std-deviation : 288.124326 ns
Execution time lower quantile : 23.856445 µs ( 2.5%)
Execution time upper quantile : 24.774097 µs (97.5%)
Overhead used : 1.744772 ns
nil
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
WARNING: Final GC required 1.298136122909759 % of runtime
Evaluation count : 954751500 in 60 samples of 15912525 calls.
Execution time mean : 61.681794 ns
Execution time std-deviation : 0.712110 ns
Execution time lower quantile : 60.622003 ns ( 2.5%)
Execution time upper quantile : 62.904801 ns (97.5%)
Overhead used : 1.744772 ns
Found 1 outliers in 60 samples (1.6667 %)
low-severe 1 (1.6667 %)
Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
nil
As a side note, the earlier version of the patch available on the other branch doesn't have a separate branch for String. This made hasheq faster for objects implementing IHashEq, but slowed down the "three hashes" benchmark roughly by a factor of 2.