Skip to content

Overhead

Justin Conklin edited this page Aug 24, 2021 · 7 revisions

Since jmh-clojure can also run externally defined (normally in Java) benchmarks, let's compare two simple benchmarks for our baseline to measure overhead.

package demo;

import java.util.concurrent.ThreadLocalRandom;
import org.openjdk.jmh.annotations.*;

public class Native {
    @Benchmark
    public Object addBoxed (LongState a, LongState b) {
        return a.boxedValue + b.boxedValue;
    }

    @Benchmark
    public long addPrim (LongState a, LongState b) {
        return a.primValue + b.primValue;
    }

    @State(Scope.Thread)
    public static class LongState {
        public Long boxedValue; // non-final on purpose
        public long primValue;

        public LongState () {
            boxedValue = primValue = ThreadLocalRandom.current().nextLong(Integer.MAX_VALUE);
        }
    }
}
(ns demo.core)

(defn add-boxed [a b]
  (+ a b))

(defn add-prim ^long [^long a ^long b]
  (unchecked-add a b))

(defn random-long []
  (rand Integer/MAX_VALUE))

We'll use the lein-jmh plugin to run our benchmarks. Here is the jmh.edn file:

{:benchmarks [{:fn demo.core/add-boxed, :args [:long, :long]}
              {:fn demo.core/add-prim, :args [:long, :long]}]

 :states {:long {:fn demo.core/random-long, :scope :thread}}}

Now execute the following command:

lein jmh '{:externs [demo.Native], :only [:fn :method :score], :type :quick}'
# => ({:fn demo.core/add-boxed,      :score [1.76108890554332E8 "ops/s"]}
#     {:fn demo.core/add-prim,       :score [3.96770743953259E8 "ops/s"]}
#     {:method demo.Native/addBoxed, :score [1.83169450586705E8 "ops/s"]}
#     {:method demo.Native/addPrim,  :score [3.97466361792193E8 "ops/s"]})

We can see that the overhead introduced by this library is virtually non-existant. The boxed versions are there just to prove that Hotspot is not doing some clever optimization tricks to our code that would influence results.

Note that the Java state fields are non-final. For more on why this is, see here.

For more, please see "How It Works".

The complete code for this example can be found here.

Clone this wiki locally