Skip to content

Commit

Permalink
Add string interning benchmark (#12237)
Browse files Browse the repository at this point in the history
* Add string interning benchmark

changelog_begin
changelog_end

* Update copyright header
  • Loading branch information
rautenrieth-da authored Jan 11, 2022
1 parent fafb86b commit 4211557
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 0 deletions.
12 changes: 12 additions & 0 deletions ledger/participant-integration-api/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ load("@scala_version//:index.bzl", "scala_major_version", "scala_major_version_s
load("//bazel_tools:proto.bzl", "proto_jars")
load(
"//bazel_tools:scala.bzl",
"da_scala_benchmark_jmh",
"da_scala_binary",
"da_scala_library",
"da_scala_test",
Expand Down Expand Up @@ -431,3 +432,14 @@ filegroup(
srcs = glob(["src/main/scala/**/*.scala"]),
visibility = ["//visibility:public"],
)

da_scala_benchmark_jmh(
name = "string-interning-benchmark",
srcs = glob(["src/bench/platform/store/interning/**/*.scala"]),
visibility = ["//visibility:public"],
deps = [
"//bazel_tools/runfiles:scala_runfiles",
"//ledger/participant-integration-api",
"//libs-scala/contextualized-logging",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.platform.store.interning

import org.openjdk.jmh.annotations.{Level, Param, Scope, Setup, State}

import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.Random

@State(Scope.Benchmark)
abstract class BenchmarkState {
@Param(Array("10000", "100000", "1000000", "10000000"))
var stringCount: Int = _

@Param(Array("10", "100"))
var stringLength: Int = _

protected val perfTestTimeout: FiniteDuration = 5.minutes

protected var entries: Array[(Int, String)] = _
protected var interning: StringInterningView = _
protected var interningEnd: Int = _

protected def extraStringCount = 0

@Setup(Level.Trial)
def setupEntries(): Unit = {
entries = BenchmarkState.createEntries(stringCount + extraStringCount, stringLength)
}
}

object BenchmarkState {

protected val perfTestTimeout: FiniteDuration = 5.minutes

private[this] def randomString(length: Int): String = Random.alphanumeric.take(length).mkString

def createEntries(stringCount: Int, stringLength: Int): Array[(Int, String)] = {
Console.print(
s"Creating an array with $stringCount entries with string length $stringLength..."
)

val entries = new Array[(Int, String)](stringCount)
(0 until stringCount).foreach(i => entries(i) = (i + 1) -> randomString(stringLength))
Console.println(s" done.")

Console.println(s"First few entries: ${entries(0)}, ${entries(1)}, ${entries(2)}, ...")
entries
}

def createInterning(entries: Array[(Int, String)]): StringInterningView = {
Console.print(s"Creating an interning view...")
val interning = new StringInterningView(
loadPrefixedEntries = (fromExclusive, toInclusive) =>
// Note: for slice(), the begin is inclusive and the end is exclusive (opposite of the enclosing call)
_ => Future.successful(entries.view.slice(fromExclusive + 1, toInclusive + 1))
)
Console.println(s" done.")

interning
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.platform.store.interning

import com.daml.logging.LoggingContext
import org.openjdk.jmh.annotations.{
Benchmark,
BenchmarkMode,
Fork,
Level,
Measurement,
Mode,
OutputTimeUnit,
Setup,
Warmup,
}

import java.util.concurrent.TimeUnit
import scala.concurrent.Await

class InitializationTimeBenchmark extends BenchmarkState {
@Setup(Level.Invocation)
def setupIteration(): Unit = {
interning = BenchmarkState.createInterning(entries)
}

@Benchmark
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = 5)
@Warmup(iterations = 5)
@Measurement(iterations = 5)
def run(): Unit = {
Await.result(interning.update(stringCount)(LoggingContext.ForTesting), perfTestTimeout)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2022 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

package com.daml.platform.store.interning

import com.daml.logging.LoggingContext
import org.openjdk.jmh.annotations.{
Benchmark,
BenchmarkMode,
Fork,
Level,
Measurement,
Mode,
Setup,
Warmup,
}

import scala.concurrent.Await

class UpdateTimeBenchmark extends BenchmarkState {
// Set up some extra entries for the repeated update() calls
override def extraStringCount = 10000000

@Setup(Level.Iteration)
def setupIteration(): Unit = {
interning = BenchmarkState.createInterning(entries)

interningEnd = stringCount
Await.result(interning.update(interningEnd)(LoggingContext.ForTesting), perfTestTimeout)
}

@Benchmark
@BenchmarkMode(Array(Mode.Throughput))
@Fork(value = 5)
@Warmup(iterations = 5)
@Measurement(iterations = 5)
def run(): Unit = {
interningEnd = interningEnd + 1
if (interningEnd > entries.length) throw new RuntimeException("Can't ingest any more strings")

Await.result(interning.update(interningEnd)(LoggingContext.ForTesting), perfTestTimeout)
}
}

0 comments on commit 4211557

Please sign in to comment.