ARTEMIS-2996 Provide JMH Benchmarks for Artemis

This commit is contained in:
franz1981 2020-11-14 17:12:38 +01:00 committed by Clebert Suconic
parent 405c3eb2a4
commit d63422161f
4 changed files with 393 additions and 0 deletions

View File

@ -0,0 +1,41 @@
Apache Artemix JMH Benchmarks
-------
This module contains optional [JMH](http://openjdk.java.net/projects/code-tools/jmh/) performance tests.
Note that this module is an optional part of the overall project build and does not deploy anything, due to its use
of JMH which is not permissively licensed. The module must be built directly.
Building the benchmarks
-------
The benchmarks are maven built and involve some code generation for the JMH part. As such it is required that you
rebuild upon changing the code.
mvn clean install
Running the benchmarks: General
-------
It is recommended that you consider some basic benchmarking practices before running benchmarks:
1. Use a quiet machine with enough CPUs to run the number of threads you mean to run.
2. Set the CPU freq to avoid variance due to turbo boost/heating.
3. Use an OS tool such as taskset to pin the threads in the topology you mean to measure.
Running the JMH Benchmarks
-----
To run all JMH benchmarks:
java -jar target/benchmark.jar
To list available benchmarks:
java -jar target/benchmark.jar -l
Some JMH help:
java -jar target/benchmark.jar -h
Example
-----
To run a benchmark on a single thread (tg 1) with gc profiling use:
java -jar target/benchmark.jar -prof gc -tg 1

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.apache.activemq.tests</groupId>
<artifactId>artemis-tests-pom</artifactId>
<version>2.17.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>performance-jmh</artifactId>
<packaging>jar</packaging>
<name>ActiveMQ Artemis JMH Performance Tests</name>
<properties>
<jmh.version>1.26</jmh.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-core-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>artemis-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${jmh.version}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>benchmark</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<!-- Don't deploy artifacts for this module. It has non-permissive
dependencies and is only optionally used for local testing. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,247 @@
/*
* 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.activemq.artemis.tests.performance.jmh;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.activemq.artemis.api.core.Message;
import org.apache.activemq.artemis.api.core.RoutingType;
import org.apache.activemq.artemis.api.core.SimpleString;
import org.apache.activemq.artemis.core.config.WildcardConfiguration;
import org.apache.activemq.artemis.core.filter.Filter;
import org.apache.activemq.artemis.core.postoffice.Binding;
import org.apache.activemq.artemis.core.postoffice.BindingType;
import org.apache.activemq.artemis.core.postoffice.Bindings;
import org.apache.activemq.artemis.core.postoffice.BindingsFactory;
import org.apache.activemq.artemis.core.postoffice.impl.BindingsImpl;
import org.apache.activemq.artemis.core.postoffice.impl.WildcardAddressManager;
import org.apache.activemq.artemis.core.server.Bindable;
import org.apache.activemq.artemis.core.server.RoutingContext;
import org.apache.activemq.artemis.core.server.impl.AddressInfo;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Group;
import org.openjdk.jmh.annotations.GroupThreads;
import org.openjdk.jmh.annotations.Measurement;
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.Warmup;
@State(Scope.Benchmark)
@Fork(2)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 8, time = 1)
public class WildcardAddressManagerPerfTest {
private static class BindingFactoryFake implements BindingsFactory {
@Override
public Bindings createBindings(SimpleString address) throws Exception {
return new BindingsImpl(address, null);
}
}
private static class BindingFake implements Binding {
final SimpleString address;
final SimpleString id;
final Long idl;
BindingFake(SimpleString addressParameter, SimpleString id, long idl) {
this.address = addressParameter;
this.id = id;
this.idl = idl;
}
@Override
public void unproposed(SimpleString groupID) {
}
@Override
public SimpleString getAddress() {
return address;
}
@Override
public Bindable getBindable() {
return null;
}
@Override
public BindingType getType() {
return BindingType.LOCAL_QUEUE;
}
@Override
public SimpleString getUniqueName() {
return id;
}
@Override
public SimpleString getRoutingName() {
return id;
}
@Override
public SimpleString getClusterName() {
return null;
}
@Override
public Filter getFilter() {
return null;
}
@Override
public boolean isHighAcceptPriority(Message message) {
return false;
}
@Override
public boolean isExclusive() {
return false;
}
@Override
public Long getID() {
return idl;
}
@Override
public int getDistance() {
return 0;
}
@Override
public void route(Message message, RoutingContext context) throws Exception {
}
@Override
public void close() throws Exception {
}
@Override
public String toManagementString() {
return "FakeBiding Address=" + this.address;
}
@Override
public boolean isConnected() {
return true;
}
@Override
public void routeWithAck(Message message, RoutingContext context) {
}
}
public WildcardAddressManager addressManager;
@Param({"2", "8", "10"})
int topicsLog2;
int topics;
AtomicLong topicCounter;
private static final WildcardConfiguration WILDCARD_CONFIGURATION;
SimpleString[] addresses;
static {
WILDCARD_CONFIGURATION = new WildcardConfiguration();
WILDCARD_CONFIGURATION.setAnyWords('>');
}
private static final SimpleString WILDCARD = SimpleString.toSimpleString("Topic1.>");
@Setup
public void init() throws Exception {
addressManager = new WildcardAddressManager(new BindingFactoryFake(), WILDCARD_CONFIGURATION, null, null);
addressManager.addAddressInfo(new AddressInfo(WILDCARD, RoutingType.MULTICAST));
topics = 1 << topicsLog2;
addresses = new SimpleString[topics];
for (int i = 0; i < topics; i++) {
Binding binding = new BindingFake(WILDCARD, SimpleString.toSimpleString("" + i), i);
addressManager.addBinding(binding);
addresses[i] = SimpleString.toSimpleString("Topic1." + i);
addressManager.getBindingsForRoutingAddress(addresses[i]);
}
topicCounter = new AtomicLong(0);
topicCounter.set(topics);
}
private long nextId() {
return topicCounter.getAndIncrement();
}
@State(value = Scope.Thread)
public static class ThreadState {
Binding binding;
long next;
SimpleString[] addresses;
@Setup
public void init(WildcardAddressManagerPerfTest benchmarkState) {
final long id = benchmarkState.nextId();
binding = new BindingFake(WILDCARD, SimpleString.toSimpleString("" + id), id);
addresses = benchmarkState.addresses;
}
public SimpleString nextAddress() {
final long current = next;
next = current + 1;
final int index = (int) (current & (addresses.length - 1));
return addresses[index];
}
}
@Benchmark
@Group("both")
@GroupThreads(2)
public Bindings testPublishWhileAddRemoveNewBinding(ThreadState state) throws Exception {
return addressManager.getBindingsForRoutingAddress(state.nextAddress());
}
@Benchmark
@Group("both")
@GroupThreads(2)
public Binding testAddRemoveNewBindingWhilePublish(ThreadState state) throws Exception {
final Binding binding = state.binding;
addressManager.addBinding(binding);
return addressManager.removeBinding(binding.getUniqueName(), null);
}
@Benchmark
@GroupThreads(4)
public Bindings testJustPublish(ThreadState state) throws Exception {
return addressManager.getBindingsForRoutingAddress(state.nextAddress());
}
@Benchmark
@GroupThreads(4)
public Binding testJustAddRemoveNewBinding(ThreadState state) throws Exception {
final Binding binding = state.binding;
addressManager.addBinding(binding);
return addressManager.removeBinding(binding.getUniqueName(), null);
}
}

View File

@ -90,6 +90,12 @@
<module>extra-tests</module>
</modules>
</profile>
<profile>
<id>jmh</id>
<modules>
<module>performance-jmh</module>
</modules>
</profile>
<profile>
<!-- deprecated: use openwire-tests -->
<id>activemq5-unit-tests</id>