/* * Copyright 2012-2016 Institut National des Sciences Appliquées de Lyon (INSA-Lyon) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gololang.microbenchmarks.arithmetic; import clojure.lang.Var; import org.gololang.microbenchmarks.support.CodeLoader; import org.gololang.microbenchmarks.support.JRubyContainerAndReceiver; import org.openjdk.jmh.annotations.*; import org.python.core.PyFunction; import org.python.core.PyLong; import org.python.util.PythonInterpreter; import javax.script.Invocable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.Random; import java.util.concurrent.TimeUnit; import static java.lang.invoke.MethodType.genericMethodType; import static java.lang.invoke.MethodType.methodType; @BenchmarkMode(Mode.SingleShotTime) @Warmup(batchSize = EuclidianGcdMicroBenchmark.DataSpace.N, iterations = 20) @Measurement(batchSize = EuclidianGcdMicroBenchmark.DataSpace.N, iterations = 5) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class EuclidianGcdMicroBenchmark { public static long gcd(final long x, final long y) { long a = x; long b = y; while (a != b) { if (a > b) { a = a - b; } else { b = b - a; } } return a; } @State(Scope.Thread) static public class JavaState { MethodHandle gcdHandle; @Setup(Level.Trial) public void setup() { try { gcdHandle = MethodHandles.lookup().findStatic(EuclidianGcdMicroBenchmark.class, "gcd", methodType(long.class, long.class, long.class)); gcdHandle = gcdHandle.asType(genericMethodType(2)); } catch (NoSuchMethodException | IllegalAccessException e) { throw new AssertionError(e); } } } @State(Scope.Thread) static public class GoloState { MethodHandle gcdHandle; @Setup(Level.Trial) public void setup() { gcdHandle = new CodeLoader().golo("arithmetic", "gcd", 2); } } @State(Scope.Thread) static public class GroovyState { MethodHandle gcdHandle; MethodHandle fast_gcdHandle; MethodHandle fastest_gcdHandle; @Setup(Level.Trial) public void setup() { gcdHandle = new CodeLoader().groovy("arithmetic", "gcd", genericMethodType(2)); fast_gcdHandle = new CodeLoader().groovy("arithmetic", "fast_gcd", methodType(long.class, long.class, long.class)); fastest_gcdHandle = new CodeLoader().groovy("arithmetic", "fastest_gcd", methodType(long.class, long.class, long.class)); } } @State(Scope.Thread) static public class GroovyIndyState { MethodHandle gcdHandle; MethodHandle fast_gcdHandle; MethodHandle fastest_gcdHandle; @Setup(Level.Trial) public void setup() { gcdHandle = new CodeLoader().groovy_indy("arithmetic", "gcd", genericMethodType(2)); fast_gcdHandle = new CodeLoader().groovy_indy("arithmetic", "fast_gcd", methodType(long.class, long.class, long.class)); fastest_gcdHandle = new CodeLoader().groovy_indy("arithmetic", "fastest_gcd", methodType(long.class, long.class, long.class)); } } @State(Scope.Thread) static public class JRubyState { JRubyContainerAndReceiver containerAndReceiver; @Setup(Level.Trial) public void setup() { containerAndReceiver = new CodeLoader().jruby("arithmetic"); } } @State(Scope.Thread) static public class ClojureState { Var gcd; Var gcd_fast; @Setup(Level.Trial) public void prepare() { gcd = new CodeLoader().clojure("arithmetic", "arithmetic", "gcd"); gcd_fast = new CodeLoader().clojure("arithmetic", "arithmetic", "fast-gcd"); } } @State(Scope.Thread) static public class NashornState { Invocable invocable; @Setup(Level.Trial) public void prepare() { invocable = (Invocable) new CodeLoader().nashorn("arithmetic"); } } @State(Scope.Thread) static public class DataSpace { public final static int N = 100_000; long[] x; long[] y; private int pos = 0; public int nextIndex() { int i = pos; pos = (pos + 1) % N; return i; } @Setup(Level.Trial) public void setup() { Random rand = new Random(999_666L); x = new long[N]; y = new long[N]; for (int i = 0; i < N; i++) { x[i] = (long) Math.abs(rand.nextInt()); y[i] = (long) Math.abs(rand.nextInt()); } } } @State(Scope.Thread) static public class PythonState { PyLong[] x; PyLong[] y; PyFunction gcd; private int pos = 0; public int nextIndex() { int i = pos; pos = (pos + 1) % DataSpace.N; return i; } @Setup(Level.Trial) public void prepare() { CodeLoader loader = new CodeLoader(); PythonInterpreter interpreter = loader.jython("arithmetic"); gcd = (PyFunction) interpreter.get("gcd"); Random rand = new Random(999_666L); x = new PyLong[DataSpace.N]; y = new PyLong[DataSpace.N]; for (int i = 0; i < DataSpace.N; i++) { x[i] = new PyLong(Math.abs(rand.nextInt())); y[i] = new PyLong(Math.abs(rand.nextInt())); } } } @Benchmark public Object baseline_java_mh(DataSpace dataSpace, JavaState javaState) throws Throwable { int index = dataSpace.nextIndex(); return javaState.gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object golo(DataSpace dataSpace, GoloState goloState) throws Throwable { int index = dataSpace.nextIndex(); return goloState.gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object groovy(DataSpace dataSpace, GroovyState groovyState) throws Throwable { int index = dataSpace.nextIndex(); return groovyState.gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object groovy_indy(DataSpace dataSpace, GroovyIndyState groovyState) throws Throwable { int index = dataSpace.nextIndex(); return groovyState.gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object groovy_fast(DataSpace dataSpace, GroovyState groovyState) throws Throwable { int index = dataSpace.nextIndex(); return groovyState.fast_gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object groovy_indy_fast(DataSpace dataSpace, GroovyIndyState groovyState) throws Throwable { int index = dataSpace.nextIndex(); return groovyState.fast_gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object groovy_fastest(DataSpace dataSpace, GroovyState groovyState) throws Throwable { int index = dataSpace.nextIndex(); return groovyState.fastest_gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object groovy_indy_fastest(DataSpace dataSpace, GroovyIndyState groovyState) throws Throwable { int index = dataSpace.nextIndex(); return groovyState.fastest_gcdHandle.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object jruby(DataSpace dataSpace, JRubyState jRubyState) { int index = dataSpace.nextIndex(); return jRubyState.containerAndReceiver.container() .callMethod(jRubyState.containerAndReceiver.receiver(), "gcd", dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object clojure(DataSpace dataSpace, ClojureState clojureState) { int index = dataSpace.nextIndex(); return clojureState.gcd.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object clojure_fast(DataSpace dataSpace, ClojureState clojureState) { int index = dataSpace.nextIndex(); return clojureState.gcd_fast.invoke(dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object nashorn(DataSpace dataSpace, NashornState nashornState) throws Throwable { int index = dataSpace.nextIndex(); return nashornState.invocable.invokeFunction("gcd", dataSpace.x[index], dataSpace.y[index]); } @Benchmark public Object jython(PythonState pythonState) throws Throwable { int index = pythonState.nextIndex(); return pythonState.gcd.__call__(pythonState.x[index], pythonState.y[index]); } }