From 0b15ecb6a8599ea21db55b70d15da759e9f77466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kohlschu=CC=88tter?= Date: Thu, 7 Aug 2025 17:37:39 +0200 Subject: [PATCH] Improve comparability of benchmark, clarify use of best coding loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ReedSolomonBenchmark runs several rounds of performance checks with a variety of CodingLoops. This was certainly helpful to determine the best variant for use in ReedSolomon.java, but may be distracting when trying to benchmark the actually used, best loop implementation across different systems and when comparing JavaReedSolomon against other implementations. Clarify that InputOutputByteTableCodingLoop is the best coding loop, expose the instance via CodingLoop.BEST_CODING_LOOP, and use that in place of a hardcoded instantiation in ReedSolomon.java. Add a commented option to ReedSolomonBenchmark that solely tests the best coding loop instead of all available loops. Morever, add a commented option to ReedSolomonBenchmark that computes bandwidth on the basis of all shards (data + parity), as done with Klaus Post's Go implementation of this library. Signed-off-by: Christian Kohlschütter --- .../java/com/backblaze/erasure/CodingLoop.java | 6 ++++++ .../java/com/backblaze/erasure/ReedSolomon.java | 2 +- .../backblaze/erasure/ReedSolomonBenchmark.java | 14 +++++++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/backblaze/erasure/CodingLoop.java b/src/main/java/com/backblaze/erasure/CodingLoop.java index 0eca0b1..0176b04 100644 --- a/src/main/java/com/backblaze/erasure/CodingLoop.java +++ b/src/main/java/com/backblaze/erasure/CodingLoop.java @@ -55,6 +55,12 @@ public interface CodingLoop { new OutputInputByteTableCodingLoop(), }; + /** + * The best implementation as determined by {@link ReedSolomonBenchmark} over + * {@link #ALL_CODING_LOOPS}. + */ + CodingLoop BEST_CODING_LOOP = new InputOutputByteTableCodingLoop(); + /** * Multiplies a subset of rows from a coding matrix by a full set of * input shards to produce some output shards. diff --git a/src/main/java/com/backblaze/erasure/ReedSolomon.java b/src/main/java/com/backblaze/erasure/ReedSolomon.java index 09f2194..c84481b 100644 --- a/src/main/java/com/backblaze/erasure/ReedSolomon.java +++ b/src/main/java/com/backblaze/erasure/ReedSolomon.java @@ -27,7 +27,7 @@ public class ReedSolomon { * Creates a ReedSolomon codec with the default coding loop. */ public static ReedSolomon create(int dataShardCount, int parityShardCount) { - return new ReedSolomon(dataShardCount, parityShardCount, new InputOutputByteTableCodingLoop()); + return new ReedSolomon(dataShardCount, parityShardCount, CodingLoop.BEST_CODING_LOOP); } /** diff --git a/src/main/java/com/backblaze/erasure/ReedSolomonBenchmark.java b/src/main/java/com/backblaze/erasure/ReedSolomonBenchmark.java index ffadeb4..d558ec9 100644 --- a/src/main/java/com/backblaze/erasure/ReedSolomonBenchmark.java +++ b/src/main/java/com/backblaze/erasure/ReedSolomonBenchmark.java @@ -32,6 +32,14 @@ public class ReedSolomonBenchmark { private static final long MEASUREMENT_DURATION = 2 * 1000; + private static final CodingLoop[] CODING_LOOPS = CodingLoop.ALL_CODING_LOOPS; + // alternatively, just benchmark the most-performant CodingLoop + // private static final CodingLoop[] CODING_LOOPS = new CodingLoop[] {CodingLoop.BEST_CODING_LOOP}; + + private static final int BANDWIDTH_COUNT = DATA_COUNT; + // alternatively, add parity shards for the bandwidth calculation, to compare with other implementations + // private static final int BANDWIDTH_COUNT = TOTAL_COUNT; + private static final Random random = new Random(); private int nextBuffer = 0; @@ -52,7 +60,7 @@ public void run() { List summaryLines = new ArrayList(); StringBuilder csv = new StringBuilder(); csv.append("Outer,Middle,Inner,Multiply,Encode,Check\n"); - for (CodingLoop codingLoop : CodingLoop.ALL_CODING_LOOPS) { + for (CodingLoop codingLoop : CODING_LOOPS) { Measurement encodeAverage = new Measurement(); { final String testName = codingLoop.getClass().getSimpleName() + " encodeParity"; @@ -113,7 +121,7 @@ private Measurement doOneEncodeMeasurement(ReedSolomon codec, BufferSet[] buffer codec.encodeParity(shards, 0, BUFFER_SIZE); long endTime = System.currentTimeMillis(); encodingTime += (endTime - startTime); - bytesEncoded += BUFFER_SIZE * DATA_COUNT; + bytesEncoded += BUFFER_SIZE * BANDWIDTH_COUNT; passesCompleted += 1; } double seconds = ((double)encodingTime) / 1000.0; @@ -139,7 +147,7 @@ private Measurement doOneCheckMeasurement(ReedSolomon codec, BufferSet[] bufferS } long endTime = System.currentTimeMillis(); checkingTime += (endTime - startTime); - bytesChecked += BUFFER_SIZE * DATA_COUNT; + bytesChecked += BUFFER_SIZE * BANDWIDTH_COUNT; passesCompleted += 1; } double seconds = ((double)checkingTime) / 1000.0;