/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.logging.log4j.perf.jmh; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Random; import org.apache.logging.log4j.message.Message; import org.apache.logging.log4j.message.StringFormattedMessage; import org.apache.logging.log4j.util.StackLocatorUtil; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; /** * <p> * Benchmarks the different ways the caller class can be obtained. To run this in sampling mode (latency test): * </p> * * <pre> * java -jar benchmarks.jar ".*ReflectionBenchmark.*" -i 5 -f 1 -wi 5 -bm sample -tu ns * </pre> * <p> * To run this in throughput testing mode: * </p> * * <pre> * java -jar benchmarks.jar ".*ReflectionBenchmark.*" -i 5 -f 1 -wi 5 -bm Throughput -tu ms * </pre> */ public class ReflectionBenchmark { @State(Scope.Thread) public static class RandomInteger { private final Random r = new Random(); int random; @Setup(Level.Iteration) public void setup() { random = r.nextInt(); } } @State(Scope.Benchmark) public static class ClassContextManager extends SecurityManager { @Override protected Class[] getClassContext() { return super.getClassContext(); } } @Benchmark public void baseline() { } @Benchmark public String test01_getCallerClassNameFromStackTrace() { return new Throwable().getStackTrace()[3].getClassName(); } @Benchmark public String test02_getCallerClassNameFromThreadStackTrace() { return Thread.currentThread().getStackTrace()[3].getClassName(); } @Benchmark public String test03_getCallerClassNameReflectively() { return StackLocatorUtil.getCallerClass(3).getName(); } @Benchmark public Class<?> test05_getStackTraceClassForClassName() throws ClassNotFoundException { return Class.forName(new Throwable().getStackTrace()[3].getClassName()); } @Benchmark public Class<?> test06_getThreadStackTraceClassForClassName() throws ClassNotFoundException { return Class.forName(Thread.currentThread().getStackTrace()[3].getClassName()); } @Benchmark public Class<?> test07_getReflectiveCallerClassUtility() { return StackLocatorUtil.getCallerClass(3); } @Benchmark public Message test09_getMessageUsingNew(final RandomInteger rng) { return new StringFormattedMessage("Hello %i", rng.random); } @Benchmark public Message test10_getMessageUsingReflection(final RandomInteger rng) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { final Constructor<? extends Message> constructor = StringFormattedMessage.class.getConstructor(String.class, Object[].class); return constructor.newInstance("Hello %i", new Object[] { rng.random }); } @Benchmark public Class<?>[] test11_getClassContextViaCallerClass() { // let's not benchmark LinkedList or anything here final Class<?>[] classes = new Class<?>[100]; Class<?> clazz; for (int i = 0; null != (clazz = StackLocatorUtil.getCallerClass(i)); i++) { classes[i] = clazz; } return classes; } @Benchmark public Class<?>[] test12_getClassContextViaSecurityManager(final ClassContextManager classContextManager) { return classContextManager.getClassContext(); } @Benchmark public Class<?> reflectionUtilGetClass() { return new ClassLocator().findClass(4); } @Benchmark public String locationLocatorGetMethod() { return new MethodLocator().findMethodName(4); } private static class ClassLocator { private Class<?> findClass(int depth) { if (depth == 1) { return locateCaller(); } else { return findClass(depth - 1); } } private Class<?> locateCaller() { return StackLocatorUtil.getCallerClass(ClassLocator.class.getName()); } } private static class MethodLocator { private String findMethodName(int depth) { if (depth == 1) { return locateMethodName(); } else { return findMethodName(depth - 1); } } private String locateMethodName() { return StackLocatorUtil.calcLocation(MethodLocator.class.getName()).getMethodName(); } } }