PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/test/clojure/core/matrix/calling_benchmark.clj

https://github.com/bmabey/core.matrix
Clojure | 124 lines | 53 code | 30 blank | 41 comment | 0 complexity | 877816a4f4fb9dceb49987a33d74f980 MD5 | raw file
  1. (ns core.matrix.calling-benchmark
  2. (:require [criterium.core :as c])
  3. (:import [core.matrix ClassPair]))
  4. ;; benchmark for a few different calling conventions
  5. (set! *unchecked-math* true)
  6. ;; (set! *warn-on-reflection* true)
  7. ;; an array to mutate: gives methods something to do with a side effect
  8. (def arr (long-array 1))
  9. ;; Java interface
  10. (definterface IInterface
  11. (interfaceCall [i])
  12. (interfaceCallPrim [^long i]))
  13. ;; Protocol
  14. (defprotocol POperation
  15. (proto-call [m i]))
  16. ;; Protocol for extending later
  17. (defprotocol PExtendedOperation
  18. (extended-call [m i]))
  19. ;; Clojure detype implementing POperation and IInterface
  20. (deftype MyType []
  21. POperation
  22. (proto-call [m i]
  23. (aset ^longs arr 0 (long i)))
  24. IInterface
  25. (interfaceCall [m i]
  26. (aset ^longs arr 0 (long i)))
  27. (interfaceCallPrim [m ^long i]
  28. (aset ^longs arr 0 i)))
  29. ;; extend PExtendedOperation to MyType *after* it is defined
  30. ;; so we can determine extra overhead of extending
  31. (extend-protocol PExtendedOperation
  32. MyType
  33. (extended-call [m i]
  34. (aset ^longs arr 0 (long i))))
  35. ;; an instance of MyType
  36. (def ^MyType my-type (MyType.))
  37. (defn prim-call [^long x]
  38. (aset ^longs arr 0 x) nil)
  39. (defn boxed-call [^Long x]
  40. (aset ^longs arr 0 (long x)) nil)
  41. (defmulti class-multimethod (fn [m i] (class m)))
  42. (defmethod class-multimethod MyType [m i] (aset ^longs arr 0 (long i)))
  43. (defmethod class-multimethod :default [m i] (throw (IllegalArgumentException.)))
  44. (defmulti double-multimethod (fn [m i] [(class m) (class i)]))
  45. (defmethod double-multimethod [MyType Long] [m i] (aset ^longs arr 0 (long i)))
  46. (defmethod double-multimethod :default [m i] (throw (IllegalArgumentException.)))
  47. ;; Experiment using a fast dedicated java implementation for the vector of two
  48. ;; classes with an optimised hashCode etc. This speeds up multimethod
  49. ;; dispatch by over 2x for me.
  50. ;; For completeness, we'd also want ClassPair to implement
  51. ;; IPersistentVector so this works with clojure.core/isa?
  52. (defmulti fast-double-multimethod (fn [m i] (ClassPair/fromObjects m i)))
  53. (defmethod fast-double-multimethod (ClassPair. MyType Long) [m i] (aset ^longs arr 0 (long i)))
  54. (defmethod fast-double-multimethod :default [m i] (throw (IllegalArgumentException.)))
  55. ;; =============================================================
  56. ;; Benchmark code follows
  57. (defn all-benchmarks []
  58. (c/quick-bench (dotimes [i 1000] (aset ^longs arr 0 i)))
  59. ;; 1.23 us
  60. ;; extremely fast!
  61. (c/quick-bench (dotimes [i 1000] (prim-call i)))
  62. ;; 1.84 us
  63. ;; very fast!
  64. (c/quick-bench (dotimes [i 1000] (boxed-call i)))
  65. ;; 7.95 us
  66. ;; fast - boxing adds moderate overhead
  67. (c/quick-bench (dotimes [i 1000] (aset arr 0 i)))
  68. ;; 9002.24 us
  69. ;; reflection is very expensive - dwarfs method calling and boxing costs
  70. (c/quick-bench (dotimes [i 1000] (proto-call my-type i)))
  71. ;; 7.95 us
  72. ;; fast - similar to regular boxed method call
  73. (c/quick-bench (dotimes [i 1000] (extended-call my-type i)))
  74. ;; 13.81 us
  75. ;; quite fast - more expensive than regular protocol call
  76. (c/quick-bench (dotimes [i 1000] (.interfaceCall ^IInterface my-type i)))
  77. ;; 6.93 us
  78. ;; fast
  79. (c/quick-bench (dotimes [i 1000] (.interfaceCallPrim ^IInterface my-type i)))
  80. ;; 1.89 us
  81. ;; very fast!
  82. (c/quick-bench (dotimes [i 1000] (.interfaceCallPrim ^MyType my-type i)))
  83. ;; 1.86 us
  84. ;; very fast!
  85. (c/quick-bench (dotimes [i 1000] (class-multimethod my-type i)))
  86. ;; 88.98 us
  87. ;; slower
  88. (c/quick-bench (dotimes [i 1000] (double-multimethod my-type i)))
  89. ;; 231.00 us
  90. ;; much slower! still better than reflection though....
  91. (c/quick-bench (dotimes [i 1000] (fast-double-multimethod my-type i)))
  92. ;; This is over 2x faster than the above for me (138us vs 320us on a
  93. ;; different machine)
  94. )