Add benchmark

This commit is contained in:
Eugene Yokota 2026-05-24 04:27:37 -04:00
parent cab1397dd7
commit c40beae1ff
4 changed files with 75 additions and 0 deletions

View File

@ -396,6 +396,17 @@ lazy val utilCache = project
addSbtCompilerInterface,
)
lazy val hashBenchmark = (project in file("internal") / "hash-benchmark")
.dependsOn(utilControl, utilCache)
.enablePlugins(JmhPlugin)
.settings(
utilCommonSettings,
name := "Hash Benchmark",
Jmh / run / javaOptions ++= Seq("-Xmx1G", "-Dfile.encoding=UTF8"),
mimaSettings,
publish / skip := true,
)
// Builds on cache to provide caching for filesystem-related operations
lazy val utilTracking = (project in file("util-tracking"))
.dependsOn(utilCache)

View File

@ -0,0 +1,60 @@
package sbt.internal.util
import java.util.concurrent.{ ThreadLocalRandom, TimeUnit }
import net.openhft.hashing.LongHashFunction
import org.openjdk.jmh.annotations.*
import sbt.util.Digest
import sbt.internal.util.hashing.Hashing
import scala.util.hashing.MurmurHash3
@State(Scope.Benchmark)
abstract class AbstractHashBenchmark:
def hash(buf: Array[Byte]): String
val buf: Array[Byte] = new Array[Byte](2048)
ThreadLocalRandom.current().nextBytes(buf)
@Benchmark
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.MICROSECONDS)
def hashByteArray: Unit =
hash(buf)
end AbstractHashBenchmark
class XXHash64HashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
val h = Hashing.xxhash64
val hash = h.hash(buf, 0, buf.size, 0)
java.lang.Long.toHexString(hash)
class WyHash64HashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
val h = Hashing.wyhash64
val hash = h.hash(buf, 0, buf.size, 0)
java.lang.Long.toHexString(hash)
class FarmHashHashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
val hash = LongHashFunction.farmNa().hashBytes(buf)
java.lang.Long.toHexString(hash)
class MurmurHash32HashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
val lo = MurmurHash3.bytesHash(buf, 0x85ebca6b)
val hash = lo.toLong & 0xffffffffL
java.lang.Long.toHexString(hash)
class MurmurHash64HashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
val hi = MurmurHash3.bytesHash(buf, 0x9747b28c)
val lo = MurmurHash3.bytesHash(buf, 0x85ebca6b)
val hash = (hi.toLong << 32) | (lo.toLong & 0xffffffffL)
java.lang.Long.toHexString(hash)
class Md5HashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
Digest.md5Hash(buf).toString
class Sha256HashBenchmark extends AbstractHashBenchmark:
override def hash(buf: Array[Byte]): String =
Digest.sha256Hash(buf).toString

View File

@ -13,5 +13,6 @@ addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.4.0")
addDependencyTreePlugin
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.14.5")
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.7")
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.8")
// libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value

View File

@ -67,6 +67,9 @@ object Digest:
def sha256Hash(digests: Digest*): Digest =
sha256Hash(digests.toSeq.map(_.toBytes).flatten.toArray[Byte])
private[sbt] def md5Hash(bytes: Array[Byte]): Digest =
apply(Md5, hashBytes(Md5, bytes), bytes.length)
// first check the file size, then the hash
def sameDigest(path: Path, digest: Digest): Boolean =
if Files.size(path) != digest.sizeBytes then false