From d8b071c878b8a3a7cfd9451fe8c6bd9deb4d3ebf Mon Sep 17 00:00:00 2001 From: Roy van Rijn Date: Sun, 21 Jan 2024 11:15:07 -0800 Subject: [PATCH] Reverting ByteBuffer idea, using Thomas's trick instead. (#538) --- prepare_royvanrijn.sh | 2 +- .../onebrc/CalculateAverage_royvanrijn.java | 44 +++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/prepare_royvanrijn.sh b/prepare_royvanrijn.sh index ba89535..a9789d6 100755 --- a/prepare_royvanrijn.sh +++ b/prepare_royvanrijn.sh @@ -16,7 +16,7 @@ # source "$HOME/.sdkman/bin/sdkman-init.sh" -sdk use java 21.0.1-graal 1>&2 +sdk use java 21.0.2-graal 1>&2 # ./mvnw clean verify removes target/ and will re-trigger native image creation. if [ ! -f target/CalculateAverage_royvanrijn_image ]; then diff --git a/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java b/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java index b392e58..6800456 100644 --- a/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java +++ b/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java @@ -15,12 +15,15 @@ */ package dev.morling.onebrc; +import java.io.IOException; import java.lang.foreign.Arena; import java.lang.reflect.Field; import java.nio.channels.FileChannel; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -102,8 +105,27 @@ public class CalculateAverage_royvanrijn { private static final int TABLE_SIZE = 1 << 19; // large enough for the contest. private static final int TABLE_MASK = (TABLE_SIZE - 1); - public static void main(String[] args) throws Exception { + // Idea of thomaswue, don't wait for slow unmap: + private static void spawnWorker() throws IOException { + ProcessHandle.Info info = ProcessHandle.current().info(); + ArrayList workerCommand = new ArrayList<>(); + info.command().ifPresent(workerCommand::add); + info.arguments().ifPresent(args -> workerCommand.addAll(Arrays.asList(args))); + workerCommand.add("--worker"); + new ProcessBuilder() + .command(workerCommand) + .inheritIO() + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .start() + .getInputStream() + .transferTo(System.out); + } + public static void main(String[] args) throws Exception { + if (args.length == 0 || !("--worker".equals(args[0]))) { + spawnWorker(); + return; + } // Calculate input segments. final FileChannel fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ); final long fileSize = fileChannel.size(); @@ -159,7 +181,7 @@ public class CalculateAverage_royvanrijn { .collect(Collectors.joining(", "))); System.out.println("}"); - // System.out.println(measurements.entrySet().stream().mapToLong(e -> UNSAFE.getInt(e.getValue(), ENTRY_COUNT + Unsafe.ARRAY_BYTE_BASE_OFFSET)).sum()); + System.out.close(); // close the stream to stop } private static byte[] fillEntry(final byte[] entry, final long fromAddress, final int length, final int temp) { @@ -176,15 +198,15 @@ public class CalculateAverage_royvanrijn { int entryMin = UNSAFE.getInt(entry, ENTRY_MIN); int entryMax = UNSAFE.getInt(entry, ENTRY_MAX); - - entryMin = Math.min(temp, entryMin); - entryMax = Math.max(temp, entryMax); - long entrySum = UNSAFE.getLong(entry, ENTRY_SUM) + temp; int entryCount = UNSAFE.getInt(entry, ENTRY_COUNT) + 1; - UNSAFE.putInt(entry, ENTRY_MIN, entryMin); - UNSAFE.putInt(entry, ENTRY_MAX, entryMax); + if (temp < entryMin) { + UNSAFE.putInt(entry, ENTRY_MIN, temp); + } + else if (temp > entryMax) { + UNSAFE.putInt(entry, ENTRY_MAX, temp); + } UNSAFE.putInt(entry, ENTRY_COUNT, entryCount); UNSAFE.putLong(entry, ENTRY_SUM, entrySum); } @@ -435,6 +457,8 @@ public class CalculateAverage_royvanrijn { reader.processStart(); if (!reader.readFirst()) { + // Found delimiter in first 8 bytes: + int temperature = reader.processEndAndGetTemperature(); // Find or insert the entry: @@ -462,6 +486,7 @@ public class CalculateAverage_royvanrijn { reader.processName(); if (!reader.readNext()) { + // Found delimiter in 8-16 bytes: int temperature = reader.processEndAndGetTemperature(); @@ -490,6 +515,8 @@ public class CalculateAverage_royvanrijn { reader.processName(); if (!reader.readNext()) { + // Found delimiter in 16-24 bytes: + int temperature = reader.processEndAndGetTemperature(); // Find or insert the entry: @@ -515,6 +542,7 @@ public class CalculateAverage_royvanrijn { } else { + // Need more than 24 bytes: reader.processName(); while (reader.readNext()) {