From 40bf6d1fa9fbccc6e8cf53560749dce3eaf2998e Mon Sep 17 00:00:00 2001 From: rafambn Date: Sat, 12 Sep 2026 14:14:13 -0300 Subject: [PATCH] cut level-6 match search overhead with rolling hash --- .../rafambn/kflate/algorithm/DeflateLevel.kt | 21 +- .../kflate/algorithm/FlateAlgorithms.kt | 68 +- .../jvmTest/kotlin/AlgorithmCoverageTest.kt | 41 ++ performance/kflate-zlib-direct-final-315.json | 690 ++++++++++++++++++ performance/kflate-zlib-window-final-315.json | 690 ++++++++++++++++++ .../level6-zlib-lazy-followup-2026-09-12.md | 60 ++ 6 files changed, 1546 insertions(+), 24 deletions(-) create mode 100644 performance/kflate-zlib-direct-final-315.json create mode 100644 performance/kflate-zlib-window-final-315.json create mode 100644 performance/level6-zlib-lazy-followup-2026-09-12.md diff --git a/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/DeflateLevel.kt b/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/DeflateLevel.kt index 695f0f0..327ac28 100644 --- a/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/DeflateLevel.kt +++ b/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/DeflateLevel.kt @@ -7,6 +7,8 @@ internal class DeflateLevel( val chainLength: Int, // Look ahead one byte when the current match is shorter than this. val maxLazyLength: Int, + // Reduce the lookahead chain search once the current match reaches this length. + val goodMatchLength: Int, // Cap the hash table so low levels retain their memory and cache advantage. val maxHashBits: Int, // Use bounded dynamic programming instead of greedy or one-byte lazy parsing. @@ -14,19 +16,20 @@ internal class DeflateLevel( ) internal val DEFLATE_LEVELS = arrayOf( - DeflateLevel(niceLength = 0, chainLength = 0, maxLazyLength = 0, maxHashBits = 12), - DeflateLevel(niceLength = 8, chainLength = 4, maxLazyLength = 0, maxHashBits = 12), - DeflateLevel(niceLength = 16, chainLength = 8, maxLazyLength = 0, maxHashBits = 13), - DeflateLevel(niceLength = 16, chainLength = 16, maxLazyLength = 0, maxHashBits = 13), - DeflateLevel(niceLength = 16, chainLength = 32, maxLazyLength = 4, maxHashBits = 14), - DeflateLevel(niceLength = 32, chainLength = 32, maxLazyLength = 16, maxHashBits = 14), - DeflateLevel(niceLength = 128, chainLength = 128, maxLazyLength = 16, maxHashBits = 15), - DeflateLevel(niceLength = 128, chainLength = 256, maxLazyLength = 32, maxHashBits = 15), - DeflateLevel(niceLength = 258, chainLength = 1_024, maxLazyLength = 128, maxHashBits = 16), + DeflateLevel(niceLength = 0, chainLength = 0, maxLazyLength = 0, goodMatchLength = 0, maxHashBits = 12), + DeflateLevel(niceLength = 8, chainLength = 4, maxLazyLength = 0, goodMatchLength = 0, maxHashBits = 12), + DeflateLevel(niceLength = 16, chainLength = 8, maxLazyLength = 0, goodMatchLength = 0, maxHashBits = 13), + DeflateLevel(niceLength = 16, chainLength = 16, maxLazyLength = 0, goodMatchLength = 0, maxHashBits = 13), + DeflateLevel(niceLength = 16, chainLength = 32, maxLazyLength = 4, goodMatchLength = 4, maxHashBits = 14), + DeflateLevel(niceLength = 32, chainLength = 32, maxLazyLength = 16, goodMatchLength = 8, maxHashBits = 14), + DeflateLevel(niceLength = 128, chainLength = 128, maxLazyLength = 16, goodMatchLength = 8, maxHashBits = 15), + DeflateLevel(niceLength = 128, chainLength = 256, maxLazyLength = 32, goodMatchLength = 8, maxHashBits = 15), + DeflateLevel(niceLength = 258, chainLength = 1_024, maxLazyLength = 128, goodMatchLength = 32, maxHashBits = 16), DeflateLevel( niceLength = 258, chainLength = 4_096, maxLazyLength = 0, + goodMatchLength = 0, maxHashBits = 20, usesCostAwareParsing = true, ), diff --git a/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/FlateAlgorithms.kt b/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/FlateAlgorithms.kt index 40bd144..95068e1 100644 --- a/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/FlateAlgorithms.kt +++ b/kflate/src/commonMain/kotlin/com/rafambn/kflate/algorithm/FlateAlgorithms.kt @@ -26,7 +26,6 @@ import com.rafambn.kflate.util.readTwoBytes import com.rafambn.kflate.util.shiftToNextByte import com.rafambn.kflate.util.writeBlock import com.rafambn.kflate.util.writeFixedBlock -import kotlin.math.ceil internal fun inflate( inputData: ByteArray, @@ -322,7 +321,12 @@ internal fun inflate( when { symbol < 256 -> { - ensureCapacity(1, bytesWrittenToOutput) + // The normal unbounded path has spare capacity almost all the time. + // Keep output-limit validation on the bounded path, but avoid doing + // long arithmetic and a function call for every literal otherwise. + if (maxOutputSize != null || bytesWrittenToOutput >= workingBuffer.size) { + ensureCapacity(1, bytesWrittenToOutput) + } workingBuffer[bytesWrittenToOutput++] = symbol.toByte() lastBitPosition = currentBitPosition } @@ -380,7 +384,9 @@ internal fun inflate( currentBitPosition += extraBits } - ensureCapacity(matchLength, bytesWrittenToOutput) + if (maxOutputSize != null || matchLength > workingBuffer.size - bytesWrittenToOutput) { + ensureCapacity(matchLength, bytesWrittenToOutput) + } val copyEndIndex = bytesWrittenToOutput + matchLength val buffer = workingBuffer @@ -497,8 +503,7 @@ internal fun deflate( val prevSize = if (isLastBlock) minOf(MATCH_DISTANCE_MASK + 1, dataSize) else MATCH_DISTANCE_MASK + 1 val prev = state.prev ?: ShortArray(prevSize) val head = state.head ?: ShortArray(mask + 1) - val baseShift1 = ceil(hashBits / 3.0).toInt() - val baseShift2 = 2 * baseShift1 + val hashShift = (hashBits + 2) / 3 val symbols = IntArray(minOf(65536, dataSize)) val literalFrequencies = IntArray(288) @@ -513,7 +518,7 @@ internal fun deflate( if (levelOptions.usesCostAwareParsing) { while (i < waitIndex && i + 2 < dataSize) { - val hashValue = deflateHash(data, i, baseShift1, baseShift2, mask) + val hashValue = deflateHash(data, i, hashShift, mask) val iMod = i and MATCH_DISTANCE_MASK prev[iMod] = head[hashValue] head[hashValue] = iMod.toShort() @@ -531,7 +536,7 @@ internal fun deflate( while (i < dataSize) { val hashEnd = minOf(i, dataSize - 2) while (hashedUntil < hashEnd) { - val hashValue = deflateHash(data, hashedUntil, baseShift1, baseShift2, mask) + val hashValue = deflateHash(data, hashedUntil, hashShift, mask) val hashIndex = hashedUntil and MATCH_DISTANCE_MASK prev[hashIndex] = head[hashValue] head[hashValue] = hashIndex.toShort() @@ -546,7 +551,7 @@ internal fun deflate( var scanIndex = windowStart while (scanIndex < windowEnd) { if (scanIndex + 2 >= dataSize) break - val hashValue = deflateHash(data, scanIndex, baseShift1, baseShift2, mask) + val hashValue = deflateHash(data, scanIndex, hashShift, mask) val scanIndexMod = scanIndex and MATCH_DISTANCE_MASK val previousIndex = head[hashValue].toInt() and 0xFFFF prev[scanIndexMod] = previousIndex.toShort() @@ -599,8 +604,9 @@ internal fun deflate( } waitIndex = i } else { + var hashWindow = if (i + 2 < dataSize) deflateHashWindow(data, i) else 0 while (i + 2 < dataSize) { - val hashValue = deflateHash(data, i, baseShift1, baseShift2, mask) + val hashValue = deflateHash(hashWindow, hashShift, mask) val iMod = i and MATCH_DISTANCE_MASK val pIMod = head[hashValue].toInt() and 0xFFFF prev[iMod] = pIMod.toShort() @@ -631,8 +637,17 @@ internal fun deflate( val nextMatch = if (shouldSearchLazyMatch(length, levelOptions.maxLazyLength, remaining)) { val nextIndex = i + 1 - val nextHash = deflateHash(data, nextIndex, baseShift1, baseShift2, mask) - findLongestMatch(data, dataSize, nextIndex, head[nextHash].toInt() and 0xFFFF, prev, levelOptions) + val nextHashWindow = updateDeflateHashWindow(hashWindow, data[i + 3]) + val nextHash = deflateHash(nextHashWindow, hashShift, mask) + findLongestMatch( + data, + dataSize, + nextIndex, + head[nextHash].toInt() and 0xFFFF, + prev, + levelOptions, + minimumLength = length, + ) } else { 0 } @@ -660,6 +675,9 @@ internal fun deflate( ++literalFrequencies[data[i].toInt() and 0xFF] } } + if (i + 3 < dataSize) { + hashWindow = updateDeflateHashWindow(hashWindow, data[i + 3]) + } i++ } @@ -816,10 +834,26 @@ internal fun shouldSearchLazyMatch(length: Int, maxLazyLength: Int, remaining: I return maxLazyLength > 0 && length in 3 until maxLazyLength && remaining > length + 1 } -private fun deflateHash(data: ByteArray, index: Int, shift1: Int, shift2: Int, mask: Int): Int { +private fun deflateHash(data: ByteArray, index: Int, hashShift: Int, mask: Int): Int { return ((data[index].toInt() and 0xFF) xor - ((data[index + 1].toInt() and 0xFF) shl shift1) xor - ((data[index + 2].toInt() and 0xFF) shl shift2)) and mask + ((data[index + 1].toInt() and 0xFF) shl hashShift) xor + ((data[index + 2].toInt() and 0xFF) shl (2 * hashShift))) and mask +} + +private fun deflateHashWindow(data: ByteArray, index: Int): Int { + return (data[index].toInt() and 0xFF) or + ((data[index + 1].toInt() and 0xFF) shl 8) or + ((data[index + 2].toInt() and 0xFF) shl 16) +} + +private fun updateDeflateHashWindow(window: Int, nextByte: Byte): Int { + return (window ushr 8) or ((nextByte.toInt() and 0xFF) shl 16) +} + +private fun deflateHash(window: Int, hashShift: Int, mask: Int): Int { + return ((window and 0xFF) xor + (((window ushr 8) and 0xFF) shl hashShift) xor + ((window ushr 16) shl (2 * hashShift))) and mask } private fun findLongestMatch( @@ -829,6 +863,7 @@ private fun findLongestMatch( previousIndex: Int, previous: ShortArray, level: DeflateLevel, + minimumLength: Int = 2, ): Int { val remaining = dataSize - index var currentIndex = index and MATCH_DISTANCE_MASK @@ -840,7 +875,10 @@ private fun findLongestMatch( val maxDistance = minOf(MATCH_DISTANCE_MASK, index) val maxLength = minOf(MAX_MATCH_LENGTH, remaining) var remainingChain = level.chainLength - var bestLength = 2 + if (level.goodMatchLength > 0 && minimumLength >= level.goodMatchLength) { + remainingChain = maxOf(1, remainingChain shr 2) + } + var bestLength = minimumLength var bestDistance = 0 while (distance <= maxDistance && --remainingChain != 0 && currentIndex != candidateIndex) { diff --git a/kflate/src/jvmTest/kotlin/AlgorithmCoverageTest.kt b/kflate/src/jvmTest/kotlin/AlgorithmCoverageTest.kt index 8937532..42860f8 100644 --- a/kflate/src/jvmTest/kotlin/AlgorithmCoverageTest.kt +++ b/kflate/src/jvmTest/kotlin/AlgorithmCoverageTest.kt @@ -25,7 +25,9 @@ import com.rafambn.kflate.huffman.generateLengthCodes import com.rafambn.kflate.huffman.validateHuffmanCodeLengths import com.rafambn.kflate.streaming.DeflateState import com.rafambn.kflate.streaming.InflateState +import java.io.ByteArrayOutputStream import java.util.zip.Deflater +import java.util.zip.Inflater import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals @@ -238,6 +240,8 @@ class AlgorithmCoverageTest { }) assertEquals(0, DEFLATE_LEVELS[3].maxLazyLength) assertTrue(DEFLATE_LEVELS[4].maxLazyLength > 0) + assertEquals(8, DEFLATE_LEVELS[6].goodMatchLength) + assertEquals(32, DEFLATE_LEVELS[8].goodMatchLength) assertTrue(!DEFLATE_LEVELS[8].usesCostAwareParsing) assertTrue(DEFLATE_LEVELS[9].usesCostAwareParsing) @@ -248,6 +252,21 @@ class AlgorithmCoverageTest { assertTrue(!shouldSearchLazyMatch(length = 3, maxLazyLength = 4, remaining = 4)) } + @Test + fun lazyLevelsRoundTripThresholdAndWindowInputs() { + val inputs = listOf( + ("abcdefgh".repeat(256) + "abcdefgX" + "abcdefgh".repeat(256)).encodeToByteArray(), + ("0123456789abcdef".repeat(2_100) + "01234567").encodeToByteArray(), + ) + + for (level in 4..8) { + for (input in inputs) { + val compressed = KFlate.compress(input, CompressionRaw(level = level)) + assertContentEquals(input, inflateWithJava(compressed)) + } + } + } + @Test fun costAwareParsingChoosesTheCheapestTokenPath() { assertEquals(8, fixedLiteralBitCost(42)) @@ -380,4 +399,26 @@ class AlgorithmCoverageTest { deflater.end() } } + + private fun inflateWithJava(input: ByteArray): ByteArray { + val inflater = Inflater(true) + return try { + inflater.setInput(input) + val output = ByteArrayOutputStream() + val buffer = ByteArray(8_192) + while (!inflater.finished()) { + val count = inflater.inflate(buffer) + if (count == 0) { + check(!inflater.needsInput() && !inflater.needsDictionary()) { + "Java Inflater stopped before finishing" + } + } else { + output.write(buffer, 0, count) + } + } + output.toByteArray() + } finally { + inflater.end() + } + } } diff --git a/performance/kflate-zlib-direct-final-315.json b/performance/kflate-zlib-direct-final-315.json new file mode 100644 index 0000000..51ff3b4 --- /dev/null +++ b/performance/kflate-zlib-direct-final-315.json @@ -0,0 +1,690 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "simpleText" + }, + "primaryMetric" : { + "score" : 4.413075879623431E-6, + "scoreError" : 9.391723498595028E-8, + "scoreConfidence" : [ + 4.319158644637481E-6, + 4.506993114609381E-6 + ], + "scorePercentiles" : { + "0.0" : 4.03601801071038E-6, + "50.0" : 4.450522726969337E-6, + "90.0" : 4.527982071354658E-6, + "95.0" : 4.577972572899794E-6, + "99.0" : 5.0230644788653165E-6, + "99.9" : 5.0230644788653165E-6, + "99.99" : 5.0230644788653165E-6, + "99.999" : 5.0230644788653165E-6, + "99.9999" : 5.0230644788653165E-6, + "100.0" : 5.0230644788653165E-6 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 4.12793109652924E-6, + 4.110750711067999E-6, + 4.363714725773376E-6, + 4.515519032891618E-6, + 4.438506783414474E-6, + 4.445351818602005E-6, + 4.465611217022873E-6, + 4.399722751764939E-6, + 4.4000675799327805E-6, + 4.503335502026114E-6, + 4.450522726969337E-6, + 4.441868155977971E-6, + 4.333634714374848E-6, + 4.523357693647082E-6, + 4.5240042293913294E-6 + ], + [ + 4.512924167151734E-6, + 4.515823180422612E-6, + 4.436578627288333E-6, + 4.436965172606532E-6, + 4.4189971590407015E-6, + 4.4975661426104475E-6, + 4.503830302784683E-6, + 4.503148860873481E-6, + 4.5919241169395195E-6, + 4.151956102299285E-6, + 4.059145198597562E-6, + 4.1689901678017385E-6, + 4.3390842624003336E-6, + 4.457676925202571E-6, + 4.500605235922496E-6 + ], + [ + 4.494179780077561E-6, + 4.049821506665155E-6, + 4.03601801071038E-6, + 4.0766666082405305E-6, + 4.545418970140435E-6, + 4.506310017617454E-6, + 4.53394883429965E-6, + 4.515202043230164E-6, + 5.0230644788653165E-6, + 4.387431994454973E-6, + 4.4532861341170185E-6, + 4.480086398129317E-6, + 4.445554434408449E-6, + 4.446176129846805E-6, + 4.456134880923207E-6 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "text" + }, + "primaryMetric" : { + "score" : 0.06273254982785947, + "scoreError" : 0.001640896802433676, + "scoreConfidence" : [ + 0.061091653025425796, + 0.06437344663029315 + ], + "scorePercentiles" : { + "0.0" : 0.05911263276470588, + "50.0" : 0.0636925803125, + "90.0" : 0.06626036557500001, + "95.0" : 0.06638342109375, + "99.0" : 0.0664449965625, + "99.9" : 0.0664449965625, + "99.99" : 0.0664449965625, + "99.999" : 0.0664449965625, + "99.9999" : 0.0664449965625, + "100.0" : 0.0664449965625 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.06020137494117647, + 0.05992085835294118, + 0.065080496125, + 0.059398684411764706, + 0.059413184, + 0.06016459964705882, + 0.059630133647058825, + 0.06007205582352941, + 0.05957838841176471, + 0.05915503694117647, + 0.05977968805882353, + 0.059449168117647055, + 0.059391977294117645, + 0.05983074941176471, + 0.059483015411764706 + ], + [ + 0.0664449965625, + 0.066386832, + 0.066202820625, + 0.0655665701875, + 0.0655353369375, + 0.065486088875, + 0.0658150799375, + 0.066037757125, + 0.0663754623125, + 0.0655972094375, + 0.0654794895, + 0.0654945270625, + 0.0655112351875, + 0.065592349875, + 0.0658475676875 + ], + [ + 0.06005302894117647, + 0.059884938352941175, + 0.059347175764705884, + 0.059197521647058826, + 0.05911263276470588, + 0.059114284882352944, + 0.05929668211764706, + 0.059996796, + 0.0636925803125, + 0.0656610433125, + 0.066346683, + 0.06591023775, + 0.066058573375, + 0.0657140235, + 0.065655806625 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "model3D" + }, + "primaryMetric" : { + "score" : 4.931217786215754E-5, + "scoreError" : 1.1632061052992764E-6, + "scoreConfidence" : [ + 4.8148971756858263E-5, + 5.047538396745682E-5 + ], + "scorePercentiles" : { + "0.0" : 4.4904814447337706E-5, + "50.0" : 5.0439846537899034E-5, + "90.0" : 5.071323871195273E-5, + "95.0" : 5.079077762843069E-5, + "99.0" : 5.2026728946684006E-5, + "99.9" : 5.2026728946684006E-5, + "99.99" : 5.2026728946684006E-5, + "99.999" : 5.2026728946684006E-5, + "99.9999" : 5.2026728946684006E-5, + "100.0" : 5.2026728946684006E-5 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 5.0685833569835796E-5, + 5.044410233519948E-5, + 5.054423024054983E-5, + 5.04023358863247E-5, + 5.051904404707784E-5, + 5.0325392452830186E-5, + 5.0478258036840776E-5, + 5.031064369781712E-5, + 5.0657851904376015E-5, + 5.080553901249619E-5, + 5.2026728946684006E-5, + 5.0756334398944536E-5, + 5.0524571580117193E-5, + 5.052539924223289E-5, + 5.0641105316455696E-5 + ], + [ + 4.4999334982904446E-5, + 4.4982869844839214E-5, + 4.938172879431223E-5, + 5.058091918681096E-5, + 5.075434642512813E-5, + 5.061186793503011E-5, + 5.047778020591501E-5, + 5.048636025440412E-5, + 5.0439846537899034E-5, + 5.056626487688963E-5, + 5.05196412950149E-5, + 5.062145682761413E-5, + 5.027328124842941E-5, + 5.022360991162884E-5, + 5.0664056025530625E-5 + ], + [ + 4.972741710166542E-5, + 4.556099498929531E-5, + 4.495539273675222E-5, + 4.917372928855892E-5, + 4.5156475934621635E-5, + 4.997737692384569E-5, + 5.037544183118453E-5, + 5.0343005486208976E-5, + 5.062775859276133E-5, + 5.0392800191445414E-5, + 4.69634291952296E-5, + 4.5656239832017166E-5, + 4.4904814447337706E-5, + 4.503402971366829E-5, + 4.496836251236399E-5 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "Rainier.bmp" + }, + "primaryMetric" : { + "score" : 0.11310468732765432, + "scoreError" : 0.0013430305251241914, + "scoreConfidence" : [ + 0.11176165680253013, + 0.1144477178527785 + ], + "scorePercentiles" : { + "0.0" : 0.1009451802, + "50.0" : 0.11342897633333333, + "90.0" : 0.115351498, + "95.0" : 0.11571311713333333, + "99.0" : 0.11645369322222222, + "99.9" : 0.11645369322222222, + "99.99" : 0.11645369322222222, + "99.999" : 0.11645369322222222, + "99.9999" : 0.11645369322222222, + "100.0" : 0.11645369322222222 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.1060742691, + 0.11316945766666667, + 0.11355050766666666, + 0.11352506811111111, + 0.11366965311111112, + 0.11342897633333333, + 0.11415480755555556, + 0.11322788744444444, + 0.11332309055555556, + 0.11350237311111111, + 0.11348182477777778, + 0.11351754455555556, + 0.11323123266666667, + 0.109450108, + 0.1009451802 + ], + [ + 0.11509111822222222, + 0.115443053, + 0.11484731755555555, + 0.11419447677777778, + 0.11449410966666666, + 0.114980519, + 0.11645369322222222, + 0.11579626366666666, + 0.11551910855555556, + 0.11529046133333333, + 0.11527269166666666, + 0.11481481855555556, + 0.11484097233333333, + 0.11497674444444445, + 0.11454206922222222 + ], + [ + 0.11232204522222222, + 0.11219552144444445, + 0.11233229244444444, + 0.11219205166666667, + 0.1123973348888889, + 0.1120476998888889, + 0.11214887777777778, + 0.11198653555555556, + 0.11255500055555556, + 0.11254215511111111, + 0.11237324866666666, + 0.112018218, + 0.11249126866666667, + 0.11282010533333334, + 0.11247917644444444 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "Maltese.bmp" + }, + "primaryMetric" : { + "score" : 0.4472375198148149, + "scoreError" : 0.012908464624244618, + "scoreConfidence" : [ + 0.4343290551905703, + 0.4601459844390595 + ], + "scorePercentiles" : { + "0.0" : 0.41880280766666667, + "50.0" : 0.467075118, + "90.0" : 0.4727800734666667, + "95.0" : 0.47322802960000004, + "99.0" : 0.47381846066666666, + "99.9" : 0.47381846066666666, + "99.99" : 0.47381846066666666, + "99.999" : 0.47381846066666666, + "99.9999" : 0.47381846066666666, + "100.0" : 0.47381846066666666 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.470612029, + 0.473380363, + 0.4726884063333333, + 0.472872585, + 0.42093205166666664, + 0.422188457, + 0.467075118, + 0.471500309, + 0.4712225583333333, + 0.47272352333333334, + 0.42271338133333336, + 0.4228163306666667, + 0.42245814666666665, + 0.4316737276666667, + 0.429247861 + ], + [ + 0.46816889566666664, + 0.46746152333333335, + 0.46749311433333335, + 0.4680565133333333, + 0.4724560486666667, + 0.47054382666666666, + 0.4684551786666667, + 0.468463494, + 0.47063028366666665, + 0.47381846066666666, + 0.47286489866666664, + 0.47226498333333333, + 0.47192508433333336, + 0.4723454673333333, + 0.47184922733333334 + ], + [ + 0.4208532893333333, + 0.42064367233333333, + 0.41978782433333334, + 0.4276028926666667, + 0.4298570763333333, + 0.4209214823333333, + 0.420785199, + 0.42067948066666666, + 0.4197168926666667, + 0.42113818766666666, + 0.42228841833333336, + 0.4201450936666667, + 0.4218655296666667, + 0.41880280766666667, + 0.419698697 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "Sunrise.bmp" + }, + "primaryMetric" : { + "score" : 1.5120825625111112, + "scoreError" : 0.04641989930140894, + "scoreConfidence" : [ + 1.4656626632097023, + 1.55850246181252 + ], + "scorePercentiles" : { + "0.0" : 1.3728639, + "50.0" : 1.527070438, + "90.0" : 1.6050763792, + "95.0" : 1.6107068507, + "99.0" : 1.628690404, + "99.9" : 1.628690404, + "99.99" : 1.628690404, + "99.999" : 1.628690404, + "99.9999" : 1.628690404, + "100.0" : 1.628690404 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 1.539819353, + 1.536553335, + 1.381151465, + 1.535323384, + 1.375823585, + 1.380033058, + 1.3728639, + 1.373012065, + 1.374516774, + 1.374905219, + 1.375025054, + 1.37761578, + 1.399321833, + 1.375418389, + 1.376030619 + ], + [ + 1.60138699, + 1.597680494, + 1.610902202, + 1.610251031, + 1.609227115, + 1.602309222, + 1.59697326, + 1.594339006, + 1.595049682, + 1.628690404, + 1.594091964, + 1.600246534, + 1.594901513, + 1.601294606, + 1.590104019 + ], + [ + 1.527070438, + 1.532062755, + 1.536045816, + 1.533511297, + 1.52373724, + 1.520685534, + 1.520008933, + 1.518798652, + 1.519522735, + 1.519754898, + 1.522868978, + 1.52816603, + 1.520357392, + 1.521652939, + 1.524609821 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "compressed_MVT.pbf" + }, + "primaryMetric" : { + "score" : 0.003722048543193458, + "scoreError" : 7.879154762656005E-5, + "scoreConfidence" : [ + 0.003643256995566898, + 0.003800840090820018 + ], + "scorePercentiles" : { + "0.0" : 0.0036103113129496403, + "50.0" : 0.0036765367216117215, + "90.0" : 0.004095206033456005, + "95.0" : 0.004106728711475409, + "99.0" : 0.004150894734439834, + "99.9" : 0.004150894734439834, + "99.99" : 0.004150894734439834, + "99.999" : 0.004150894734439834, + "99.9999" : 0.004150894734439834, + "100.0" : 0.004150894734439834 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.003624801481884058, + 0.0036549600474452557, + 0.0036560313467153284, + 0.003628636221014493, + 0.0036103113129496403, + 0.003620028014440433, + 0.003621931953068592, + 0.00361977680866426, + 0.003644622992727273, + 0.003626332713768116, + 0.0036197880613718413, + 0.0036195674115523466, + 0.003614109772563177, + 0.0036233985559566786, + 0.0036217798122743683 + ], + [ + 0.0036694934175824177, + 0.0036639417875457877, + 0.003677412356617647, + 0.0036826957095588237, + 0.003678429731617647, + 0.003818432140684411, + 0.0038199179847328243, + 0.00409194306122449, + 0.004100100491803278, + 0.004104454290983607, + 0.004107703463114754, + 0.0037127384703703704, + 0.0036658522673992675, + 0.0037157463555555557, + 0.0036909704206642066 + ], + [ + 0.004150894734439834, + 0.003902518626459144, + 0.0036895220698529413, + 0.003704362037037037, + 0.0036765367216117215, + 0.0036813809963235295, + 0.0036664706117216115, + 0.003676774380952381, + 0.0036827290330882353, + 0.0036892911838235292, + 0.003667885315018315, + 0.0036766602783882786, + 0.0036808317647058822, + 0.0036734643296703296, + 0.003666953904761905 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/performance/kflate-zlib-window-final-315.json b/performance/kflate-zlib-window-final-315.json new file mode 100644 index 0000000..c1a20a0 --- /dev/null +++ b/performance/kflate-zlib-window-final-315.json @@ -0,0 +1,690 @@ +[ + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "simpleText" + }, + "primaryMetric" : { + "score" : 4.414447079865096E-6, + "scoreError" : 8.287528257927631E-8, + "scoreConfidence" : [ + 4.33157179728582E-6, + 4.497322362444372E-6 + ], + "scorePercentiles" : { + "0.0" : 4.06356153074201E-6, + "50.0" : 4.4445242943225855E-6, + "90.0" : 4.618778916748649E-6, + "95.0" : 4.645651483828092E-6, + "99.0" : 4.6708661420632325E-6, + "99.9" : 4.6708661420632325E-6, + "99.99" : 4.6708661420632325E-6, + "99.999" : 4.6708661420632325E-6, + "99.9999" : 4.6708661420632325E-6, + "100.0" : 4.6708661420632325E-6 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 4.457029106010578E-6, + 4.46785662406811E-6, + 4.215376584572334E-6, + 4.2919819817113725E-6, + 4.06356153074201E-6, + 4.101337531165934E-6, + 4.397257550844552E-6, + 4.380613607795905E-6, + 4.395578523655092E-6, + 4.395280159779929E-6, + 4.4049735314583685E-6, + 4.43180947380082E-6, + 4.512720830024545E-6, + 4.407024291908279E-6, + 4.4445242943225855E-6 + ], + [ + 4.314845054139166E-6, + 4.546768663602849E-6, + 4.6109537077159956E-6, + 4.6165820036463505E-6, + 4.622037300087335E-6, + 4.616606661189525E-6, + 4.652358298446367E-6, + 4.602992972331143E-6, + 4.486200388450549E-6, + 4.6708661420632325E-6, + 4.361542107259812E-6, + 4.252520765835863E-6, + 4.630002249718785E-6, + 4.2187773053594176E-6, + 4.210534393405492E-6 + ], + [ + 4.4699712019305966E-6, + 4.462459578607316E-6, + 4.33717033815252E-6, + 4.48347889956786E-6, + 4.508516324313603E-6, + 4.546328319742548E-6, + 4.205803327838797E-6, + 4.157820165118851E-6, + 4.3359050389277104E-6, + 4.065214027899717E-6, + 4.430859045981951E-6, + 4.463188525833832E-6, + 4.467960320757667E-6, + 4.472299352519272E-6, + 4.462630491624798E-6 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "text" + }, + "primaryMetric" : { + "score" : 0.06488160637328066, + "scoreError" : 0.002323340074963021, + "scoreConfidence" : [ + 0.06255826629831765, + 0.06720494644824368 + ], + "scorePercentiles" : { + "0.0" : 0.05854261961111111, + "50.0" : 0.066080306375, + "90.0" : 0.06762198461333334, + "95.0" : 0.07360764976999998, + "99.0" : 0.0814402426923077, + "99.9" : 0.0814402426923077, + "99.99" : 0.0814402426923077, + "99.999" : 0.0814402426923077, + "99.9999" : 0.0814402426923077, + "100.0" : 0.0814402426923077 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.06105172770588235, + 0.060547829, + 0.06042405594117647, + 0.060219962, + 0.060057824647058826, + 0.05980274947058824, + 0.059816477352941176, + 0.06059275582352941, + 0.061027684470588234, + 0.06948615706666667, + 0.0814402426923077, + 0.07537400378571428, + 0.060880464764705884, + 0.059327966823529414, + 0.05892136976470588 + ], + [ + 0.06725074246666667, + 0.06692666866666666, + 0.067096074, + 0.06673740406666667, + 0.066487307125, + 0.0665256915, + 0.06696591886666667, + 0.0661937921875, + 0.06688962233333333, + 0.06676971086666666, + 0.06719633966666666, + 0.06788995933333333, + 0.0660382331875, + 0.066051298875, + 0.0674433348 + ], + [ + 0.066113917125, + 0.0665758814375, + 0.065237799375, + 0.05854261961111111, + 0.05905129458823529, + 0.058805078222222223, + 0.0651439821875, + 0.0663900311875, + 0.066391763625, + 0.0661589385, + 0.066080306375, + 0.065817172, + 0.065746283375, + 0.06573371875, + 0.0664501311875 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "model3D" + }, + "primaryMetric" : { + "score" : 5.0060509292124985E-5, + "scoreError" : 1.3180328399565896E-6, + "scoreConfidence" : [ + 4.87424764521684E-5, + 5.137854213208157E-5 + ], + "scorePercentiles" : { + "0.0" : 4.5717307797787735E-5, + "50.0" : 5.110672774655084E-5, + "90.0" : 5.2644891823560136E-5, + "95.0" : 5.281262389642412E-5, + "99.0" : 5.3034436297121045E-5, + "99.9" : 5.3034436297121045E-5, + "99.99" : 5.3034436297121045E-5, + "99.999" : 5.3034436297121045E-5, + "99.9999" : 5.3034436297121045E-5, + "100.0" : 5.3034436297121045E-5 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 5.279889210304054E-5, + 5.2818508950731374E-5, + 5.3034436297121045E-5, + 5.2749332718067716E-5, + 5.230677414631596E-5, + 5.2297099864059395E-5, + 5.236836314136126E-5, + 5.243282129377228E-5, + 5.23077596360023E-5, + 4.7843380991103035E-5, + 4.667616268433825E-5, + 4.7451400208738555E-5, + 5.257526456055509E-5, + 5.2456582891907485E-5, + 5.242273069867393E-5 + ], + [ + 4.6178086149584486E-5, + 4.5939511414266684E-5, + 4.595293480058813E-5, + 4.5880969494013486E-5, + 4.731202194995033E-5, + 5.104754187720104E-5, + 4.5717307797787735E-5, + 4.5954382431314895E-5, + 4.59903421766518E-5, + 4.612785985058107E-5, + 4.685744612573784E-5, + 5.102684634220998E-5, + 5.102877827661854E-5, + 4.851748164136392E-5, + 4.8729314835566384E-5 + ], + [ + 5.109079020228852E-5, + 5.116194700496189E-5, + 5.116848196654218E-5, + 5.113275291411043E-5, + 5.107259086963182E-5, + 5.108283702757916E-5, + 5.113709667689162E-5, + 5.110672774655084E-5, + 5.1099395064881986E-5, + 5.1176991710586914E-5, + 5.119729954954955E-5, + 5.11747007777323E-5, + 5.118651678607984E-5, + 5.169808729584453E-5, + 5.1436367203167585E-5 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "Rainier.bmp" + }, + "primaryMetric" : { + "score" : 0.1027965714989899, + "scoreError" : 0.002677206899533355, + "scoreConfidence" : [ + 0.10011936459945654, + 0.10547377839852325 + ], + "scorePercentiles" : { + "0.0" : 0.0938139230909091, + "50.0" : 0.1048324299, + "90.0" : 0.10749026106000001, + "95.0" : 0.1077573478, + "99.0" : 0.1082963524, + "99.9" : 0.1082963524, + "99.99" : 0.1082963524, + "99.999" : 0.1082963524, + "99.9999" : 0.1082963524, + "100.0" : 0.1082963524 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.1048596807, + 0.1045061048, + 0.104646191, + 0.1055920771, + 0.1054709183, + 0.1047546411, + 0.1044127426, + 0.1048324299, + 0.1060275819, + 0.1045879532, + 0.1046635735, + 0.1041664583, + 0.1054708249, + 0.1040522935, + 0.1046284151 + ], + [ + 0.1012920857, + 0.0956588380909091, + 0.106746921, + 0.1068805513, + 0.1062464833, + 0.1076219412, + 0.1082963524, + 0.1078153792, + 0.1074542311, + 0.1066131661, + 0.1066631889, + 0.1063231351, + 0.106556028, + 0.1063174745, + 0.1069282631 + ], + [ + 0.107544306, + 0.1051944354, + 0.1063873299, + 0.1053816189, + 0.097623102, + 0.094200254, + 0.0938139230909091, + 0.09420270836363637, + 0.09452722409090909, + 0.09409255772727272, + 0.094076782, + 0.09390524572727273, + 0.094286932, + 0.09409674054545454, + 0.09642663281818181 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "Maltese.bmp" + }, + "primaryMetric" : { + "score" : 0.3970232663407407, + "scoreError" : 0.009694838504246883, + "scoreConfidence" : [ + 0.3873284278364938, + 0.4067181048449876 + ], + "scorePercentiles" : { + "0.0" : 0.384819386, + "50.0" : 0.3892856046666667, + "90.0" : 0.43620589246666663, + "95.0" : 0.43714787746666667, + "99.0" : 0.4375768586666667, + "99.9" : 0.4375768586666667, + "99.99" : 0.4375768586666667, + "99.999" : 0.4375768586666667, + "99.9999" : 0.4375768586666667, + "100.0" : 0.4375768586666667 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.3855714846666667, + 0.39245760133333335, + 0.386845285, + 0.3851320343333333, + 0.38549291166666666, + 0.390746607, + 0.386573311, + 0.38827076, + 0.38586229066666666, + 0.38882909233333335, + 0.385429344, + 0.384819386, + 0.386345291, + 0.3853626, + 0.3900381233333333 + ], + [ + 0.389710543, + 0.3896105086666667, + 0.3888894216666667, + 0.38951067066666667, + 0.38934740366666665, + 0.39659414433333334, + 0.389595906, + 0.3892856046666667, + 0.388066517, + 0.38889634366666664, + 0.3910863293333333, + 0.388641347, + 0.4329516173333333, + 0.4375768586666667, + 0.43633474066666667 + ], + [ + 0.436592602, + 0.43611999366666665, + 0.43360013833333333, + 0.4353262353333333, + 0.4373858526666667, + 0.3880765253333333, + 0.3859554946666667, + 0.39454419, + 0.3996991636666667, + 0.38585863466666664, + 0.38643832, + 0.389383789, + 0.386609537, + 0.389576262, + 0.38700616833333334 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "Sunrise.bmp" + }, + "primaryMetric" : { + "score" : 1.5208021571999994, + "scoreError" : 0.0413572320129602, + "scoreConfidence" : [ + 1.4794449251870392, + 1.5621593892129597 + ], + "scorePercentiles" : { + "0.0" : 1.374973062, + "50.0" : 1.543808707, + "90.0" : 1.6072150163999999, + "95.0" : 1.6104807989, + "99.0" : 1.640206682, + "99.9" : 1.640206682, + "99.99" : 1.640206682, + "99.999" : 1.640206682, + "99.9999" : 1.640206682, + "100.0" : 1.640206682 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 1.424994559, + 1.456257475, + 1.424049935, + 1.430084749, + 1.423505329, + 1.423962612, + 1.423813869, + 1.424626584, + 1.423258392, + 1.422703138, + 1.422677408, + 1.422645983, + 1.441715148, + 1.428309343, + 1.423479014 + ], + [ + 1.60758144, + 1.640206682, + 1.595508786, + 1.609836458, + 1.610756945, + 1.606970734, + 1.599896333, + 1.602268507, + 1.596897307, + 1.597949371, + 1.6018182, + 1.60572279, + 1.606060371, + 1.595273946, + 1.595891143 + ], + [ + 1.374973062, + 1.466059429, + 1.550119458, + 1.548313242, + 1.560699142, + 1.535971629, + 1.541856152, + 1.538690275, + 1.539385657, + 1.541955176, + 1.548390276, + 1.55617275, + 1.556449478, + 1.54453009, + 1.543808707 + ] + ] + }, + "secondaryMetrics" : { + } + }, + { + "jmhVersion" : "1.37", + "benchmark" : "com.rafambn.kflate.benchmark.CompressionBenchmarks.rawDeflateCompression", + "mode" : "avgt", + "threads" : 1, + "forks" : 3, + "jvm" : "/usr/lib/jvm/java-25-openjdk-amd64/bin/java", + "jvmArgs" : [ + ], + "jdkVersion" : "25.0.4", + "vmName" : "OpenJDK 64-Bit Server VM", + "vmVersion" : "25.0.4+7-1-26.04-Ubuntu", + "warmupIterations" : 3, + "warmupTime" : "1 s", + "warmupBatchSize" : 1, + "measurementIterations" : 15, + "measurementTime" : "1 s", + "measurementBatchSize" : 1, + "params" : { + "corpus" : "compressed_MVT.pbf" + }, + "primaryMetric" : { + "score" : 0.003899227784121714, + "scoreError" : 1.1768828200826433E-4, + "scoreConfidence" : [ + 0.0037815395021134498, + 0.004016916066129979 + ], + "scorePercentiles" : { + "0.0" : 0.0036810875220588237, + "50.0" : 0.0037418335746268656, + "90.0" : 0.00416442459253112, + "95.0" : 0.004183260429388076, + "99.0" : 0.0042415490466101696, + "99.9" : 0.0042415490466101696, + "99.99" : 0.0042415490466101696, + "99.999" : 0.0042415490466101696, + "99.9999" : 0.0042415490466101696, + "100.0" : 0.0042415490466101696 + }, + "scoreUnit" : "s/op", + "rawData" : [ + [ + 0.004164109045643153, + 0.004187592933054394, + 0.004162759572614108, + 0.0042415490466101696, + 0.004143143227272727, + 0.0041263674032921815, + 0.004144376975206612, + 0.0041357633016528925, + 0.004132824329218107, + 0.004135605347107438, + 0.004128226061728395, + 0.004152781207468879, + 0.004132756636363637, + 0.004134647185950413, + 0.004128871427983539 + ], + [ + 0.003688498301470588, + 0.0037085131992619924, + 0.0037061247074074073, + 0.0037032625387453874, + 0.0037149634851851854, + 0.0037418335746268656, + 0.003716391848148148, + 0.003978070031746031, + 0.003684340580882353, + 0.0036810875220588237, + 0.0036947223210332105, + 0.003682707411764706, + 0.003701866859778598, + 0.0036939496494464946, + 0.0037089297851851852 + ], + [ + 0.004164897912863071, + 0.004159009518672199, + 0.004150824269709544, + 0.004173151254166667, + 0.0036932022878228784, + 0.0036936025793357936, + 0.003693719177121771, + 0.0036954400147601475, + 0.0036933683099630997, + 0.0036898505, + 0.0036946155719557194, + 0.0037067174666666667, + 0.003697977557195572, + 0.003757546086142322, + 0.00374469226119403 + ] + ] + }, + "secondaryMetrics" : { + } + } +] + + diff --git a/performance/level6-zlib-lazy-followup-2026-09-12.md b/performance/level6-zlib-lazy-followup-2026-09-12.md new file mode 100644 index 0000000..028cf16 --- /dev/null +++ b/performance/level6-zlib-lazy-followup-2026-09-12.md @@ -0,0 +1,60 @@ +# Level-6 zlib-style lazy-parser follow-up + +Date: 2026-09-12 +Branch: `perf/restore-level6-speed` +Base commit: `843513734e4cede3f1084a1a858112ecb66d19ef` +Host: Linux remote, JVM 25.0.4 +Compression level: 6 + +## Decision + +Retain the corrected implementation. + +The parser policy remains: + +- Level 0: no compression. +- Levels 1-3: greedy parsing. +- Levels 4-8: one-byte lazy parsing. +- Level 9: cost-aware parsing. + +The regular matcher now uses a rolling 24-bit window for KFlate's existing three-byte hash ordering. It avoids reloading the first two bytes at every position and reuses the next-position hash during lazy lookahead. The lazy search also uses zlib-style good-match throttling and starts from the current match length, so it only spends chain work looking for a strictly longer next match. Level 9 keeps the original hash ordering and cost-aware path. + +The level-4 throttle is effectively inactive because its lazy threshold is four and the throttle requires a current match of at least four. The effective throttle applies to levels 5-8, matching the intended zlib-style threshold behavior. The reference implementation and thresholds are in [zlib's `deflate.c`](https://github.com/madler/zlib/blob/develop/deflate.c). + +## Controlled Linux benchmark + +Baseline: direct three-byte hash with no good-match throttle. +Candidate: rolling old-order hash window, good-match throttle, and seeded lazy lookahead. + +Both runs used three one-second warmups, fifteen one-second measurements, three forks, average-time mode, and all seven level-6 benchmark corpora. + +Raw results: [`kflate-zlib-direct-final-315.json`](kflate-zlib-direct-final-315.json) and [`kflate-zlib-window-final-315.json`](kflate-zlib-window-final-315.json). + +| Corpus | Baseline ms | Candidate ms | Time change | Baseline bytes | Candidate bytes | Size change | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | +| `simpleText` | 0.004 | 0.004 | +0.03% | 84 | 84 | 0 | +| `text` | 62.733 | 64.882 | +3.43% | 506,455 | 506,673 | +218 (+0.04%) | +| `model3D` | 0.049 | 0.050 | +1.52% | 2,153 | 2,153 | 0 | +| `Rainier.bmp` | 113.105 | 102.797 | **-9.11%** | 3,283,450 | 3,283,450 | 0 | +| `Maltese.bmp` | 447.238 | 397.023 | **-11.23%** | 7,158,472 | 7,158,472 | 0 | +| `Sunrise.bmp` | 1,512.083 | 1,520.802 | +0.58% | 26,838,825 | 26,838,825 | 0 | +| `compressed_MVT.pbf` | 3.722 | 3.899 | +4.76% | 92,605 | 92,608 | +3 (+0.003%) | + +The meaningful result is the large-image workload: Rainier and Maltese are about 9-11% faster with identical output sizes. The small fixtures and the text/MVT timing deltas are within the run-to-run confidence noise; the only material size changes are +218 bytes for text and +3 bytes for MVT. + +## Experiments rejected + +- An aggressive zlib hash ordering changed match-chain distribution and produced less stable size/time behavior, so it was not retained. +- Removing good-match throttling made the rolling-window parser worse on text, Sunrise, and MVT in the isolation run. The throttle remains. +- The leftover zlib hash ordering in the level-9 overload was found during review and restored before approval. + +## Verification + +- Local `:kflate:jvmTest`: passed. +- Remote Linux `:kflate:jvmTest`: passed. +- Local `:kflate:assemble`: passed for the configured JVM, Native, JS, Wasm, Android, Apple, and other targets. +- Remote benchmark-jar build: passed. +- Astra medium review: approved the corrected diff with no remaining blockers. +- Local and Linux checkouts are on `perf/restore-level6-speed` at the same base commit. + +The commit contains only the six files listed in this report; unrelated worktree changes were left untouched.