Skip to content

Commit

Permalink
Merge branch 'gunnarmorling:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
ebarlas authored Jan 3, 2024
2 parents 961d8cd + a5cc174 commit 20bacae
Show file tree
Hide file tree
Showing 7 changed files with 646 additions and 9 deletions.
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,19 @@ Submit your implementation by Jan 31 2024 and become part of the leaderboard!

## Results

| # | Result (m:s:ms) | Implementation | Submitter |
|---|-----------------|--------------------|---------------|
| 1.| 00:23.366| [link](https://github.com/gunnarmorling/1brc/pull/5/)| [Roy van Rijn](https://github.com/royvanrijn)|
| 2.| 00:38.510| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_bjhara.java)| [Hampus Ram](https://github.com/bjhara)|
| 3.| 00:50.547| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_padreati.java)| [Aurelian Tutuianu](https://github.com/padreati)|
| 4.| 02:08.315| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_itaske.java)| [itaske](https://github.com/itaske)|
| 5.| 02:08.650| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java)| [Kuduwa Keshavram](https://github.com/kuduwa_keshavram)|
| 6.| 04:13.449| [link](https://github.com/gunnarmorling/onebrc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage.java) (baseline)| [Gunnar Morling](https://github.com/gunnarmorling)|
| # | Result (m:s.ms) | Implementation | JDK | Submitter |
|---|-----------------|--------------------|-----|---------------|
| 1.| 00:14.848| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_spullara.java)| 21.0.1-graalce| [Sam Pullara](https://github.com/spullara)|
| 2.| 00:16.558| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ebarlas.java)| 21.0.1-open| [Elliot Barlas](https://github.com/ebarlas)|
| 3.| 00:18.865| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_palmr.java)| 21.0.1-open| [Nick Palmer](https://github.com/palmr)|
| 4.| 00:23.366| [link](https://github.com/gunnarmorling/1brc/pull/5/)| 21.0.1-open | [Roy van Rijn](https://github.com/royvanrijn)|
| 5.| 00:38.510| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_bjhara.java)| 21.0.1-open | [Hampus Ram](https://github.com/bjhara)|
| 6.| 00:50.547| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_padreati.java)| 21.0.1-open | [Aurelian Tutuianu](https://github.com/padreati)|
| 7.| 00:53.679| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_criccomini.java)| 21.0.1-open | [Chris Riccomini](https://github.com/criccomini)|
| 8.| 00:57.141| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_truelive.java)| 21.0.1-open | [Roman Schweitzer](https://github.com/truelive)|
| 9.| 02:08.315| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_itaske.java)| 21.0.1-open | [itaske](https://github.com/itaske)|
|10.| 02:08.650| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java)| 21.0.1-open | [Kuduwa Keshavram](https://github.com/kuduwa_keshavram)|
|11.| 04:13.449| [link](https://github.com/gunnarmorling/onebrc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage.java) (baseline)| 21.0.1-open | [Gunnar Morling](https://github.com/gunnarmorling)|

See [below](#entering-the-challenge) for instructions how to enter the challenge with your own implementation.

Expand Down Expand Up @@ -116,7 +121,7 @@ To submit your own implementation to 1BRC, follow these steps:
* The execution time of the program on your system and specs of the same (CPU, number of cores, RAM). This is for informative purposes only, the official runtime will be determined as described below.
* I will run the program and determine its performance as described in the next section, and enter the result to the scoreboard.
**Note:** I reserve the right to not evaluate specific submissions if I feel doubtful about the implementation (I.e. I won't run your BitCoin miner ;).
**Note:** I reserve the right to not evaluate specific submissions if I feel doubtful about the implementation (I.e. I won't run your Bitcoin miner ;).
If you'd like to discuss any potential ideas for implementing 1BRC with the community,
you can use the [GitHub Discussions](https://github.com/gunnarmorling/onebrc/discussions) of this repository.
Expand Down Expand Up @@ -150,6 +155,9 @@ A: No, this challenge is focussed on Java only. Feel free to inofficially share
_Q: Can I use non-JVM languages and/or tools?_\
A: No, this challenge is focussed on Java only. Feel free to inofficially share interesting implementations and results though. For instance it would be interesting to see how DuckDB fares with this task.
_Q: I've got an implementation—but it's not in Java. Can I share it somewhere?_\
A: Whilst non-Java solutions cannot be formally submitted to the challenge, you are welcome to share them over in the [Show and tell](https://github.com/gunnarmorling/1brc/discussions/categories/show-and-tell) GitHub discussion area.
_Q: Can I use JNI?_\
A: Submissions must be completely implemented in Java, i.e. you cannot write JNI glue code in C/C++. You could use AOT compilation of Java code via GraalVM though, either by AOT-compiling the entire application, or by creating a native library (see [here](https://www.graalvm.org/22.0/reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM/).
Expand Down
21 changes: 21 additions & 0 deletions calculate_average_criccomini.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/sh
#
# Copyright 2023 The original authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


#JAVA_OPTS="-XX:+UseZGC -server -Xms700m -Xlog:gc"
JAVA_OPTS="-XX:+UseZGC -Xms700m"
time java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_criccomini
20 changes: 20 additions & 0 deletions calculate_average_palmr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh
#
# Copyright 2023 The original authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


JAVA_OPTS="--enable-preview"
time java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_palmr
20 changes: 20 additions & 0 deletions calculate_average_truelive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh
#
# Copyright 2023 The original authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


JAVA_OPTS="-Xmx4G"
time java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_truelive
113 changes: 113 additions & 0 deletions src/main/java/dev/morling/onebrc/CalculateAverage_criccomini.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright 2023 The original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dev.morling.onebrc;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.*;

public class CalculateAverage_criccomini {

private static final String FILE = "./measurements.txt";
private static final long FILE_SIZE = new File(FILE).length();
private static final long SEGMENT_SIZE = 256_000_000;

private static class MeasurementAggregator {
private double min = Double.POSITIVE_INFINITY;
private double max = Double.NEGATIVE_INFINITY;
private double sum;
private long count;

public String toString() {
return round(min) + "/" + round(sum / count) + "/" + round(max);
}

private double round(double value) {
return Math.round(value * 10.0) / 10.0;
}
}

private static Map<String, MeasurementAggregator> processSegment(MappedByteBuffer buffer, int length) {
Map<String, MeasurementAggregator> aggregates = new HashMap<>();
int lineStart = 0;
int doubleStart = 0;
String station = null;
for (int i = 0; i < length; ++i) {
byte b = buffer.get(i);
if (b == ';') {
byte[] stationBuffer = new byte[i - lineStart];
buffer.position(lineStart);
buffer.get(stationBuffer);
station = new String(stationBuffer, StandardCharsets.UTF_8);
doubleStart = i + 1;
}
else if (b == '\n') {
byte[] doubleBuffer = new byte[i - doubleStart];
buffer.position(doubleStart);
buffer.get(doubleBuffer);
Double temperature = Double.parseDouble(new String(doubleBuffer));
lineStart = i + 1;

MeasurementAggregator aggregator = aggregates.computeIfAbsent(station, s -> new MeasurementAggregator());
aggregator.min = Math.min(aggregator.min, temperature);
aggregator.max = Math.max(aggregator.max, temperature);
aggregator.sum += temperature;
aggregator.count++;
}
}
return aggregates;
}

public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(128);
RandomAccessFile file = new RandomAccessFile(FILE, "r");
long position = 0;
List<Future<Map<String, MeasurementAggregator>>> futures = new ArrayList<>();
while (position < FILE_SIZE) {
int end = (int) Math.min(position + SEGMENT_SIZE, FILE_SIZE);
int length = (int) (end - position);
MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, position, length);
while (buffer.get(length - 1) != '\n') {
--length;
}
position += length;
int finalLength = length;
futures.add(executor.submit(() -> processSegment(buffer, finalLength)));
}

executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

// Merge results into a single TreeMap<String, MeasurementAggregator>
Map<String, MeasurementAggregator> aggregates = new TreeMap<>();
for (Future<Map<String, MeasurementAggregator>> future : futures) {
Map<String, MeasurementAggregator> segmentAggregates = future.get();
for (Map.Entry<String, MeasurementAggregator> entry : segmentAggregates.entrySet()) {
MeasurementAggregator aggregator = aggregates.computeIfAbsent(entry.getKey(), s -> new MeasurementAggregator());
aggregator.min = Math.min(aggregator.min, entry.getValue().min);
aggregator.max = Math.max(aggregator.max, entry.getValue().max);
aggregator.sum += entry.getValue().sum;
aggregator.count += entry.getValue().count;
}
}
System.out.println(aggregates);
}
}
Loading

0 comments on commit 20bacae

Please sign in to comment.