Add davecom Entry
This commit is contained in:
parent
8703674765
commit
8a282ab71b
20
calculate_average_davecom.sh
Executable file
20
calculate_average_davecom.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=""
|
||||
time java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_davecom
|
208
src/main/java/dev/morling/onebrc/CalculateAverage_davecom.java
Normal file
208
src/main/java/dev/morling/onebrc/CalculateAverage_davecom.java
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.IOException;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class CalculateAverage_davecom {
|
||||
|
||||
/*
|
||||
* Original Header Could Not Be Changed to Match Checks so...
|
||||
* Copyright 2024 David Kopec
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* Created by David Kopec with some inspiration from seijikun's solution
|
||||
* and assistance from GitHub Copilot.
|
||||
*/
|
||||
|
||||
private static final String FILE = "./measurements.txt";
|
||||
|
||||
private static final ConcurrentHashMap<String, Integer> mins = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, Integer> maxs = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, Integer> sums = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, Integer> counts = new ConcurrentHashMap<>();
|
||||
|
||||
public static void processChunk(MappedByteBuffer chunk, long chunkSize) {
|
||||
// setup
|
||||
chunk.load();
|
||||
HashMap<String, IntSummaryStatistics> values = new HashMap<>();
|
||||
|
||||
// do the actual processing
|
||||
long end = chunk.position() + chunkSize;
|
||||
byte[] name = new byte[128];
|
||||
int value = 0;
|
||||
byte b = 0;
|
||||
boolean negate = false;
|
||||
long nameStart = 0;
|
||||
long nameEnd = 0;
|
||||
int nameLength = 0;
|
||||
while (chunk.position() < end) {
|
||||
// read name up to semicolon
|
||||
nameStart = chunk.position();
|
||||
b = chunk.get();
|
||||
while (b != ';') {
|
||||
b = chunk.get();
|
||||
}
|
||||
nameEnd = chunk.position() - 1;
|
||||
nameLength = (int) (nameEnd - nameStart);
|
||||
// generate byte array for name
|
||||
chunk.get(chunk.position() - nameLength - 1, name, 0, nameLength);
|
||||
// convert name to string
|
||||
String nameString = new String(name, 0, nameLength);
|
||||
// read value
|
||||
value = 0;
|
||||
b = chunk.get();
|
||||
negate = false;
|
||||
while (b != '\n') {
|
||||
if (b == '.') {
|
||||
b = chunk.get();
|
||||
continue;
|
||||
}
|
||||
else if (b == '-') {
|
||||
negate = true;
|
||||
b = chunk.get();
|
||||
continue;
|
||||
}
|
||||
value = value * 10 + (b - '0');
|
||||
b = chunk.get();
|
||||
}
|
||||
if (negate) {
|
||||
value = -value;
|
||||
}
|
||||
|
||||
if (values.containsKey(nameString)) {
|
||||
values.get(nameString).accept(value);
|
||||
}
|
||||
else {
|
||||
IntSummaryStatistics stats = new IntSummaryStatistics();
|
||||
stats.accept(value);
|
||||
values.put(nameString, stats);
|
||||
}
|
||||
}
|
||||
|
||||
for (String nameStr : values.keySet()) {
|
||||
IntSummaryStatistics stats = values.get(nameStr);
|
||||
mins.compute(nameStr, (k, v) -> v == null ? stats.getMin() : Math.min(v, stats.getMin()));
|
||||
maxs.compute(nameStr, (k, v) -> v == null ? stats.getMax() : Math.max(v, stats.getMax()));
|
||||
sums.compute(nameStr, (k, v) -> v == null ? (int) stats.getSum() : (v + (int) stats.getSum()));
|
||||
counts.compute(nameStr, (k, v) -> v == null ? (int) stats.getCount() : (v + (int) stats.getCount()));
|
||||
}
|
||||
}
|
||||
|
||||
public static void outputResults() {
|
||||
// output results sorted by name with format {name}={min}/{mean}/{max} in one giant string
|
||||
// fast string concatenation starting with { and ending with } with a comma between each (no newlines)
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('{');
|
||||
var sortedNames = mins.keySet().stream().sorted().toArray(String[]::new);
|
||||
DecimalFormat df = new DecimalFormat("0.0");
|
||||
df.setRoundingMode(RoundingMode.HALF_UP);
|
||||
for (String name : sortedNames) {
|
||||
double min = ((double) mins.get(name)) / 10;
|
||||
double max = ((double) maxs.get(name)) / 10;
|
||||
double average = ((double) sums.get(name)) / ((double) counts.get(name)) / 10;
|
||||
sb.append(name);
|
||||
sb.append('=');
|
||||
sb.append(df.format(min));
|
||||
sb.append('/');
|
||||
sb.append(df.format(average));
|
||||
sb.append('/');
|
||||
sb.append(df.format(max));
|
||||
sb.append(',');
|
||||
sb.append(' ');
|
||||
}
|
||||
if (sb.length() > 1) {
|
||||
sb.deleteCharAt(sb.length() - 2);
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
}
|
||||
sb.append('}');
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
// create thread pool
|
||||
ExecutorService es = Executors.newVirtualThreadPerTaskExecutor();
|
||||
|
||||
// load file
|
||||
FileChannel fc = FileChannel.open(Path.of(FILE));
|
||||
|
||||
// configuration information
|
||||
long fileSize = fc.size();
|
||||
int numProcessors = Runtime.getRuntime().availableProcessors();
|
||||
int numChunks = numProcessors * 2000;
|
||||
// System.out.println("numProcessors: " + numProcessors);
|
||||
// System.out.println("numChunks: " + numChunks);
|
||||
|
||||
// create check buffer
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(128);
|
||||
|
||||
// find appropriate chunks
|
||||
// System.out.println("fileSize: " + fileSize);
|
||||
long chunkLimit = fileSize / numChunks;
|
||||
long chunkStart = 0;
|
||||
long chunkEnd = chunkLimit;
|
||||
// int chunkNum = 0;
|
||||
while (chunkEnd < fileSize) {
|
||||
// System.out.println("initiated chunkNum: " + chunkNum);
|
||||
// find the next newline
|
||||
fc.position(chunkEnd);
|
||||
bb.clear();
|
||||
fc.read(bb);
|
||||
bb.flip();
|
||||
while (bb.get() != '\n' && bb.position() < bb.limit()) {
|
||||
}
|
||||
chunkEnd = chunkEnd + bb.position();
|
||||
if (chunkEnd > fileSize) {
|
||||
chunkEnd = fileSize - 1;
|
||||
}
|
||||
// process chunk
|
||||
long chunkSize = chunkEnd - chunkStart;
|
||||
if (chunkSize < 1) {
|
||||
break;
|
||||
}
|
||||
// System.out.println("chunkStart: " + chunkStart);
|
||||
// System.out.println("chunkEnd: " + chunkEnd);
|
||||
// System.out.println("chunkSize: " + chunkSize);
|
||||
MappedByteBuffer chunk = fc.map(FileChannel.MapMode.READ_ONLY, chunkStart, chunkSize);
|
||||
// final int chunkNumFinal = chunkNum;
|
||||
es.submit(() -> {
|
||||
// System.out.println("started chunkNum: " + chunkNumFinal);
|
||||
processChunk(chunk, chunkSize);
|
||||
// System.out.println("finished chunkNum: " + chunkNumFinal);
|
||||
});
|
||||
chunkStart = chunkEnd;
|
||||
chunkEnd = chunkEnd + chunkLimit;
|
||||
if (chunkEnd > fileSize) {
|
||||
chunkEnd = fileSize - 1;
|
||||
}
|
||||
// chunkNum++;
|
||||
}
|
||||
es.close();
|
||||
|
||||
outputResults();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user