I was just checking to see how much overhead I might pay using apply rather 
than destructuring a collection of args so I could call a function directly 
on them, when I found something I thought interesting:

TLDR:

- apply is really slow - 2 orders of magnitude slower than a direct call
- apply on an array, which I thought would be a direct way to the java 
varargs api is really slow
- destructuring a list is two orders of magnitude slower than a vector
- it is an order of magnitude faster to destructure a vector and may a 
direct call, than to use apply
- etc

openjdk full version "21.0.4+7"
clojure 1.12.0
AMD Ryzen 9 5950X 16-Core Processor

If I've made any silly mistakes, please point them out and I'll run these 
benchmarks again.

If I am correct then there should be a lot of room to speed up apply and 
destructuring of lists ?

Interested in peoples thoughts...


Jules


m3.repl> ;; let's have function that takes 4 args
m3.repl> (defn foo [a b c d])
#'m3.repl/foo
m3.repl> ;; let's try some direct calls
m3.repl> (time (dotimes [_ 100000000] (foo 1 2 3 4)))
"Elapsed time: 65.149019 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (foo 1 2 3 4)))
"Elapsed time: 49.920188 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (foo 1 2 3 4)))
"Elapsed time: 48.02132 msecs"
nil
m3.repl> ;; now lets try with a variety of collections via apply
m3.repl> (def vargs [1 2 3 4])
#'m3.repl/vargs
m3.repl> (def largs (list 1 2 3 4))
#'m3.repl/largs
m3.repl> (def aargs (into-array Object [1 2 3 4]))
#'m3.repl/aargs
m3.repl> ;; a vector
m3.repl> (time (dotimes [_ 100000000] (apply foo vargs)))
"Elapsed time: 7166.218804 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (apply foo vargs)))
"Elapsed time: 7167.766347 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (apply foo vargs)))
"Elapsed time: 7154.58141 msecs"
nil
m3.repl> ;; a list
m3.repl> (time (dotimes [_ 100000000] (apply foo largs)))
"Elapsed time: 5657.564262 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (apply foo largs)))
"Elapsed time: 5597.083287 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (apply foo largs)))
"Elapsed time: 5638.361902 msecs"
nil
m3.repl> ;; and an array
m3.repl> (time (dotimes [_ 100000000] (apply foo aargs)))
"Elapsed time: 7954.757485 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (apply foo aargs)))
"Elapsed time: 8125.750746 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (apply foo aargs)))
"Elapsed time: 8151.5701 msecs"
nil
m3.repl> ;; is it faster to destructure first ?
m3.repl> ;; a vector
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] vargs] (foo a b c 
d))))
"Elapsed time: 904.68628 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] vargs] (foo a b c 
d))))
"Elapsed time: 902.818246 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] vargs] (foo a b c 
d))))
"Elapsed time: 905.498641 msecs"
nil
m3.repl> ;; a list
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] largs] (foo a b c 
d))))
"Elapsed time: 30043.489179 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] largs] (foo a b c 
d))))
"Elapsed time: 30159.705918 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] largs] (foo a b c 
d))))
"Elapsed time: 30289.946966 msecs"
nil
m3.repl> ;; an array
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] aargs] (foo a b c 
d))))
"Elapsed time: 14231.86232 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] aargs] (foo a b c 
d))))
"Elapsed time: 14081.057031 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d] aargs] (foo a b c 
d))))
"Elapsed time: 14924.808985 msecs"
nil
m3.repl> ;; hmm... maybe destructuring the vector is taking a shortcut and 
not building a new collection whereas the others are
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d e] vargs] (foo a b c 
d))))
"Elapsed time: 1158.761312 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d e] vargs] (foo a b c 
d))))
"Elapsed time: 570.542383 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d e] vargs] (foo a b c 
d))))
"Elapsed time: 588.179669 msecs"
nil
m3.repl> (time (dotimes [_ 100000000] (let [[a b c d e] vargs] (foo a b c 
d))))
"Elapsed time: 589.489251 msecs"
nil
m3.repl> 

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/d0e9472f-ca7d-4106-acc1-14082dd00aa5n%40googlegroups.com.

Reply via email to