This is an automated email from the ASF dual-hosted git repository.
jin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git
The following commit(s) were added to refs/heads/master by this push:
new 5df28fa2c feat(perf): support JMH benchmark in HG-test module (#2238)
5df28fa2c is described below
commit 5df28fa2cafd9607edd746c78219e65649d55667
Author: conghuhu <[email protected]>
AuthorDate: Mon Jul 17 16:50:35 2023 +0800
feat(perf): support JMH benchmark in HG-test module (#2238)
* chore: add param to max cap
* chore: add non argument constructor to IntMapByEcSegment
---------
Co-authored-by: shiyi <[email protected]>
---
.../apache/hugegraph/util/collection/IntMap.java | 6 +-
hugegraph-dist/release-docs/LICENSE | 1 +
.../release-docs/licenses/LINCENSE-jopt-simple.txt | 24 ++++
hugegraph-test/pom.xml | 35 ++++++
.../hugegraph/benchmark/BenchmarkConstants.java | 23 ++++
.../apache/hugegraph/benchmark/SimpleRandom.java | 42 +++++++
.../map/MapRandomGetPutThroughputTest.java | 137 +++++++++++++++++++++
pom.xml | 14 ++-
8 files changed, 280 insertions(+), 2 deletions(-)
diff --git
a/hugegraph-core/src/main/java/org/apache/hugegraph/util/collection/IntMap.java
b/hugegraph-core/src/main/java/org/apache/hugegraph/util/collection/IntMap.java
index 446582746..02b705225 100644
---
a/hugegraph-core/src/main/java/org/apache/hugegraph/util/collection/IntMap.java
+++
b/hugegraph-core/src/main/java/org/apache/hugegraph/util/collection/IntMap.java
@@ -68,7 +68,7 @@ public interface IntMap {
private final int segmentMask;
private final Function<Integer, IntMap> creator;
- private static final int DEFAULT_SEGMENTS = IntSet.CPUS * 100;
+ private static final int DEFAULT_SEGMENTS = (IntSet.CPUS + 8) * 32;
private static final Function<Integer, IntMap> DEFAULT_CREATOR =
size -> new IntMapByFixedAddr(size);
@@ -512,6 +512,10 @@ public interface IntMap {
private final MutableIntIntMap[] maps;
private final int segmentMask;
+ public IntMapByEcSegment() {
+ this(IntMapBySegments.DEFAULT_SEGMENTS);
+ }
+
public IntMapByEcSegment(int segments) {
segments = IntSet.sizeToPowerOf2Size(segments);
this.segmentMask = segments - 1;
diff --git a/hugegraph-dist/release-docs/LICENSE
b/hugegraph-dist/release-docs/LICENSE
index 5bfd9e606..f1cc9686c 100644
--- a/hugegraph-dist/release-docs/LICENSE
+++ b/hugegraph-dist/release-docs/LICENSE
@@ -539,6 +539,7 @@ See licenses/ for text of these licenses.
(The MIT License) * mockito-core (org.mockito:mockito-core:3.3.3 -
https://github.com/mockito/mockito)
(The MIT License) * sourcecode (com.lihaoyi:sourcecode_2.12:0.1.4 -
https://github.com/lihaoyi/sourcecode)
(The MIT License) * Checker Qual
(org.checkerframework:checker-qual:2.0.0 - http://checkerframework.org)
+ (The MIT License) * jopt-simple (net.sf.jopt-simple:jopt-simple:5.0.4 -
https://github.com/jopt-simple/jopt-simple)
========================================================================
Third party Public Domain licenses
diff --git a/hugegraph-dist/release-docs/licenses/LINCENSE-jopt-simple.txt
b/hugegraph-dist/release-docs/licenses/LINCENSE-jopt-simple.txt
new file mode 100644
index 000000000..6984620c3
--- /dev/null
+++ b/hugegraph-dist/release-docs/licenses/LINCENSE-jopt-simple.txt
@@ -0,0 +1,24 @@
+/*
+ The MIT License
+
+ Copyright (c) 2004-2021 Paul R. Holser, Jr.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
diff --git a/hugegraph-test/pom.xml b/hugegraph-test/pom.xml
index 0bda198c4..75e8caf66 100644
--- a/hugegraph-test/pom.xml
+++ b/hugegraph-test/pom.xml
@@ -120,6 +120,20 @@
</exclusion>
</exclusions>
</dependency>
+
+ <!-- JMH -->
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-core</artifactId>
+ <version>${jmh.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-generator-annprocess</artifactId>
+ <version>${jmh.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -256,6 +270,27 @@
</execution>
</executions>
</plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <finalName>microbenchmarks</finalName>
+ <transformers>
+ <transformer
+
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.openjdk.jmh.Main</mainClass>
+ </transformer>
+ </transformers>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
<resources>
diff --git
a/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/BenchmarkConstants.java
b/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/BenchmarkConstants.java
new file mode 100644
index 000000000..1525e8143
--- /dev/null
+++
b/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/BenchmarkConstants.java
@@ -0,0 +1,23 @@
+/*
+ * 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.hugegraph.benchmark;
+
+public class BenchmarkConstants {
+
+ public static String OUTPUT_PATH = "./hugegraph-test/target/";
+}
diff --git
a/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/SimpleRandom.java
b/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/SimpleRandom.java
new file mode 100644
index 000000000..3338f10af
--- /dev/null
+++
b/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/SimpleRandom.java
@@ -0,0 +1,42 @@
+/*
+ * 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.hugegraph.benchmark;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Fairly fast random numbers
+ */
+public final class SimpleRandom {
+
+ private static final long MULTIPLIER = 0x5DEECE66DL;
+ private static final long ADD_END = 0xBL;
+ private static final long MASK = (1L << 48) - 1;
+ private static final AtomicLong SEG = new AtomicLong(-715159705);
+ private long seed;
+
+ public SimpleRandom() {
+ this.seed = System.nanoTime() + SEG.getAndAdd(129);
+ }
+
+ public int next() {
+ long nextSeed = (this.seed * MULTIPLIER + ADD_END) & MASK;
+ this.seed = nextSeed;
+ return ((int) (nextSeed >>> 17)) & 0x7FFFFFFF;
+ }
+}
diff --git
a/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/map/MapRandomGetPutThroughputTest.java
b/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/map/MapRandomGetPutThroughputTest.java
new file mode 100644
index 000000000..eafe4b861
--- /dev/null
+++
b/hugegraph-test/src/test/java/org/apache/hugegraph/benchmark/map/MapRandomGetPutThroughputTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.hugegraph.benchmark.map;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.hugegraph.benchmark.BenchmarkConstants;
+import org.apache.hugegraph.benchmark.SimpleRandom;
+import org.apache.hugegraph.util.collection.IntMap;
+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.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.results.format.ResultFormatType;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@BenchmarkMode({Mode.Throughput})
+@Warmup(iterations = 2, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
+@Measurement(iterations = 6, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
+@State(Scope.Benchmark)
+@Fork(2)
+public class MapRandomGetPutThroughputTest {
+
+ @Param(value = {"1000", "10000", "100000", "1000000"})
+ private int MAP_CAPACITY;
+
+ private ConcurrentHashMap<Integer, Integer> concurrentHashMapNonCap;
+
+ private ConcurrentHashMap<Integer, Integer> concurrentHashMap;
+
+ private IntMap.IntMapBySegments intMapBySegments;
+
+ private IntMap.IntMapByEcSegment intMapByEcSegments;
+
+ private static final int THREAD_COUNT = 8;
+
+ private static final String OUTPUT_FILE_NAME =
"map_random_get_put_result.json";
+
+ @Setup(Level.Trial)
+ public void prepareMap() {
+ this.concurrentHashMapNonCap = new ConcurrentHashMap<>();
+ this.concurrentHashMap = new ConcurrentHashMap<>(MAP_CAPACITY);
+ this.intMapBySegments = new IntMap.IntMapBySegments(MAP_CAPACITY);
+ this.intMapByEcSegments = new IntMap.IntMapByEcSegment();
+ }
+
+ /**
+ * The instantiated @State annotation only supports public classes.
+ */
+ @State(Scope.Thread)
+ public static class ThreadState {
+
+ private final SimpleRandom random = new SimpleRandom();
+
+ int next() {
+ return random.next();
+ }
+ }
+
+ @Benchmark
+ @Threads(THREAD_COUNT)
+ public void randomGetPutOfConcurrentHashMapWithNoneInitCap(ThreadState
state) {
+ int key = state.next() & (MAP_CAPACITY - 1);
+ if (!this.concurrentHashMapNonCap.containsKey(key)) {
+ this.concurrentHashMapNonCap.put(key, state.next());
+ }
+ this.concurrentHashMapNonCap.get(key);
+ }
+
+ @Benchmark
+ @Threads(THREAD_COUNT)
+ public void randomGetPutOfConcurrentHashMapWithInitCap(ThreadState state) {
+ int key = state.next() & (MAP_CAPACITY - 1);
+ if (!this.concurrentHashMap.containsKey(key)) {
+ this.concurrentHashMap.put(key, state.next());
+ }
+ this.concurrentHashMap.get(key);
+ }
+
+ @Benchmark
+ @Threads(THREAD_COUNT)
+ public void randomGetPutOfIntMapBySegments(ThreadState state) {
+ int key = state.next() & (MAP_CAPACITY - 1);
+ if (!this.intMapBySegments.containsKey(key)) {
+ this.intMapBySegments.put(key, state.next());
+ }
+ this.intMapBySegments.get(key);
+ }
+
+ @Benchmark
+ @Threads(THREAD_COUNT)
+ public void randomGetPutOfIntMapByEcSegment(ThreadState state) {
+ int key = state.next() & (MAP_CAPACITY - 1);
+ if (!this.intMapByEcSegments.containsKey(key)) {
+ this.intMapByEcSegments.put(key, state.next());
+ }
+ this.intMapByEcSegments.get(key);
+ }
+
+ public static void main(String[] args) throws RunnerException {
+ Options opt = new OptionsBuilder()
+ .include(MapRandomGetPutThroughputTest.class.getSimpleName())
+ .result(BenchmarkConstants.OUTPUT_PATH + OUTPUT_FILE_NAME)
+ .resultFormat(ResultFormatType.JSON)
+ .build();
+ new Runner(opt).run();
+ }
+}
diff --git a/pom.xml b/pom.xml
index 8679c83dd..719328316 100644
--- a/pom.xml
+++ b/pom.xml
@@ -114,6 +114,7 @@
<hugegraph-commons.version>1.0.0</hugegraph-commons.version>
<grpc.version>1.47.0</grpc.version>
<protobuf.version>3.21.7</protobuf.version>
+ <jmh.version>1.36</jmh.version>
</properties>
<modules>
@@ -322,7 +323,18 @@
<artifactId>commons-text</artifactId>
<version>1.10.0</version>
</dependency>
-
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-core</artifactId>
+ <version>${jmh.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openjdk.jmh</groupId>
+ <artifactId>jmh-generator-annprocess</artifactId>
+ <version>${jmh.version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</dependencyManagement>