Skip to content

Commit 0625d27

Browse files
committed
Add benchmarks for Bytes.get
Signed-off-by: Luis Pinto <[email protected]>
1 parent e9aec84 commit 0625d27

File tree

7 files changed

+397
-0
lines changed

7 files changed

+397
-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: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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] = "mega".equals(mode) ? org.apache.tuweni.bytes.Bytes.wrap(getBytes(48)) : org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
41+
bytesV1[i + 2] = "mega".equals(mode) ? org.apache.tuweni.bytes.Bytes.repeat((byte) 0x09, 16) : org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
42+
bytesV1[i + 3] = "mega".equals(mode) ? org.apache.tuweni.bytes.Bytes.wrap(bytesV1[i], bytesV1[i+1]) : org.apache.tuweni.bytes.Bytes.wrap(getBytes(32));
43+
}
44+
}
45+
46+
private static byte[] getBytes(final int size) {
47+
byte[] b = new byte[size];
48+
RANDOM.nextBytes(b);
49+
return b;
50+
}
51+
52+
@Benchmark
53+
public void test() {
54+
for (org.apache.tuweni.bytes.Bytes b : bytesV1) {
55+
b.get(1);
56+
}
57+
}
58+
59+
String getUniqueTestId() {
60+
return this.getClass().getSimpleName() + "-" + mode + "-" + System.currentTimeMillis();
61+
}
62+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.benchmark;
2+
3+
import java.util.Random;
4+
import java.util.concurrent.TimeUnit;
5+
6+
import org.openjdk.jmh.annotations.Benchmark;
7+
import org.openjdk.jmh.annotations.BenchmarkMode;
8+
import org.openjdk.jmh.annotations.Fork;
9+
import org.openjdk.jmh.annotations.Measurement;
10+
import org.openjdk.jmh.annotations.Mode;
11+
import org.openjdk.jmh.annotations.OutputTimeUnit;
12+
import org.openjdk.jmh.annotations.Param;
13+
import org.openjdk.jmh.annotations.Scope;
14+
import org.openjdk.jmh.annotations.Setup;
15+
import org.openjdk.jmh.annotations.State;
16+
import org.openjdk.jmh.annotations.Warmup;
17+
18+
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
19+
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
20+
@BenchmarkMode(value = Mode.AverageTime)
21+
@State(Scope.Benchmark)
22+
@Fork(value = 1)
23+
@OutputTimeUnit(value = TimeUnit.MILLISECONDS)
24+
public class BytesMegamorphicBenchmarkV2 extends ProfiledBenchmark {
25+
private static final int N = 4;
26+
private static final int FACTOR = 1000000;
27+
private static final Random RANDOM = new Random(23L);
28+
org.apache.tuweni.bytes.v2.Bytes[] bytesV2;
29+
30+
@Param({"mono", "mega"})
31+
private String mode;
32+
33+
@Setup
34+
public void setup() {
35+
bytesV2 = new org.apache.tuweni.bytes.v2.Bytes[N * FACTOR];
36+
for (int i = 0; i < N * FACTOR; i += N) {
37+
bytesV2[i] = org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
38+
bytesV2[i + 1] = "mega".equals(mode) ? org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(48)) : org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
39+
bytesV2[i + 2] = "mega".equals(mode) ? org.apache.tuweni.bytes.v2.Bytes.repeat((byte) 0x09, 16) : org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
40+
bytesV2[i + 3] = "mega".equals(mode) ? org.apache.tuweni.bytes.v2.Bytes.wrap(bytesV2[i], bytesV2[i+1]) : org.apache.tuweni.bytes.v2.Bytes.wrap(getBytes(32));
41+
}
42+
}
43+
44+
private static byte[] getBytes(final int size) {
45+
byte[] b = new byte[size];
46+
RANDOM.nextBytes(b);
47+
return b;
48+
}
49+
50+
@Benchmark
51+
public void test() {
52+
for (org.apache.tuweni.bytes.v2.Bytes b : bytesV2) {
53+
b.get(1);
54+
}
55+
}
56+
57+
String getUniqueTestId() {
58+
return this.getClass().getSimpleName() + "-" + mode + "-" + System.currentTimeMillis();
59+
}
60+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package org.benchmark;
2+
3+
import org.openjdk.jmh.annotations.Benchmark;
4+
import org.openjdk.jmh.annotations.BenchmarkMode;
5+
import org.openjdk.jmh.annotations.Fork;
6+
import org.openjdk.jmh.annotations.Measurement;
7+
import org.openjdk.jmh.annotations.Mode;
8+
import org.openjdk.jmh.annotations.OutputTimeUnit;
9+
import org.openjdk.jmh.annotations.Param;
10+
import org.openjdk.jmh.annotations.Scope;
11+
import org.openjdk.jmh.annotations.Setup;
12+
import org.openjdk.jmh.annotations.State;
13+
import org.openjdk.jmh.annotations.Warmup;
14+
15+
import java.util.concurrent.TimeUnit;
16+
17+
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
18+
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
19+
@BenchmarkMode(value = Mode.AverageTime)
20+
@State(Scope.Benchmark)
21+
@Fork(value = 1)
22+
@OutputTimeUnit(value = TimeUnit.MILLISECONDS)
23+
public class InterfaceCall {
24+
interface A {
25+
void m();
26+
}
27+
28+
static class C1 implements A {
29+
int c = 0;
30+
@Override
31+
public void m() {
32+
c++;
33+
}
34+
}
35+
36+
static class C2 implements A {
37+
int c = 1;
38+
@Override
39+
public void m() {
40+
c++;
41+
}
42+
}
43+
44+
static class C3 implements A {
45+
int c = 2;
46+
@Override
47+
public void m() {
48+
c++;
49+
}
50+
}
51+
52+
A[] as;
53+
54+
@Param({"mono", "mega"})
55+
private String mode;
56+
57+
@Setup
58+
public void setup() {
59+
as = new A[300000000];
60+
boolean mega = mode.equals("mega");
61+
for (int c = 0; c < 300000000; c += 3) {
62+
as[c] = new C1();
63+
as[c + 1] = mega ? new C2() : new C1();
64+
as[c + 2] = mega ? new C3() : new C1();
65+
}
66+
}
67+
68+
@Benchmark
69+
public void test() {
70+
for (A a : as) {
71+
a.m();
72+
}
73+
}
74+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.benchmark;
2+
3+
import one.profiler.AsyncProfiler;
4+
import org.openjdk.jmh.annotations.Level;
5+
import org.openjdk.jmh.annotations.Scope;
6+
import org.openjdk.jmh.annotations.Setup;
7+
import org.openjdk.jmh.annotations.State;
8+
9+
import java.io.IOException;
10+
11+
@State(value = Scope.Benchmark)
12+
public class ProfiledBenchmark {
13+
private int counter = getWarmupIterations();
14+
15+
@Setup(Level.Iteration)
16+
public void startProfiler() throws IOException {
17+
if (counter-- == 0) {
18+
String fileName = "/tmp/flamegraph-" + getUniqueTestId() + ".html";
19+
AsyncProfiler.getInstance(System.getenv("ASYNC_PROFILER")).execute("start,interval=1ms,collapsed,flamegraph,features=vtable,file=" + fileName);
20+
}
21+
}
22+
23+
/**
24+
* Warmup iterations from where to start the profiler from.
25+
* @return warmup iterations
26+
*/
27+
int getWarmupIterations() {
28+
return 10;
29+
}
30+
31+
/**
32+
* Benchmark test id to be used in the filename for the profiler benchmark.
33+
* @return unique test id
34+
*/
35+
String getUniqueTestId() {
36+
return this.getClass().getSimpleName() + "-" + System.currentTimeMillis();
37+
}
38+
}

0 commit comments

Comments
 (0)