Skip to content

Commit e5706e0

Browse files
committed
Add eventually visible benchmark
1 parent 1e763b2 commit e5706e0

File tree

8 files changed

+310
-0
lines changed

8 files changed

+310
-0
lines changed

sdk/logs/build.gradle.kts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,33 @@ plugins {
99
description = "OpenTelemetry Log SDK"
1010
otelJava.moduleName.set("io.opentelemetry.sdk.logs")
1111

12+
sourceSets {
13+
create("jmhJava9") {
14+
java {
15+
srcDirs("src/jmh/java9")
16+
}
17+
compileClasspath += sourceSets.jmh.get().compileClasspath
18+
compileClasspath += sourceSets.jmh.get().output
19+
}
20+
}
21+
22+
tasks {
23+
named<JavaCompile>("compileJmhJava9Java") {
24+
options.release = 9
25+
dependsOn("compileJmhJava")
26+
}
27+
28+
// Configure JMH jar as multi-release jar
29+
named<Jar>("jmhJar") {
30+
into("META-INF/versions/9") {
31+
from(sourceSets["jmhJava9"].output)
32+
}
33+
manifest.attributes(
34+
"Multi-Release" to "true"
35+
)
36+
}
37+
}
38+
1239
dependencies {
1340
api(project(":api:all"))
1441
api(project(":sdk:common"))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
public interface BooleanState {
9+
10+
boolean get();
11+
12+
void set(boolean state);
13+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
import java.util.concurrent.TimeUnit;
9+
import org.openjdk.jmh.annotations.Benchmark;
10+
import org.openjdk.jmh.annotations.BenchmarkMode;
11+
import org.openjdk.jmh.annotations.Fork;
12+
import org.openjdk.jmh.annotations.Level;
13+
import org.openjdk.jmh.annotations.Measurement;
14+
import org.openjdk.jmh.annotations.Mode;
15+
import org.openjdk.jmh.annotations.OutputTimeUnit;
16+
import org.openjdk.jmh.annotations.Param;
17+
import org.openjdk.jmh.annotations.Scope;
18+
import org.openjdk.jmh.annotations.Setup;
19+
import org.openjdk.jmh.annotations.State;
20+
import org.openjdk.jmh.annotations.Threads;
21+
import org.openjdk.jmh.annotations.Warmup;
22+
23+
@BenchmarkMode(Mode.AverageTime)
24+
@OutputTimeUnit(TimeUnit.NANOSECONDS)
25+
@Warmup(iterations = 5, time = 1)
26+
@Measurement(iterations = 10, time = 1)
27+
@Fork(1)
28+
@State(Scope.Benchmark)
29+
public class BooleanStateBenchmark {
30+
31+
@Param({
32+
"NonVolatileBooleanState",
33+
"ImmediateBooleanState",
34+
"EventualBooleanState",
35+
"VarHandleImmediateBooleanState", // available with -PjmhJavaVersion=11 and higher
36+
"VarHandleEventualBooleanState" // available with -PjmhJavaVersion=11 and higher
37+
})
38+
private String implementation;
39+
40+
private BooleanState state;
41+
42+
@Setup(Level.Trial)
43+
public void setup() {
44+
switch (implementation) {
45+
case "NonVolatileBooleanState":
46+
state = new NonVolatileBooleanState();
47+
break;
48+
case "ImmediateBooleanState":
49+
state = new ImmediateBooleanState();
50+
break;
51+
case "EventualBooleanState":
52+
state = new EventualBooleanState();
53+
break;
54+
case "VarHandleImmediateBooleanState":
55+
state = createVarHandleImmediateBooleanState();
56+
break;
57+
case "VarHandleEventualBooleanState":
58+
state = createVarHandleEventualBooleanState();
59+
break;
60+
default:
61+
throw new IllegalArgumentException("Unknown implementation: " + implementation);
62+
}
63+
}
64+
65+
private static BooleanState createVarHandleEventualBooleanState() {
66+
try {
67+
Class<?> clazz =
68+
Class.forName("io.opentelemetry.sdk.logs.booleanstate.VarHandleEventualBooleanState");
69+
return (BooleanState) clazz.getConstructor().newInstance();
70+
} catch (Exception e) {
71+
throw new IllegalStateException(
72+
"VarHandleEventualBooleanState not available on this Java version", e);
73+
}
74+
}
75+
76+
private static BooleanState createVarHandleImmediateBooleanState() {
77+
try {
78+
Class<?> clazz =
79+
Class.forName("io.opentelemetry.sdk.logs.booleanstate.VarHandleImmediateBooleanState");
80+
return (BooleanState) clazz.getConstructor().newInstance();
81+
} catch (Exception e) {
82+
throw new IllegalStateException(
83+
"VarHandleImmediateBooleanState not available on this Java version", e);
84+
}
85+
}
86+
87+
@Benchmark
88+
@Threads(1)
89+
public int read_singleThread() {
90+
int count = 0;
91+
for (int i = 0; i < 100; i++) {
92+
if (state.get()) {
93+
count++;
94+
}
95+
}
96+
return count;
97+
}
98+
99+
@Benchmark
100+
@Threads(2) // not expecting significant concurrent access
101+
public int read_twoThreads() {
102+
int count = 0;
103+
for (int i = 0; i < 100; i++) {
104+
if (state.get()) {
105+
count++;
106+
}
107+
}
108+
return count;
109+
}
110+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
public class EventualBooleanState implements BooleanState {
9+
10+
private volatile boolean state;
11+
private boolean cached;
12+
13+
private int counter;
14+
15+
@Override
16+
public boolean get() {
17+
if (counter++ > 1000) {
18+
counter = 0;
19+
cached = state; // Update cached value for visibility in this thread
20+
}
21+
return cached;
22+
}
23+
24+
@Override
25+
public void set(boolean state) {
26+
this.state = state;
27+
this.cached = state; // Update cached value for immediate visibility in this thread
28+
}
29+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
public class ImmediateBooleanState implements BooleanState {
9+
10+
private volatile boolean state;
11+
12+
@Override
13+
public boolean get() {
14+
return state;
15+
}
16+
17+
@Override
18+
public void set(boolean state) {
19+
this.state = state;
20+
}
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
public class NonVolatileBooleanState implements BooleanState {
9+
10+
private boolean state;
11+
12+
@Override
13+
public boolean get() {
14+
return state;
15+
}
16+
17+
@Override
18+
public void set(boolean state) {
19+
this.state = state;
20+
}
21+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
import java.lang.invoke.MethodHandles;
9+
import java.lang.invoke.VarHandle;
10+
11+
public class VarHandleEventualBooleanState implements BooleanState {
12+
13+
private static final VarHandle STATE_HANDLE;
14+
15+
static {
16+
try {
17+
MethodHandles.Lookup lookup = MethodHandles.lookup();
18+
STATE_HANDLE =
19+
lookup.findVarHandle(VarHandleEventualBooleanState.class, "state", boolean.class);
20+
} catch (ReflectiveOperationException e) {
21+
throw new ExceptionInInitializerError(e);
22+
}
23+
}
24+
25+
@SuppressWarnings("UnusedVariable") // Used by VarHandle
26+
private boolean state;
27+
28+
private int counter = 0;
29+
30+
public VarHandleEventualBooleanState() {
31+
STATE_HANDLE.setRelease(this, false);
32+
}
33+
34+
@Override
35+
public boolean get() {
36+
if (counter++ > 1000) {
37+
counter = 0;
38+
return (boolean) STATE_HANDLE.getAcquire(this);
39+
}
40+
41+
return (boolean) STATE_HANDLE.getOpaque(this);
42+
}
43+
44+
@Override
45+
public void set(boolean state) {
46+
STATE_HANDLE.setRelease(this, state);
47+
}
48+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.sdk.logs.booleanstate;
7+
8+
import java.lang.invoke.MethodHandles;
9+
import java.lang.invoke.VarHandle;
10+
11+
public class VarHandleImmediateBooleanState implements BooleanState {
12+
13+
private static final VarHandle STATE_HANDLE;
14+
15+
static {
16+
try {
17+
MethodHandles.Lookup lookup = MethodHandles.lookup();
18+
STATE_HANDLE =
19+
lookup.findVarHandle(VarHandleImmediateBooleanState.class, "state", boolean.class);
20+
} catch (ReflectiveOperationException e) {
21+
throw new ExceptionInInitializerError(e);
22+
}
23+
}
24+
25+
@SuppressWarnings("UnusedVariable") // Used by VarHandle
26+
private boolean state;
27+
28+
public VarHandleImmediateBooleanState() {
29+
STATE_HANDLE.setRelease(this, false);
30+
}
31+
32+
@Override
33+
public boolean get() {
34+
return (boolean) STATE_HANDLE.getAcquire(this);
35+
}
36+
37+
@Override
38+
public void set(boolean state) {
39+
STATE_HANDLE.setRelease(this, state);
40+
}
41+
}

0 commit comments

Comments
 (0)