Skip to content

Commit e2ee4cb

Browse files
authored
give in to the graal (gunnarmorling#660)
1 parent 5728ca9 commit e2ee4cb

File tree

3 files changed

+74
-58
lines changed

3 files changed

+74
-58
lines changed

calculate_average_iziamos.sh

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,18 @@
1515
# limitations under the License.
1616
#
1717

18-
JAVA_OPTS="--enable-preview
19-
-XX:+UnlockExperimentalVMOptions \
20-
-XX:+UseEpsilonGC -Xms16m -Xmx16m -XX:-AlwaysPreTouch \
21-
-XX:-TieredCompilation -XX:CICompilerCount=1 -XX:CompilationMode=high-only \
22-
-XX:C1MaxTrivialSize=500 -XX:-UseCountedLoopSafepoints -XX:+UseCMoveUnconditionally -XX:+DisableAttachMechanism \
23-
-XX:-PreserveFramePointer -Xnoclassgc -disablesystemassertions -XX:-UsePerfData \
24-
-XX:-UseTransparentHugePages -XX:-UseCompressedOops"
25-
java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_iziamos
18+
19+
if [ -f target/CalculateAverage_iziamos_image ]; then
20+
echo "Using graal" 1>&2
21+
target/CalculateAverage_iziamos_image
22+
else
23+
echo "Using openjdk" 1>&2
24+
JAVA_OPTS="--enable-preview
25+
-XX:+UnlockExperimentalVMOptions \
26+
-XX:+UseEpsilonGC -Xms16m -Xmx16m -XX:-AlwaysPreTouch \
27+
-XX:-TieredCompilation -XX:CICompilerCount=1 -XX:CompilationMode=high-only \
28+
-XX:C1MaxTrivialSize=500 -XX:-UseCountedLoopSafepoints -XX:+UseCMoveUnconditionally -XX:+DisableAttachMechanism \
29+
-XX:-PreserveFramePointer -Xnoclassgc -disablesystemassertions -XX:-UsePerfData \
30+
-XX:-UseTransparentHugePages -XX:-UseCompressedOops"
31+
java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_iziamos
32+
fi

prepare_iziamos.sh

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
#
3+
# Copyright 2023 The original authors
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
source "$HOME/.sdkman/bin/sdkman-init.sh"
19+
sdk use java 21.0.2-graal 1>&2
20+
21+
if [ ! -f target/CalculateAverage_iziamos_image ]; then
22+
NATIVE_IMAGE_OPTS="-H:+UnlockExperimentalVMOptions --gc=epsilon -O3 -march=native -R:MaxHeapSize=64m -H:-GenLoopSafepoints --enable-preview -H:InlineAllBonus=10 -H:-ParseRuntimeOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_iziamos"
23+
native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_iziamos_image dev.morling.onebrc.CalculateAverage_iziamos
24+
fi

src/main/java/dev/morling/onebrc/CalculateAverage_iziamos.java

Lines changed: 35 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,9 @@
1515
*/
1616
package dev.morling.onebrc;
1717

18-
import sun.misc.Unsafe;
19-
2018
import java.io.IOException;
19+
import java.io.UncheckedIOException;
2120
import java.lang.foreign.Arena;
22-
import java.lang.foreign.MemorySegment;
23-
import java.lang.reflect.Field;
2421
import java.nio.ByteOrder;
2522
import java.nio.channels.FileChannel;
2623
import java.nio.file.Files;
@@ -34,45 +31,42 @@
3431
import static java.nio.file.StandardOpenOption.READ;
3532

3633
public class CalculateAverage_iziamos {
37-
private static final Unsafe UNSAFE;
34+
private static final sun.misc.Unsafe UNSAFE = initUnsafe();
3835

39-
private static final String FILE = "./measurements.txt";
40-
private static final Arena GLOBAL_ARENA = Arena.global();
41-
private final static MemorySegment WHOLE_FILE_SEGMENT;
42-
private final static long FILE_SIZE;
43-
private final static long BASE_POINTER;
44-
private final static long END_POINTER;
45-
46-
static {
36+
private static sun.misc.Unsafe initUnsafe() {
4737
try {
48-
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
38+
java.lang.reflect.Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
4939
theUnsafe.setAccessible(true);
50-
UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);
51-
52-
final var fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE), READ);
53-
WHOLE_FILE_SEGMENT = fileChannel.map(READ_ONLY, 0, fileChannel.size(), GLOBAL_ARENA);
54-
40+
return (sun.misc.Unsafe) theUnsafe.get(sun.misc.Unsafe.class);
5541
}
56-
catch (final NoSuchFieldException | IllegalAccessException | IOException e) {
42+
catch (NoSuchFieldException | IllegalAccessException e) {
5743
throw new RuntimeException(e);
5844
}
59-
60-
FILE_SIZE = WHOLE_FILE_SEGMENT.byteSize();
61-
BASE_POINTER = WHOLE_FILE_SEGMENT.address();
62-
END_POINTER = BASE_POINTER + FILE_SIZE;
6345
}
6446

65-
private static final long CHUNK_SIZE = 64 * 1024 * 1024;
66-
// private static final long CHUNK_SIZE = Long.MAX_VALUE;
47+
private static final String FILE = "./measurements.txt";
48+
private static final Arena GLOBAL_ARENA = Arena.global();
6749

6850
public static void main(String[] args) throws Exception {
69-
// Thread.sleep(10_000);
51+
// final long chunkSize = Long.MAX_VALUE;
52+
final long chunkSize = 64 * 1024 * 1024;
53+
54+
final FileChannel fileChannel;
55+
try {
56+
fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE), READ);
57+
}
58+
catch (final IOException e) {
59+
throw new UncheckedIOException(e);
60+
}
7061

71-
final long threadCount = 1 + FILE_SIZE / CHUNK_SIZE;
62+
final var seg = fileChannel.map(READ_ONLY, 0, fileChannel.size(), GLOBAL_ARENA);
63+
64+
final long fileSize = seg.byteSize();
65+
final long threadCount = 1 + fileSize / chunkSize;
7266

7367
final var processingFutures = new CompletableFuture[(int) threadCount];
7468
for (int i = 0; i < threadCount; ++i) {
75-
processingFutures[i] = processSegment(i, CHUNK_SIZE);
69+
processingFutures[i] = processSegment(seg.address(), seg.address() + fileSize, i, chunkSize);
7670
}
7771

7872
final long aggregate = (long) processingFutures[0].get();
@@ -102,15 +96,18 @@ private double round(double value) {
10296
}
10397
}
10498

105-
private static CompletableFuture<Long> processSegment(final long chunkNumber, final long chunkSize) {
99+
private static CompletableFuture<Long> processSegment(final long basePointer,
100+
final long endPointer,
101+
final long chunkNumber,
102+
final long chunkSize) {
106103
final var ret = new CompletableFuture<Long>();
107104

108105
Thread.ofVirtual().start(() -> {
109106
final long relativeStart = chunkNumber * chunkSize;
110-
final long absoluteStart = BASE_POINTER + relativeStart;
107+
final long absoluteStart = basePointer + relativeStart;
111108

112-
final long absoluteEnd = computeAbsoluteEndWithSlack(absoluteStart + chunkSize);
113-
final long startOffsetAfterSkipping = skipIncomplete(WHOLE_FILE_SEGMENT.address(), absoluteStart);
109+
final long absoluteEnd = computeAbsoluteEndWithSlack(absoluteStart + chunkSize, endPointer);
110+
final long startOffsetAfterSkipping = skipIncomplete(basePointer, absoluteStart);
114111

115112
final long result = processEvents(startOffsetAfterSkipping, absoluteEnd);
116113
ret.complete(result);
@@ -119,8 +116,8 @@ private static CompletableFuture<Long> processSegment(final long chunkNumber, fi
119116
return ret;
120117
}
121118

122-
private static long computeAbsoluteEndWithSlack(final long chunk) {
123-
return Long.compareUnsigned(END_POINTER, chunk) > 0 ? chunk : END_POINTER;
119+
private static long computeAbsoluteEndWithSlack(final long chunk, final long endPointer) {
120+
return Long.compareUnsigned(endPointer, chunk) > 0 ? chunk : endPointer;
124121
}
125122

126123
private static long skipIncomplete(final long basePointer, final long start) {
@@ -142,7 +139,7 @@ private static long processEvents(final long start, final long limit) {
142139
}
143140

144141
private static void scalarLoop(final long start, final long limit, final long result) {
145-
final LoopCursor cursor = new ScalarLoopCursor(start, limit);
142+
final LoopCursor cursor = new LoopCursor(start, limit);
146143
while (cursor.hasMore()) {
147144
final long address = cursor.getCurrentAddress();
148145
final int length = cursor.getStringLength();
@@ -152,25 +149,13 @@ private static void scalarLoop(final long start, final long limit, final long re
152149
}
153150
}
154151

155-
public interface LoopCursor {
156-
long getCurrentAddress();
157-
158-
int getStringLength();
159-
160-
int getHash();
161-
162-
int getCurrentValue();
163-
164-
boolean hasMore();
165-
}
166-
167-
public static class ScalarLoopCursor implements LoopCursor {
152+
public static class LoopCursor {
168153
private long pointer;
169154
private final long limit;
170155

171156
private int hash = 0;
172157

173-
public ScalarLoopCursor(final long pointer, final long limit) {
158+
public LoopCursor(final long pointer, final long limit) {
174159
this.pointer = pointer;
175160
this.limit = limit;
176161
}

0 commit comments

Comments
 (0)