Skip to content

Commit c379e48

Browse files
committed
Add ExactMathBenchmark.
1 parent 0a90cdd commit c379e48

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.truffle.benchmark;
42+
43+
import java.util.Random;
44+
import java.util.stream.DoubleStream;
45+
46+
import org.openjdk.jmh.annotations.Benchmark;
47+
import org.openjdk.jmh.annotations.Fork;
48+
import org.openjdk.jmh.annotations.Measurement;
49+
import org.openjdk.jmh.annotations.Scope;
50+
import org.openjdk.jmh.annotations.State;
51+
import org.openjdk.jmh.annotations.Warmup;
52+
import org.openjdk.jmh.infra.Blackhole;
53+
54+
import com.oracle.truffle.api.CompilerDirectives;
55+
import com.oracle.truffle.api.ExactMath;
56+
57+
/**
58+
* Benchmarks {@link ExactMath} functions.
59+
*
60+
* Checkstyle: stop
61+
*/
62+
@Warmup(iterations = 5, time = TruffleBenchmark.Defaults.ITERATION_TIME)
63+
@Measurement(iterations = 5, time = TruffleBenchmark.Defaults.ITERATION_TIME)
64+
@Fork(TruffleBenchmark.Defaults.FORKS)
65+
public class ExactMathBenchmark extends TruffleBenchmark {
66+
67+
@State(Scope.Benchmark)
68+
public static class ThreadState {
69+
// fixed random seed for reproducibility
70+
private static final int RANDOM_SEED = 42;
71+
private static final int LENGTH = 10_000;
72+
73+
Random r = new Random(RANDOM_SEED);
74+
long[] longs = r.longs(LENGTH).toArray();
75+
double[] doubles = DoubleStream.concat(
76+
DoubleStream.of(Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, -0.0, 0.0),
77+
r.doubles(LENGTH, -0x1p10, 0x1p+65)).toArray();
78+
79+
double[] doublesValidUI64 = r.doubles(LENGTH, Math.nextUp(-1.0), 0x1p64).toArray();
80+
double[] doublesValidSI64 = r.doubles(LENGTH, -0x1p63, 0x1p63).toArray();
81+
}
82+
83+
/**
84+
* Signed version as a performance reference point for unsigned.
85+
*/
86+
@Benchmark
87+
public void doubleToSignedLongSat(ThreadState state, Blackhole blackhole) {
88+
for (double input : state.doubles) {
89+
blackhole.consume((long) input);
90+
}
91+
}
92+
93+
@Benchmark
94+
public void doubleToUnsignedLongSat(ThreadState state, Blackhole blackhole) {
95+
for (double input : state.doubles) {
96+
blackhole.consume(ExactMath.truncateToUnsignedLong(input));
97+
}
98+
}
99+
100+
@Benchmark
101+
public void doubleToUnsignedLongSatFallback(ThreadState state, Blackhole blackhole) {
102+
for (double input : state.doubles) {
103+
blackhole.consume(truncateToUnsignedLongFallback(input));
104+
}
105+
}
106+
107+
/**
108+
* Signed version as a performance reference point for unsigned.
109+
*/
110+
@Benchmark
111+
public void doubleToSignedLongChecked(ThreadState state, Blackhole blackhole) {
112+
for (double input : state.doublesValidSI64) {
113+
blackhole.consume(i64_trunc_f64_s(input));
114+
}
115+
}
116+
117+
@Benchmark
118+
public void doubleToUnsignedLongChecked(ThreadState state, Blackhole blackhole) {
119+
for (double input : state.doublesValidUI64) {
120+
blackhole.consume(i64_trunc_f64_u(input));
121+
}
122+
}
123+
124+
/**
125+
* Signed version as a performance reference point for unsigned.
126+
*/
127+
@Benchmark
128+
public void longToDoubleSigned(ThreadState state, Blackhole blackhole) {
129+
for (long input : state.longs) {
130+
blackhole.consume((double) input);
131+
}
132+
}
133+
134+
@Benchmark
135+
public void longToDoubleUnsigned(ThreadState state, Blackhole blackhole) {
136+
for (long input : state.longs) {
137+
blackhole.consume(ExactMath.unsignedToDouble(input));
138+
}
139+
}
140+
141+
@Benchmark
142+
public void longToDoubleUnsignedFallback(ThreadState state, Blackhole blackhole) {
143+
for (long input : state.longs) {
144+
blackhole.consume(unsignedToDoubleFallback(input));
145+
}
146+
}
147+
148+
/**
149+
* @see ExactMath#unsignedToDouble(long)
150+
*/
151+
public static double unsignedToDoubleFallback(long x) {
152+
if (x >= 0) {
153+
return x;
154+
} else {
155+
double halfRoundUp = ((x >>> 1) | (x & 1));
156+
return halfRoundUp + halfRoundUp;
157+
}
158+
}
159+
160+
/**
161+
* @see ExactMath#truncateToUnsignedLong(double)
162+
*/
163+
private static long truncateToUnsignedLongFallback(double x) {
164+
if (x >= 0x1p63) {
165+
long signedResult = (long) (x - 0x1p63);
166+
return signedResult | (1L << 63);
167+
} else {
168+
long signedResult = (long) x;
169+
return signedResult & ~(signedResult >> 63); // max(result, 0)
170+
}
171+
}
172+
173+
private long i64_trunc_f64_u(double x) {
174+
if (x > -1.0 && x < 0x1p64) {
175+
return ExactMath.truncateToUnsignedLong(x);
176+
} else {
177+
return truncError(x);
178+
}
179+
}
180+
181+
private long i64_trunc_f64_s(double x) {
182+
if (x >= -0x1p63 && x < 0x1p63) {
183+
return (long) x;
184+
} else {
185+
return truncError(x);
186+
}
187+
}
188+
189+
private static long truncError(double x) {
190+
CompilerDirectives.transferToInterpreterAndInvalidate();
191+
if (Double.isNaN(x)) {
192+
throw new AssertionError(x);
193+
} else {
194+
throw new AssertionError(x);
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)