Skip to content

Commit 2dbda56

Browse files
committed
Add benchmarks for Bytes.get
Signed-off-by: Luis Pinto <luis.pinto@consensys.net>
1 parent 4b362ba commit 2dbda56

File tree

7 files changed

+427
-0
lines changed

7 files changed

+427
-0
lines changed

bytes/build.gradle

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
1111
* specific language governing permissions and limitations under the License.
1212
*/
13+
plugins {
14+
id 'me.champeau.jmh' version '0.7.2'
15+
}
16+
1317
description = 'Classes and utilities for working with byte arrays.'
1418

1519
dependencies {
@@ -23,6 +27,30 @@ dependencies {
2327
testImplementation 'org.junit.jupiter:junit-jupiter-api'
2428
testImplementation 'org.junit.jupiter:junit-jupiter-params'
2529
testImplementation 'org.mockito:mockito-junit-jupiter'
30+
jmhImplementation 'tools.profiler:async-profiler:3.0'
2631

2732
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
33+
34+
jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
35+
}
36+
37+
// to pass compilation as the compiler doesn't like what jmh tool is doing
38+
compileJmhJava {
39+
options.compilerArgs << '-Xlint:none'
40+
}
41+
42+
jmh {
43+
jmhVersion = '1.37'
44+
if (project.hasProperty('jmh.includes')) {
45+
includes = [project.property('jmh.includes')]
46+
}
47+
48+
jvmArgs = ['-XX:LoopUnrollLimit=1',
49+
'-XX:-TieredCompilation',
50+
'-XX:+UnlockDiagnosticVMOptions',
51+
// '-XX:+TraceDeoptimization',
52+
// '-XX:+PrintCompilation',
53+
// '-XX:+PrintInlining',
54+
// '-XX:-Inline'
55+
]
2856
}

bytes/build.gradle.orig

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
3+
* file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
4+
* to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
5+
* License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
plugins {
14+
id 'me.champeau.jmh' version '0.7.2'
15+
}
16+
17+
description = 'Classes and utilities for working with byte arrays.'
18+
19+
dependencies {
20+
implementation 'org.connid:framework'
21+
implementation 'org.connid:framework-internal'
22+
compileOnly 'com.google.code.findbugs:jsr305'
23+
compileOnly 'com.google.errorprone:error_prone_annotations'
24+
api 'io.vertx:vertx-core'
25+
26+
testImplementation 'io.vertx:vertx-core'
27+
testImplementation 'org.junit.jupiter:junit-jupiter-api'
28+
testImplementation 'org.junit.jupiter:junit-jupiter-params'
29+
testImplementation 'org.mockito:mockito-junit-jupiter'
30+
testImplementation 'tools.profiler:async-profiler:3.0'
31+
32+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
33+
34+
jmhAnnotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
35+
}
36+
37+
// to pass compilation as the compiler doesn't like what jmh tool is doing
38+
compileJmhJava {
39+
options.compilerArgs << '-Xlint:none'
40+
}
41+
42+
jmh {
43+
jmhVersion = '1.37'
44+
if (project.hasProperty('jmh.includes')) {
45+
includes = [project.property('jmh.includes')]
46+
}
47+
// def asyncProfiler = System.getenv("ASYNC_PROFILER")
48+
// def timestamp = new Date().format("yyyyMMddHHmmss")
49+
// def flamegraphFile = "/tmp/flamegraph-${timestamp}.html"
50+
51+
jvmArgs = ['-XX:LoopUnrollLimit=1',
52+
'-XX:-TieredCompilation',
53+
'-XX:+UnlockDiagnosticVMOptions',
54+
// '-XX:+TraceDeoptimization',
55+
// '-XX:+PrintCompilation',
56+
<<<<<<< Updated upstream
57+
// '-XX:+PrintInlining',
58+
=======
59+
// '-XX:+PrintInlining',
60+
>>>>>>> Stashed changes
61+
// '-XX:-Inline',
62+
// "-agentpath:$asyncProfiler/lib/libasyncProfiler.dylib=start,collapsed,loglevel=TRACE,flamegraph,file=$flamegraphFile"
63+
]
64+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright The Tuweni Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
package org.benchmark;
4+
5+
import java.util.Random;
6+
import java.util.concurrent.TimeUnit;
7+
8+
import org.openjdk.jmh.annotations.Benchmark;
9+
import org.openjdk.jmh.annotations.BenchmarkMode;
10+
import org.openjdk.jmh.annotations.Fork;
11+
import org.openjdk.jmh.annotations.Measurement;
12+
import org.openjdk.jmh.annotations.Mode;
13+
import org.openjdk.jmh.annotations.OutputTimeUnit;
14+
import org.openjdk.jmh.annotations.Param;
15+
import org.openjdk.jmh.annotations.Scope;
16+
import org.openjdk.jmh.annotations.Setup;
17+
import org.openjdk.jmh.annotations.State;
18+
import org.openjdk.jmh.annotations.Warmup;
19+
20+
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
21+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
22+
@BenchmarkMode(value = Mode.AverageTime)
23+
@State(Scope.Benchmark)
24+
@Fork(value = 1)
25+
@OutputTimeUnit(value = TimeUnit.MILLISECONDS)
26+
public class BytesMegamorphicBenchmarkV1 extends ProfiledBenchmark {
27+
private static final int N = 4;
28+
private static final int FACTOR = 1000000;
29+
private static final Random RANDOM = new Random(23L);
30+
org.apache.tuweni.bytes.Bytes[] bytesV1;
31+
32+
@Param({"mono", "mega"})
33+
private String mode;
34+
35+
@Setup
36+
public void setup() {
37+
bytesV1 = new org.apache.tuweni.bytes.Bytes[N * FACTOR];
38+
for (int i = 0; i < N * FACTOR; i += N) {
39+
bytesV1[i] = org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
40+
bytesV1[i + 1] =
41+
"mega".equals(mode)
42+
? org.apache.tuweni.bytes.Bytes.wrap(getBytes(48))
43+
: org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
44+
bytesV1[i + 2] =
45+
"mega".equals(mode)
46+
? org.apache.tuweni.bytes.Bytes.repeat((byte) 0x09, 16)
47+
: org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
48+
bytesV1[i + 3] =
49+
"mega".equals(mode)
50+
? org.apache.tuweni.bytes.Bytes.wrap(bytesV1[i], bytesV1[i + 1])
51+
: org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
52+
}
53+
}
54+
55+
private static byte[] getBytes(final int size) {
56+
byte[] b = new byte[size];
57+
RANDOM.nextBytes(b);
58+
return b;
59+
}
60+
61+
@Benchmark
62+
public void test() {
63+
for (org.apache.tuweni.bytes.Bytes b : bytesV1) {
64+
b.get(1);
65+
}
66+
}
67+
68+
String getUniqueTestId() {
69+
return this.getClass().getSimpleName() + "-" + mode + "-" + System.currentTimeMillis();
70+
}
71+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright The Tuweni Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
package org.benchmark;
4+
5+
import java.util.Random;
6+
import java.util.concurrent.TimeUnit;
7+
8+
import org.openjdk.jmh.annotations.Benchmark;
9+
import org.openjdk.jmh.annotations.BenchmarkMode;
10+
import org.openjdk.jmh.annotations.Fork;
11+
import org.openjdk.jmh.annotations.Measurement;
12+
import org.openjdk.jmh.annotations.Mode;
13+
import org.openjdk.jmh.annotations.OutputTimeUnit;
14+
import org.openjdk.jmh.annotations.Param;
15+
import org.openjdk.jmh.annotations.Scope;
16+
import org.openjdk.jmh.annotations.Setup;
17+
import org.openjdk.jmh.annotations.State;
18+
import org.openjdk.jmh.annotations.Warmup;
19+
20+
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
21+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
22+
@BenchmarkMode(value = Mode.AverageTime)
23+
@State(Scope.Benchmark)
24+
@Fork(value = 1)
25+
@OutputTimeUnit(value = TimeUnit.MILLISECONDS)
26+
public class BytesMegamorphicBenchmarkV2 extends ProfiledBenchmark {
27+
private static final int N = 4;
28+
private static final int FACTOR = 1000000;
29+
private static final Random RANDOM = new Random(23L);
30+
org.apache.tuweni.bytes.v2.Bytes[] bytesV2;
31+
32+
@Param({"mono", "mega"})
33+
private String mode;
34+
35+
@Setup
36+
public void setup() {
37+
bytesV2 = new org.apache.tuweni.bytes.v2.Bytes[N * FACTOR];
38+
for (int i = 0; i < N * FACTOR; i += N) {
39+
bytesV2[i] = org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
40+
bytesV2[i + 1] =
41+
"mega".equals(mode)
42+
? org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(48))
43+
: org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
44+
bytesV2[i + 2] =
45+
"mega".equals(mode)
46+
? org.apache.tuweni.bytes.v2.Bytes.repeat((byte) 0x09, 16)
47+
: org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
48+
bytesV2[i + 3] =
49+
"mega".equals(mode)
50+
? org.apache.tuweni.bytes.v2.Bytes.wrap(bytesV2[i], bytesV2[i + 1])
51+
: org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
52+
}
53+
}
54+
55+
private static byte[] getBytes(final int size) {
56+
byte[] b = new byte[size];
57+
RANDOM.nextBytes(b);
58+
return b;
59+
}
60+
61+
@Benchmark
62+
public void test() {
63+
for (org.apache.tuweni.bytes.v2.Bytes b : bytesV2) {
64+
b.get(1);
65+
}
66+
}
67+
68+
String getUniqueTestId() {
69+
return this.getClass().getSimpleName() + "-" + mode + "-" + System.currentTimeMillis();
70+
}
71+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright The Tuweni Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
package org.benchmark;
4+
5+
import java.util.concurrent.TimeUnit;
6+
7+
import org.openjdk.jmh.annotations.Benchmark;
8+
import org.openjdk.jmh.annotations.BenchmarkMode;
9+
import org.openjdk.jmh.annotations.Fork;
10+
import org.openjdk.jmh.annotations.Measurement;
11+
import org.openjdk.jmh.annotations.Mode;
12+
import org.openjdk.jmh.annotations.OutputTimeUnit;
13+
import org.openjdk.jmh.annotations.Param;
14+
import org.openjdk.jmh.annotations.Scope;
15+
import org.openjdk.jmh.annotations.Setup;
16+
import org.openjdk.jmh.annotations.State;
17+
import org.openjdk.jmh.annotations.Warmup;
18+
19+
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
20+
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
21+
@BenchmarkMode(value = Mode.AverageTime)
22+
@State(Scope.Benchmark)
23+
@Fork(value = 1)
24+
@OutputTimeUnit(value = TimeUnit.MILLISECONDS)
25+
public class InterfaceCall {
26+
interface A {
27+
void m();
28+
}
29+
30+
static class C1 implements A {
31+
int c = 0;
32+
33+
@Override
34+
public void m() {
35+
c++;
36+
}
37+
}
38+
39+
static class C2 implements A {
40+
int c = 1;
41+
42+
@Override
43+
public void m() {
44+
c++;
45+
}
46+
}
47+
48+
static class C3 implements A {
49+
int c = 2;
50+
51+
@Override
52+
public void m() {
53+
c++;
54+
}
55+
}
56+
57+
A[] as;
58+
59+
@Param({"mono", "mega"})
60+
private String mode;
61+
62+
@Setup
63+
public void setup() {
64+
as = new A[300000000];
65+
boolean mega = mode.equals("mega");
66+
for (int c = 0; c < 300000000; c += 3) {
67+
as[c] = new C1();
68+
as[c + 1] = mega ? new C2() : new C1();
69+
as[c + 2] = mega ? new C3() : new C1();
70+
}
71+
}
72+
73+
@Benchmark
74+
public void test() {
75+
for (A a : as) {
76+
a.m();
77+
}
78+
}
79+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright The Tuweni Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
package org.benchmark;
4+
5+
import java.io.IOException;
6+
7+
import one.profiler.AsyncProfiler;
8+
import org.openjdk.jmh.annotations.Level;
9+
import org.openjdk.jmh.annotations.Scope;
10+
import org.openjdk.jmh.annotations.Setup;
11+
import org.openjdk.jmh.annotations.State;
12+
13+
@State(value = Scope.Benchmark)
14+
public class ProfiledBenchmark {
15+
private int counter = getWarmupIterations();
16+
17+
@Setup(Level.Iteration)
18+
public void startProfiler() throws IOException {
19+
if (counter-- == 0) {
20+
String fileName = "/tmp/flamegraph-" + getUniqueTestId() + ".html";
21+
AsyncProfiler.getInstance(System.getenv("ASYNC_PROFILER"))
22+
.execute("start,interval=1ms,collapsed,flamegraph,features=vtable,file=" + fileName);
23+
}
24+
}
25+
26+
/**
27+
* Warmup iterations from where to start the profiler from.
28+
*
29+
* @return warmup iterations
30+
*/
31+
int getWarmupIterations() {
32+
return 10;
33+
}
34+
35+
/**
36+
* Benchmark test id to be used in the filename for the profiler benchmark.
37+
*
38+
* @return unique test id
39+
*/
40+
String getUniqueTestId() {
41+
return this.getClass().getSimpleName() + "-" + System.currentTimeMillis();
42+
}
43+
}

0 commit comments

Comments
 (0)