Skip to content

Instantly share code, notes, and snippets.

Created March 14, 2017 15:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/8777ffbfd3a39c1a3f61eb4d64711c8f to your computer and use it in GitHub Desktop.
Save anonymous/8777ffbfd3a39c1a3f61eb4d64711c8f to your computer and use it in GitHub Desktop.
Benchmark getting caller's class on Java 8
package benchmark.throwing;
import sun.reflect.Reflection;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import benchmarker.main.Bench;
@State(Scope.Thread)
@Fork(1)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
public class GetCallerClass {
interface StackTrace1 {
static Class<?> impl() {
Class<?> clazz = null;
for(StackTraceElement element : new Throwable().fillInStackTrace().getStackTrace())
try {
if(clazz == null & (clazz = Class.forName(element.getClassName())) != StackTrace1.class)
clazz = null;
else if(clazz != StackTrace1.class) break;
} catch(ClassNotFoundException e) {
throw new AssertionError(e);
}
return clazz;
}
}
interface StackTrace2 {
static Class<?> impl() {
Class<?> clazz = null;
for(StackTraceElement element : new Throwable().getStackTrace())
try {
if(clazz == null & (clazz = Class.forName(element.getClassName())) != StackTrace2.class)
clazz = null;
else if(clazz != StackTrace2.class) break;
} catch(ClassNotFoundException e) {
throw new AssertionError(e);
}
return clazz;
}
}
interface StackTrace3 {
public final static class MyThrowable extends Throwable {
public static final MyThrowable INSTANCE = new MyThrowable();
MyThrowable() {
super("", null, false, true);
}
public final synchronized @Override Throwable fillInStackTrace() {
return getMessage() == "" ? super.fillInStackTrace() : this;
}
}
static Class<?> impl() {
StackTraceElement[] trace;
synchronized(MyThrowable.INSTANCE) {
trace = MyThrowable.INSTANCE.fillInStackTrace().getStackTrace();
}
Class<?> clazz = null;
for(StackTraceElement element : trace)
try {
if(clazz == null & (clazz = Class.forName(element.getClassName())) != StackTrace3.class)
clazz = null;
else if(clazz != StackTrace3.class) break;
} catch(ClassNotFoundException e) {
throw new AssertionError(e);
}
return clazz;
}
}
interface StackTrace4 {
static Throwable IT = new Throwable();
static Class<?> impl() {
StackTraceElement[] trace;
synchronized(IT) {
trace = IT.fillInStackTrace().getStackTrace();
}
Class<?> clazz = null;
for(StackTraceElement element : trace)
try {
if(clazz == null & (clazz = Class.forName(element.getClassName())) != StackTrace4.class)
clazz = null;
else if(clazz != StackTrace4.class) break;
} catch(ClassNotFoundException e) {
throw new AssertionError(e);
}
return clazz;
}
}
interface Security {
static Class<?> impl() {
return MySecurityManager.INSTANCE.pleaseGetClassContext()[2];
}
public static class MySecurityManager extends SecurityManager {
public static final MySecurityManager INSTANCE = new MySecurityManager();
public Class<?>[] pleaseGetClassContext() {
return getClassContext();
}
}
}
interface MethodInvoke {
static final Method getStackTraceElement = method();
static final Throwable obj = new Throwable();
static Method method() {
try {
Method method = Throwable.class.getDeclaredMethod("getStackTraceElement", Integer.TYPE);
method.setAccessible(true);
return method;
} catch(RuntimeException | NoSuchMethodException e) {
throw new AssertionError(e);
}
}
static Class<?> impl() {
try {
StackTraceElement element = (StackTraceElement) getStackTraceElement.invoke(obj, 2);
String className = element.getClassName();
Class<?> forName = Class.forName(className);
return forName;
} catch(RuntimeException | ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
}
}
public interface HandleInvoke {
public StackTraceElement apply(Throwable t, int index);
static final HandleInvoke getStackTraceElement = method();
static final Throwable obj = new Throwable();
static HandleInvoke method() {
try {
Method method = Throwable.class.getDeclaredMethod("getStackTraceElement", Integer.TYPE);
method.setAccessible(true);
Class<HandleInvoke> intfc = HandleInvoke.class;
Lookup lookup = MethodHandles.lookup();
MethodHandle bindTo = lookup.unreflect(method);
HandleInvoke as = MethodHandleProxies.asInterfaceInstance(intfc, bindTo);
return as;
} catch(RuntimeException | IllegalAccessException | NoSuchMethodException e) {
throw new AssertionError(e);
}
}
static Class<?> impl() {
try {
StackTraceElement apply = getStackTraceElement.apply(obj,2);
String className = apply.getClassName();
return Class.forName(className);
} catch(ClassNotFoundException e) {
throw new AssertionError(e);
}
}
}
public interface ReflectionGet {
static @SuppressWarnings("deprecation") Class<?> impl() {
return Reflection.getCallerClass(2);
}
}
private int order;
private Random random;
public @Setup(Level.Iteration) void setup() {random = new Random(4321);}
private static final Supplier<Class<?>> exception1 = new Supplier<Class<?>>() {public @Override Class<?> get() {return StackTrace1 .impl();}};
private static final Supplier<Class<?>> exception2 = new Supplier<Class<?>>() {public @Override Class<?> get() {return StackTrace2 .impl();}};
private static final Supplier<Class<?>> exception3 = new Supplier<Class<?>>() {public @Override Class<?> get() {return StackTrace3 .impl();}};
private static final Supplier<Class<?>> exception4 = new Supplier<Class<?>>() {public @Override Class<?> get() {return StackTrace4 .impl();}};
private static final Supplier<Class<?>> baseline = new Supplier<Class<?>>() {public @Override Class<?> get() {return getClass ();}};
private static final Supplier<Class<?>> security = new Supplier<Class<?>>() {public @Override Class<?> get() {return Security .impl();}};
private static final Supplier<Class<?>> invokeMethod = new Supplier<Class<?>>() {public @Override Class<?> get() {return MethodInvoke .impl();}};
private static final Supplier<Class<?>> invokeHandle = new Supplier<Class<?>>() {public @Override Class<?> get() {return HandleInvoke .impl();}};
private static final Supplier<Class<?>> reflection = new Supplier<Class<?>>() {public @Override Class<?> get() {return ReflectionGet.impl();}};
public @Benchmark Class<?> baseline () {return stacksGo(baseline );}
public @Benchmark Class<?> custom_SecurityManager_getClassContext () {return stacksGo(security );}
public @Benchmark Class<?> exception_Throwable_getStackTrace_v1 () {return stacksGo(exception1 );}
public @Benchmark Class<?> exception_Throwable_getStackTrace_v2 () {return stacksGo(exception2 );}
public @Benchmark Class<?> exception_Throwable_getStackTrace_v3 () {return stacksGo(exception3 );}
public @Benchmark Class<?> exception_Throwable_getStackTrace_v4 () {return stacksGo(exception4 );}
public @Benchmark Class<?> invokeMethod_Throwable_getStackTraceElement() {return stacksGo(invokeMethod);}
public @Benchmark Class<?> invokeHandle_Throwable_getStackTraceElement() {return stacksGo(invokeHandle);}
public @Benchmark Class<?> static_Reflection_getCallerClass () {return stacksGo(reflection );}
private Class<?> stacksGo(Supplier<Class<?>> s) {order=random.nextInt()|1; return stackBeg(0, s);}
private Class<?> stackBeg(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stack_03(num+1, s): stack_47(num+1, s);}
private Class<?> stack_03(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stack_01(num+1, s): stack_23(num+1, s);}
private Class<?> stack_47(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stack_45(num+1, s): stack_67(num+1, s);}
private Class<?> stack_01(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stackAt0(num+1, s): stackAt1(num+1, s);}
private Class<?> stack_23(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stackAt2(num+1, s): stackAt3(num+1, s);}
private Class<?> stack_45(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stackAt4(num+1, s): stackAt5(num+1, s);}
private Class<?> stack_67(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) >> 31 == 0 ? stackAt6(num+1, s): stackAt7(num+1, s);}
private Class<?> stackAt0(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt1(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt2(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt3(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt4(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt5(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt6(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackAt7(int num, Supplier<Class<?>> s) {return stackEnd(num, s);}
private Class<?> stackEnd(int num, Supplier<Class<?>> s) {return order << num/2 << (num-num/2) == 0 ? s.get(): stackBeg(num+1, s);}
// Benchmark Mode Cnt Score Error Units
// GetCallerClass.baseline avgt 5 181.628 ± 1.945 ns/op
// GetCallerClass.custom_SecurityManager_getClassContext avgt 5 3338.956 ± 29.751 ns/op
// GetCallerClass.exception_Throwable_getStackTrace_v1 avgt 5 52768.248 ± 928.263 ns/op
// GetCallerClass.exception_Throwable_getStackTrace_v2 avgt 5 49930.420 ± 774.868 ns/op
// GetCallerClass.exception_Throwable_getStackTrace_v3 avgt 5 49911.325 ± 566.927 ns/op
// GetCallerClass.exception_Throwable_getStackTrace_v4 avgt 5 49530.699 ± 773.626 ns/op
// GetCallerClass.invokeHandle_Throwable_getStackTraceElement avgt 5 1738.658 ± 21.474 ns/op
// GetCallerClass.invokeMethod_Throwable_getStackTraceElement avgt 5 1633.620 ± 33.011 ns/op
// GetCallerClass.static_Reflection_getCallerClass avgt 5 313.214 ± 5.901 ns/op
public static void main(String[] args) {
GetCallerClass o = new GetCallerClass();
o.setup();
System.out.println(o.exception_Throwable_getStackTrace_v1());
System.out.println(o.exception_Throwable_getStackTrace_v2());
System.out.println(o.exception_Throwable_getStackTrace_v3());
System.out.println(o.exception_Throwable_getStackTrace_v4());
System.out.println(o.baseline());
System.out.println(o.custom_SecurityManager_getClassContext());
System.out.println(o.invokeMethod_Throwable_getStackTraceElement());
System.out.println(o.invokeHandle_Throwable_getStackTraceElement());
System.out.println(o.static_Reflection_getCallerClass());
Bench.me().run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment