Improve scheduling for thomaswue (#358)

* Improve scheduling for another 6%.

* Tune hash function and collision handling.
This commit is contained in:
Thomas Wuerthinger 2024-01-15 20:43:12 +01:00 committed by GitHub
parent c926aab444
commit be179dcf07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -32,10 +32,10 @@ import java.util.stream.IntStream;
* Simple solution that memory maps the input file, then splits it into one segment per available core and uses * Simple solution that memory maps the input file, then splits it into one segment per available core and uses
* sun.misc.Unsafe to directly access the mapped memory. Uses a long at a time when checking for collision. * sun.misc.Unsafe to directly access the mapped memory. Uses a long at a time when checking for collision.
* <p> * <p>
* Runs in 0.66s on my Intel i9-13900K * Runs in 0.60s on my Intel i9-13900K
* Perf stats: * Perf stats:
* 35,935,262,091 cpu_core/cycles/ * 34,716,719,245 cpu_core/cycles/
* 47,305,591,173 cpu_atom/cycles/ * 40,776,530,892 cpu_atom/cycles/
*/ */
public class CalculateAverage_thomaswue { public class CalculateAverage_thomaswue {
private static final String FILE = "./measurements.txt"; private static final String FILE = "./measurements.txt";
@ -112,25 +112,33 @@ public class CalculateAverage_thomaswue {
// Main parse loop. // Main parse loop.
private static Result[] parseLoop(long chunkStart, long chunkEnd) { private static Result[] parseLoop(long chunkStart, long chunkEnd) {
Result[] results = new Result[1 << 18]; Result[] results = new Result[1 << 17];
Scanner scanner = new Scanner(chunkStart, chunkEnd); Scanner scanner = new Scanner(chunkStart, chunkEnd);
long word = scanner.getLong();
int pos = findDelimiter(word);
while (scanner.hasNext()) { while (scanner.hasNext()) {
long nameAddress = scanner.pos(); long nameAddress = scanner.pos();
long hash = 0; long hash = 0;
// Search for ';', one long at a time. // Search for ';', one long at a time.
long word = scanner.getLong();
int pos = findDelimiter(word);
if (pos != 8) { if (pos != 8) {
scanner.add(pos); scanner.add(pos);
word = mask(word, pos); word = mask(word, pos);
hash ^= word; hash = word;
int number = scanNumber(scanner);
long nextWord = scanner.getLong();
int nextPos = findDelimiter(nextWord);
Result existingResult = results[hashToIndex(hash, results)]; Result existingResult = results[hashToIndex(hash, results)];
if (existingResult != null && existingResult.lastNameLong == word) { if (existingResult != null && existingResult.lastNameLong == word) {
scanAndRecord(scanner, existingResult); word = nextWord;
pos = nextPos;
record(existingResult, number);
continue; continue;
} }
scanner.setPos(nameAddress + pos);
} }
else { else {
scanner.add(8); scanner.add(8);
@ -142,9 +150,13 @@ public class CalculateAverage_thomaswue {
scanner.add(pos); scanner.add(pos);
word = mask(word, pos); word = mask(word, pos);
hash ^= word; hash ^= word;
Result existingResult = results[hashToIndex(hash, results)]; Result existingResult = results[hashToIndex(hash, results)];
if (existingResult != null && existingResult.lastNameLong == word && existingResult.secondLastNameLong == prevWord) { if (existingResult != null && existingResult.lastNameLong == word && existingResult.secondLastNameLong == prevWord) {
scanAndRecord(scanner, existingResult); int number = scanNumber(scanner);
word = scanner.getLong();
pos = findDelimiter(word);
record(existingResult, number);
continue; continue;
} }
} }
@ -188,7 +200,7 @@ public class CalculateAverage_thomaswue {
int i = 0; int i = 0;
for (; i < nameLength + 1 - 8; i += 8) { for (; i < nameLength + 1 - 8; i += 8) {
if (scanner.getLongAt(existingResult.nameAddress + i) != scanner.getLongAt(nameAddress + i)) { if (scanner.getLongAt(existingResult.nameAddress + i) != scanner.getLongAt(nameAddress + i)) {
tableIndex = (tableIndex + 1) & (results.length - 1); tableIndex = (tableIndex + 31) & (results.length - 1);
continue outer; continue outer;
} }
} }
@ -198,20 +210,23 @@ public class CalculateAverage_thomaswue {
} }
else { else {
// Collision error, try next. // Collision error, try next.
tableIndex = (tableIndex + 1) & (results.length - 1); tableIndex = (tableIndex + 31) & (results.length - 1);
} }
} }
word = scanner.getLong();
pos = findDelimiter(word);
} }
return results; return results;
} }
private static void scanAndRecord(Scanner scanPtr, Result existingResult) { private static int scanNumber(Scanner scanPtr) {
scanPtr.add(1); scanPtr.add(1);
long numberWord = scanPtr.getLong(); long numberWord = scanPtr.getLong();
int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000); int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);
int number = convertIntoNumber(decimalSepPos, numberWord); int number = convertIntoNumber(decimalSepPos, numberWord);
scanPtr.add((decimalSepPos >>> 3) + 3); scanPtr.add((decimalSepPos >>> 3) + 3);
record(existingResult, number); return number;
} }
private static void record(Result existingResult, int number) { private static void record(Result existingResult, int number) {
@ -222,8 +237,8 @@ public class CalculateAverage_thomaswue {
} }
private static int hashToIndex(long hash, Result[] results) { private static int hashToIndex(long hash, Result[] results) {
int hashAsInt = (int) (hash ^ (hash >>> 32)); int hashAsInt = (int) (hash ^ (hash >>> 28));
int finalHash = (hashAsInt ^ (hashAsInt >>> 18)); int finalHash = (hashAsInt ^ (hashAsInt >>> 15));
return (finalHash & (results.length - 1)); return (finalHash & (results.length - 1));
} }
@ -344,5 +359,9 @@ public class CalculateAverage_thomaswue {
UNSAFE.copyMemory(null, pos, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, nameLength); UNSAFE.copyMemory(null, pos, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, nameLength);
return new String(bytes, StandardCharsets.UTF_8); return new String(bytes, StandardCharsets.UTF_8);
} }
public void setPos(long l) {
this.pos = l;
}
} }
} }