LOG4J2-1349 benchmark
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/167b281e Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/167b281e Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/167b281e Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext Commit: 167b281e8c57cca996f5bd316e75747a34f72a3b Parents: eb0d5ed Author: rpopma <[email protected]> Authored: Sun Aug 21 20:10:20 2016 +0900 Committer: rpopma <[email protected]> Committed: Tue Aug 23 00:31:19 2016 +0900 ---------------------------------------------------------------------- .../log4j/perf/jmh/ThreadContextBenchmark.java | 165 +++++++++++++++++++ 1 file changed, 165 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/167b281e/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java ---------------------------------------------------------------------- diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java new file mode 100644 index 0000000..a8d15b8 --- /dev/null +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java @@ -0,0 +1,165 @@ +/* + * 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.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +import org.apache.logging.log4j.ThreadContext; +import org.apache.logging.log4j.ThreadContextBenchmarkAccess; +import org.apache.logging.log4j.core.config.Property; +import org.apache.logging.log4j.core.impl.ContextDataInjector; +import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory; +import org.apache.logging.log4j.spi.ArrayContextData; +import org.apache.logging.log4j.spi.CopyOnWriteOpenHashMapThreadContextMap; +import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap; +import org.apache.logging.log4j.spi.DefaultThreadContextMap; +import org.apache.logging.log4j.spi.GarbageFreeOpenHashMapThreadContextMap; +import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap; +import org.apache.logging.log4j.spi.MutableContextData; +import org.apache.logging.log4j.spi.OpenHashMapContextData; +import org.apache.logging.log4j.spi.ThreadContextMap; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +/** + * Compares performance of ThreadContextMap implementations. + */ +// ============================== HOW TO RUN THIS TEST: ==================================== +// (Quick build: mvn -DskipTests=true clean package -pl log4j-perf -am ) +// +// single thread: +// java -jar log4j-perf/target/benchmarks.jar ".*ThreadContextBench.*" +// +// four threads: +// java -jar log4j-perf/target/benchmarks.jar ".*ThreadContextBench.*" -f 1 -wi 10 -i 20 -tu ns -bm sample -t 4 +// +// Usage help: +// java -jar log4j-perf/target/benchmarks.jar -help +// +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +@State(Scope.Benchmark) +public class ThreadContextBenchmark { + private static final String DEFAULT_CONTEXT_MAP = "Default"; + private static final String COPY_OPENHASH_MAP = "CopyOpenHash"; + private static final String COPY_ARRAY_MAP = "CopySortedArray"; + private static final String NO_GC_OPENHASH_MAP = "NoGcOpenHash"; + private static final String NO_GC_ARRAY_MAP = "NoGcSortedArray"; + private static final Map<String, Class<? extends ThreadContextMap>> IMPLEMENTATIONS = new HashMap<>(); + static { + IMPLEMENTATIONS.put(DEFAULT_CONTEXT_MAP, DefaultThreadContextMap.class); + IMPLEMENTATIONS.put(COPY_OPENHASH_MAP, CopyOnWriteOpenHashMapThreadContextMap.class); + IMPLEMENTATIONS.put(COPY_ARRAY_MAP, CopyOnWriteSortedArrayThreadContextMap.class); + IMPLEMENTATIONS.put(NO_GC_OPENHASH_MAP, GarbageFreeOpenHashMapThreadContextMap.class); + IMPLEMENTATIONS.put(NO_GC_ARRAY_MAP, GarbageFreeSortedArrayThreadContextMap.class); + } + + @Param({ "Default", "CopyOpenHash", "CopySortedArray", "NoGcOpenHash", "NoGcSortedArray"}) + public String threadContextMapAlias; + + @Param({"5", "50", "500"}) + public int count; + + private final int KEY_LENGTH = 16; + private String[] keys; + private String[] values; + private List<Property> propertyList; + + private ContextDataInjector injector; + private MutableContextData reusableContextData; + + @Setup + public void setup() { + System.setProperty("log4j2.threadContextMap", IMPLEMENTATIONS.get(threadContextMapAlias).getName()); + ThreadContextBenchmarkAccess.init(); + + injector = ContextDataInjectorFactory.createInjector(); + System.out.println(threadContextMapAlias + ": Injector = " + injector); + + reusableContextData = threadContextMapAlias.contains("Array") + ? new ArrayContextData() + : new OpenHashMapContextData<>(); + + keys = new String[count]; + values = new String[count]; + Random r = new Random(); + for (int j = 0; j < keys.length; j++) { + char[] str = new char[KEY_LENGTH]; + for (int i = 0; i < str.length; i++) { + str[i] = (char) r.nextInt(); + } + keys[j] = new String(str); + values[j] = new String(str); + } + final int PROPERTIES_COUNT = 5; // count + propertyList = new ArrayList<>(PROPERTIES_COUNT); + for (int j = 0; j < PROPERTIES_COUNT; j++) { + char[] str = new char[KEY_LENGTH]; + for (int i = 0; i < str.length; i++) { + str[i] = (char) r.nextInt(); + } + propertyList.add(Property.createProperty(new String(str), new String(str))); + } + + clearAndPut(); // ensure ThreadContext contains values + } + + @TearDown + public void tearDown() { + System.clearProperty("log4j2.threadContextMap"); + ThreadContextBenchmarkAccess.init(); + } + + @Benchmark + public void clearAndPut() { + ThreadContext.clearMap(); + for (int i = 0; i < count; i++) { + ThreadContext.put(keys[i], values[i]); + } + } + + @Benchmark + public MutableContextData injectWithoutProperties() { + reusableContextData.clear(); + return injector.injectContextData(null, reusableContextData); + } + + @Benchmark + public MutableContextData injectWithProperties() { + reusableContextData.clear(); + return injector.injectContextData(propertyList, reusableContextData); + } +} \ No newline at end of file
