Adding Moysés Borges Furtado's submission
This commit is contained in:
parent
e5d074651f
commit
acb6510a02
20
calculate_average_moysesb.sh
Executable file
20
calculate_average_moysesb.sh
Executable file
@ -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="-XX:+UseZGC --enable-preview"
|
||||||
|
time java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_moysesb
|
201
src/main/java/dev/morling/onebrc/CalculateAverage_moysesb.java
Normal file
201
src/main/java/dev/morling/onebrc/CalculateAverage_moysesb.java
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* 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.lang.foreign.Arena;
|
||||||
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.lang.foreign.ValueLayout;
|
||||||
|
import java.nio.BufferUnderflowException;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorCompletionService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
public class CalculateAverage_moysesb {
|
||||||
|
|
||||||
|
private static final String FILE = "./measurements.txt";
|
||||||
|
|
||||||
|
static class ByteArray {
|
||||||
|
final byte[] value;
|
||||||
|
final int hashCode;
|
||||||
|
|
||||||
|
private ByteArray(byte[] val, int hashCode) {
|
||||||
|
this.value = val;
|
||||||
|
this.hashCode = hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof ByteArray other) {
|
||||||
|
return this == other || hashCode == other.hashCode && Arrays.equals(value, other.value);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final Map<ByteArray, double[]> allResults = new HashMap<>(512);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
|
||||||
|
int ncpus = Runtime.getRuntime().availableProcessors();
|
||||||
|
ExecutorCompletionService<Map<ByteArray, double[]>> exec = new ExecutorCompletionService<>(Executors.newFixedThreadPool(ncpus));
|
||||||
|
var file = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);
|
||||||
|
File f = new File(FILE);
|
||||||
|
long fileSize = f.length();
|
||||||
|
long split = 0;
|
||||||
|
long chunkSize = Math.min(1 << 28, fileSize < 1 << 28 ? fileSize : (fileSize / ncpus));
|
||||||
|
List<Future<Map<ByteArray, double[]>>> tasks = new ArrayList<>();
|
||||||
|
|
||||||
|
while (split < fileSize) {
|
||||||
|
final long[] offset = {split};
|
||||||
|
var task = exec.submit(() -> {
|
||||||
|
try {
|
||||||
|
final Map<ByteArray, double[]> results = new HashMap<>(512);
|
||||||
|
file:
|
||||||
|
for (; ; ) {
|
||||||
|
long chunk = Math.min(fileSize - offset[0], chunkSize);
|
||||||
|
if (chunk == 0) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
MemorySegment mm = file.map(FileChannel.MapMode.READ_ONLY, offset[0], chunk, Arena.ofConfined());
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
if (offset[0] > 0) {
|
||||||
|
while (mm.get(ValueLayout.JAVA_BYTE, i) != '\n') {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (i < chunk) {
|
||||||
|
try {
|
||||||
|
byte[] city = new byte[32];
|
||||||
|
byte[] valb = new byte[16];
|
||||||
|
byte[] target = city;
|
||||||
|
double val = 0d;
|
||||||
|
int dotOffset = 0;
|
||||||
|
int l = 0;
|
||||||
|
int nameHash = 0;
|
||||||
|
for (; ; ) {
|
||||||
|
byte b = mm.get(ValueLayout.OfByte.JAVA_BYTE, i++);
|
||||||
|
if (b == ';') {
|
||||||
|
target = valb;
|
||||||
|
l = 0;
|
||||||
|
} else if (b == '\n') {
|
||||||
|
int integral = 0;
|
||||||
|
int mult = 1;
|
||||||
|
int frac = 0;
|
||||||
|
for (int ii = 0; ii < dotOffset; ii++) {
|
||||||
|
if (valb[ii] == '-') {
|
||||||
|
mult = -1;
|
||||||
|
} else {
|
||||||
|
integral = integral * 10 + (valb[ii] - '0');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int ii = dotOffset+1; ii < l; ii++) {
|
||||||
|
frac = frac * 10 + (valb[ii] - '0');
|
||||||
|
}
|
||||||
|
val = integral;
|
||||||
|
if (frac > 0)
|
||||||
|
val += (frac/10d);
|
||||||
|
|
||||||
|
val *= mult;
|
||||||
|
var ba = new ByteArray(city, nameHash);
|
||||||
|
|
||||||
|
var r = results.computeIfAbsent(ba, _s -> new double[]{1000, -1000, 0, 0});
|
||||||
|
r[0] = Math.min(r[0], val);
|
||||||
|
r[1] = Math.max(r[1], val);
|
||||||
|
r[2]++;
|
||||||
|
r[3] += val;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (target == city) {
|
||||||
|
nameHash = nameHash * 31 + b;
|
||||||
|
} else if (b == '.') {
|
||||||
|
dotOffset = l;
|
||||||
|
}
|
||||||
|
target[l++] = b;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (BufferUnderflowException | IndexOutOfBoundsException e) {
|
||||||
|
//happens on the last segment after EOF
|
||||||
|
break file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset[0] += i;
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tasks.add(task);
|
||||||
|
split += chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int taken = 0;
|
||||||
|
while (taken < tasks.size()) {
|
||||||
|
Future<Map<ByteArray, double[]>> fut = exec.take();
|
||||||
|
var map = fut.get();
|
||||||
|
taken++;
|
||||||
|
if (map == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Map.Entry<ByteArray, double[]> e : map.entrySet()) {
|
||||||
|
var ba = e.getKey();
|
||||||
|
var val = e.getValue();
|
||||||
|
allResults.merge(ba, val, (old, _new) -> {
|
||||||
|
old[0] = Math.min(old[0], _new[0]);
|
||||||
|
old[1] = Math.max(old[1], _new[1]);
|
||||||
|
old[2] += _new[2];
|
||||||
|
old[3] += _new[3];
|
||||||
|
return old;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SortedMap<String, String> sorted = new TreeMap<>();
|
||||||
|
for (Map.Entry<ByteArray, double[]> e : allResults.entrySet()) {
|
||||||
|
byte[] utf8 = e.getKey().value;
|
||||||
|
int strlen = 0;
|
||||||
|
while (utf8[strlen] != '\0') strlen++;
|
||||||
|
String city = new String(utf8, 0, strlen, StandardCharsets.UTF_8);
|
||||||
|
double[] r = e.getValue();
|
||||||
|
String fmt = FormatProcessor.FMT."%.1f\{round(r[0])}/%.1f\{round(r[3]/r[2])}/%.1f\{round(r[1])}";
|
||||||
|
sorted.put(city, fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(sorted);
|
||||||
|
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double round(double d) {
|
||||||
|
return Math.round(d * 10.0) / 10.0;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user