1

I go through the "Clojure programming" book by Chas Emerick, Brian Carper and Christophe Grand.

At the part about memoization, I noticed significantly decreased time elapsed for the second (and other) calls of function without even using memoization.

Sure, using memoization decreased time by order of magnitude, but I'm interested, if Clojure perform something like memoization internally.

Here is the code:

(defn prime? 
  [n]
  (cond
    (== 1 n) false
    (== 2 n) true
    (even? n) false
    :else (->> (range 3 (inc (Math/sqrt n)) 2)
               (filter #(zero? (rem n %)))
               empty?)))


(def n 123)

(time (prime? n))
(time (prime? n))

(let [m-prime? (memoize prime?)]
  (time (m-prime? n))
  (time (m-prime? n)))

And the output:

"Elapsed time: 0.235977 msecs"
"Elapsed time: 0.054549 msecs"
"Elapsed time: 0.045127 msecs"
"Elapsed time: 0.003814 msecs"

So, why the second call is almost 5 times faster, than the first one?

2
  • 3
    I think you missed JIT. I think that first performance increasing is JIT's work. Commented Dec 3, 2015 at 22:00
  • OK, maybe, someone can suggest good intro reading about how Clojure compiles to Java bytecode? Commented Dec 4, 2015 at 10:56

2 Answers 2

2

Internaly each clojure functions are represented by jvm classes - first call is longer because classloader have to load class.

as previous answer says - it's not JIT for sure, as JIT for most optimisation has a certain threshold - can be changed using XX:CompileThreshold - default value is set to 10000 - this is one of the reasons why jvm has to be warm up before benchmarking.

keep in mind that memoization is just cache. And the function have to be "pure" to work it correctly - it'd extremely hard for compiler to guess which function can be potentially automatically memoized.

Sign up to request clarification or add additional context in comments.

1 Comment

The class is loaded when the function is read, not the first time it's called. Run your repl with the -verbose:class option and you can see that.
2

The first time you call any Clojure function it's slower. I think Clojure delays some internal linkage or setup until a function is called.

It might be JIT, but I don't think so. That would kick in when the function is defined.

Memoization is not a panacea. If what you're calling is not really really slow, then it can actually be slower than just executing the original code. For example, I when I wrote the tournament pairing algorithm , I experimented with memoization on a function that was called repeatedly and always returned the same result, and it slowed the matching algorithm down significantly. It was 2-3 times as slow with memoization than without.

1 Comment

Yah, I have once profiled an inappropriate memoization, it took a lot of time vectorizing, hashing, and cache searching the arg-list that even exceeds a bare computation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.