mirror of
https://github.com/digital-asset/daml.git
synced 2024-09-19 16:57:40 +03:00
Benchmarks for Speedy/DAML-LF/Protobuf translations [DPP-104] (#8272)
* Fix typos and inconsistencies * Implement toString for SRequiresOnLedger * Add benchmarks changelog_begin changelog_end * Add copyright headers * Make SubmissionBuilder final * Address missing reference ledger export on Windows * Fix README.md * Add clarification on README.md * Limit visibility of reference ledger export output * Ensure benchmark recognizes the optionality of exercise return values * Address https://github.com/digital-asset/daml/pull/8272#discussion_r542194308 * Follow up to changes from https://github.com/digital-asset/daml/pull/8273
This commit is contained in:
parent
7375afd4f3
commit
6580dbd15c
@ -192,7 +192,7 @@ private[engine] final class ValueTranslator(compiledPackages: CompiledPackages)
|
||||
}
|
||||
case Some(labeledRecords) =>
|
||||
recordFlds.map {
|
||||
case ((lbl, typ)) =>
|
||||
case (lbl, typ) =>
|
||||
labeledRecords
|
||||
.get(lbl)
|
||||
.fold(fail(s"Missing record label $lbl for record $typeRecordId")) { v =>
|
||||
|
@ -148,7 +148,7 @@ private[lf] object Anf {
|
||||
private[this] type Tx[T, A] = (DepthA, T, K[AExpr, A]) => Trampoline[A]
|
||||
|
||||
/**
|
||||
* K Is the type for contiunations.
|
||||
* K Is the type for continuations.
|
||||
*
|
||||
* @tparam T Type the function would have returned had it not been in CPS.
|
||||
* @tparam A The return type of the continuation (minus the Trampoline
|
||||
|
@ -29,7 +29,9 @@ object SError {
|
||||
/** Operation is only supported in on-ledger mode but was
|
||||
* called in off-ledger mode.
|
||||
*/
|
||||
final case class SRequiresOnLedger(operation: String) extends SError
|
||||
final case class SRequiresOnLedger(operation: String) extends SError {
|
||||
override def toString = s"Requires on-ledger mode: " + operation
|
||||
}
|
||||
|
||||
def crash[A](reason: String): A =
|
||||
throw SErrorCrash(reason)
|
||||
|
@ -9,7 +9,7 @@ import com.daml.lf.data.{FrontStack, Ref}
|
||||
import com.daml.lf.speedy.SResult._
|
||||
import com.daml.lf.speedy.SValue._
|
||||
import com.daml.lf.speedy.SExpr.{SEApp, SEMakeClo, SEImportValue, SELocA}
|
||||
import com.daml.lf.value.{Value}
|
||||
import com.daml.lf.value.Value
|
||||
import com.daml.lf.value.test.TypedValueGenerators.genAddend
|
||||
import com.daml.lf.value.test.ValueGenerators.{cidV0Gen, comparableCoidsGen}
|
||||
import com.daml.lf.PureCompiledPackages
|
||||
|
@ -651,7 +651,7 @@ object Ast {
|
||||
returnType: Type,
|
||||
update: E
|
||||
): GenTemplateChoice[E] =
|
||||
new GenTemplateChoice(
|
||||
GenTemplateChoice(
|
||||
name,
|
||||
consuming,
|
||||
controllers,
|
||||
|
@ -88,7 +88,7 @@ object Util {
|
||||
// A package undefined w.r.t. the function `packages` is treated as a sink.
|
||||
def dependenciesInTopologicalOrder(
|
||||
pkgIds: List[Ref.PackageId],
|
||||
packages: Ref.PackageId PartialFunction Package,
|
||||
packages: PartialFunction[Ref.PackageId, Package],
|
||||
): List[Ref.PackageId] = {
|
||||
|
||||
@tailrec
|
||||
|
@ -22,7 +22,7 @@ object ValueCoder {
|
||||
import Value.MAXIMUM_NESTING
|
||||
|
||||
/**
|
||||
* Error type for signalling errors occuring during decoding serialized values
|
||||
* Error type for signalling errors occurring during decoding serialized values
|
||||
* @param errorMessage description
|
||||
*/
|
||||
final case class DecodeError(errorMessage: String)
|
||||
@ -35,7 +35,7 @@ object ValueCoder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Error type for signalling errors occuring during encoding values
|
||||
* Error type for signalling errors occurring during encoding values
|
||||
* @param errorMessage description
|
||||
*/
|
||||
final case class EncodeError(errorMessage: String)
|
||||
@ -51,7 +51,7 @@ object ValueCoder {
|
||||
private[lf] def encode(contractId: Cid): proto.ContractId
|
||||
}
|
||||
|
||||
@deprecated("use CidEndocer", since = "1.1.2")
|
||||
@deprecated("use CidEncoder", since = "1.1.2")
|
||||
val AbsCidDecoder = CidEncoder
|
||||
|
||||
object CidEncoder extends EncodeCid[ContractId] {
|
||||
|
@ -202,6 +202,7 @@ client_server_build(
|
||||
"--contract-id-seeding=testing-weak",
|
||||
"--participant participant-id=%s,port=%d" % (REFERENCE_LEDGER_EXPORT_NAME, REFERENCE_LEDGER_EXPORT_PORT),
|
||||
],
|
||||
visibility = [":__subpackages__"],
|
||||
) if not is_windows else None
|
||||
|
||||
# Test for checking the integrity of the ledger export produced above.
|
||||
|
@ -9,6 +9,7 @@ load(
|
||||
"da_scala_test",
|
||||
"lf_scalacopts",
|
||||
)
|
||||
load("@os_info//:os_info.bzl", "is_windows")
|
||||
|
||||
da_scala_library(
|
||||
name = "tools",
|
||||
@ -125,3 +126,31 @@ da_scala_benchmark_jmh(
|
||||
"@maven//:org_scalaz_scalaz_core_2_12",
|
||||
],
|
||||
)
|
||||
|
||||
da_scala_benchmark_jmh(
|
||||
name = "benchmark-codec",
|
||||
srcs = glob(["codec-benchmark/src/benchmark/scala/**/*.scala"]),
|
||||
data = [
|
||||
"//ledger/participant-state/kvutils:reference-ledger-export.out",
|
||||
] if not is_windows else [],
|
||||
max_heap_size = "4g",
|
||||
scalacopts = lf_scalacopts,
|
||||
tags = [
|
||||
"manual",
|
||||
],
|
||||
deps = [
|
||||
"//bazel_tools/runfiles:scala_runfiles",
|
||||
"//daml-lf/archive:daml_lf_archive_reader",
|
||||
"//daml-lf/archive:daml_lf_dev_archive_proto_java",
|
||||
"//daml-lf/data",
|
||||
"//daml-lf/engine",
|
||||
"//daml-lf/interpreter",
|
||||
"//daml-lf/language",
|
||||
"//daml-lf/transaction",
|
||||
"//daml-lf/transaction:transaction_proto_java",
|
||||
"//daml-lf/transaction:value_proto_java",
|
||||
"//ledger/participant-state/kvutils",
|
||||
"@maven//:com_google_protobuf_protobuf_java",
|
||||
"@maven//:org_scalaz_scalaz_core_2_12",
|
||||
],
|
||||
)
|
||||
|
@ -0,0 +1,82 @@
|
||||
### Value and transaction coding benchmarks
|
||||
|
||||
#### Running
|
||||
|
||||
To run the benchmarks with the default input data, simply run:
|
||||
|
||||
bazel run //ledger/participant-state/kvutils/tools:benchmark-codec
|
||||
|
||||
The default input data is the reference ledger export. It cannot be used as a
|
||||
reliable source to compare performances between commits, as the content of the
|
||||
export may vary over time. This should, however, provide a good dataset to
|
||||
have a tight feedback loop on improvements to the translation between Speedy,
|
||||
DAML-LF, and Protobuf objects and messages.
|
||||
|
||||
To run the benchmarks with a custom ledger export, you can run the following:
|
||||
|
||||
bazel run //ledger/participant-state/kvutils/tools:benchmark-codec -- \
|
||||
-p ledgerExport=/absolute/path/to/a/ledger/export.bin
|
||||
|
||||
Please ensure to use an absolute path, as this will be run in a Bazel sandbox
|
||||
whose working directory is unlikely to be yours.
|
||||
|
||||
There are two main use cases to pass a specific ledger export:
|
||||
|
||||
1. evaluate performance improvements over specific datasets, to address edge cases
|
||||
2. compare the performance improvements of two commits using the same dataset so
|
||||
that the outcomes are comparable
|
||||
|
||||
Note that each benchmark will consume the ledger export in its entirety, so it's
|
||||
probably better to limit its size.
|
||||
|
||||
Note that `-p` is a [JMH](https://github.com/openjdk/jmh) option. You can see
|
||||
all available options by running:
|
||||
|
||||
bazel run //ledger/participant-state/kvutils/tools:benchmark-codec -- -h
|
||||
|
||||
JMH is mature and rich of features, ranging from setting up the run to gather
|
||||
profiling information, persisting the results, tuning the JVM and much more.
|
||||
|
||||
You are **strongly** advised to have a look at the available options to make sure
|
||||
you run the benchmarks that are relevant to you with the proper settings.
|
||||
|
||||
##### Examples
|
||||
|
||||
* Run only serialization benchmarks (see [Terminology](#terminology)) forking once,
|
||||
with default data, five warm-up iterations and ten measured iterations:
|
||||
|
||||
bazel run //ledger/participant-state/kvutils/tools:benchmark-codec -- \
|
||||
-f 1 -wi 5 -i 10 ".*Deserialize.*"
|
||||
|
||||
* Run only transaction benchmarks forking once, with default data, five warm-up
|
||||
iterations and five measured iterations, forcing GC between iterations,
|
||||
reporting the average time:
|
||||
|
||||
bazel run //ledger/participant-state/kvutils/tools:benchmark-codec -- \
|
||||
-f 1 -wi 5 -i 5 -gc true -bm avgt -tu ms ".*Transaction.*"
|
||||
|
||||
* List the benchmarks selected by the provided filter and exit:
|
||||
|
||||
bazel run //ledger/participant-state/kvutils/tools:benchmark-codec -- -l ".*engine.*"
|
||||
|
||||
#### Terminology
|
||||
|
||||
* _serialize_: translate from a Protobuf object to its serialized from
|
||||
* _deserialize_: translate a serialized Protobuf message into its object representation
|
||||
* _encode_: translate a Protobuf object to a DAML-LF object
|
||||
* _decode_: translate a DAML-LF object to a Protobuf object
|
||||
|
||||
#### Known issues
|
||||
|
||||
##### SLF4J warning
|
||||
|
||||
On the first warm-up iteration, a warning by SLF4J appears. This does not cause any
|
||||
functional issue with the benchmarks. A first analysis seems to point at the need
|
||||
to ensure the runtime dependencies (like the Logback Classic JAR) are correctly
|
||||
forwarded to the JMH artifact ultimately produced by the Bazel `scala_benchmark_jmh`
|
||||
rule.
|
||||
|
||||
##### Failure to run the benchmarks without an explicit export file on Windows
|
||||
|
||||
On Windows the build does not produce the reference ledger export. On Windows, you
|
||||
must explicitly pass a ledger export to the benchmarks in order to run them.
|
@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.{
|
||||
BenchmarkWithLedgerExport,
|
||||
DecodedTransaction,
|
||||
EncodedTransaction,
|
||||
assertDecode
|
||||
}
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class DecodeTransactionBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var encodedTransactions: Vector[EncodedTransaction] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
encodedTransactions = submissions.transactions
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[DecodedTransaction] =
|
||||
encodedTransactions.map(assertDecode)
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, DecodedValue, EncodedValue, assertDecode}
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class DecodeValueBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var encodedValues: Vector[EncodedValue] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
encodedValues = submissions.values.map(_.value).toVector
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[DecodedValue] =
|
||||
encodedValues.map(assertDecode)
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, EncodedTransaction}
|
||||
import com.google.protobuf.ByteString
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class DeserializeTransactionBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var protobufTransactions: Vector[ByteString] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
val encodedTransactions = submissions.transactions
|
||||
protobufTransactions = encodedTransactions.map(_.toByteString)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[EncodedTransaction] =
|
||||
protobufTransactions.map(EncodedTransaction.deserialize)
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, EncodedValue}
|
||||
import com.google.protobuf.ByteString
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class DeserializeValueBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var protobufValues: Vector[ByteString] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
val encodedValues = submissions.values.map(_.value).toVector
|
||||
protobufValues = encodedValues.map(_.toByteString)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[EncodedValue] =
|
||||
protobufValues.map(EncodedValue.deserialize)
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark._
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class EncodeTransactionBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var decodedTransactions: Vector[DecodedTransaction] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
val encodedTransactions = submissions.transactions
|
||||
decodedTransactions = encodedTransactions.map(assertDecode)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[EncodedTransaction] =
|
||||
decodedTransactions.map(assertEncode)
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark._
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class EncodeValueBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var decodedValues: Vector[DecodedValue] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
val encodedValues = submissions.values.map(_.value).toVector
|
||||
decodedValues = encodedValues.map(assertDecode)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[EncodedValue] =
|
||||
decodedValues.map(assertEncode)
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, EncodedTransaction}
|
||||
import com.google.protobuf.ByteString
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class SerializeTransactionBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var encodedTransactions: Vector[EncodedTransaction] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
encodedTransactions = submissions.transactions
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[ByteString] =
|
||||
encodedTransactions.map(_.toByteString)
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, EncodedValue}
|
||||
import com.google.protobuf.ByteString
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class SerializeValueBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
var encodedValues: Vector[EncodedValue] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
encodedValues = submissions.values.map(_.value).toVector
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[ByteString] =
|
||||
encodedValues.map(_.toByteString)
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.benchmark
|
||||
|
||||
import java.nio.file.{Files, Paths}
|
||||
|
||||
import com.daml.bazeltools.BazelRunfiles
|
||||
import com.daml.ledger.participant.state.kvutils.DamlKvutils.DamlSubmission
|
||||
import com.daml.ledger.participant.state.kvutils.Envelope
|
||||
import com.daml.ledger.participant.state.kvutils.`export`.ProtobufBasedLedgerDataImporter
|
||||
import com.daml.lf.archive.Decode
|
||||
import com.google.protobuf.ByteString
|
||||
import org.openjdk.jmh.annotations.{Param, Scope, Setup, State}
|
||||
|
||||
import scala.collection.JavaConverters.iterableAsScalaIterableConverter
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
abstract class BenchmarkWithLedgerExport {
|
||||
|
||||
@Param(Array(""))
|
||||
var ledgerExport: String = _
|
||||
|
||||
protected var submissions: Submissions = _
|
||||
|
||||
@Setup
|
||||
def setup(): Unit = {
|
||||
|
||||
if (ledgerExport.isEmpty) {
|
||||
ledgerExport = referenceLedgerExportPath
|
||||
}
|
||||
|
||||
val source = Paths.get(ledgerExport)
|
||||
|
||||
if (Files.notExists(source)) {
|
||||
throw new IllegalArgumentException(s"Ledger export file not found at $ledgerExport")
|
||||
}
|
||||
|
||||
val builder = Submissions.newBuilder()
|
||||
|
||||
def decodeEnvelope(envelope: ByteString): Unit =
|
||||
Envelope.open(envelope).fold(sys.error, identity) match {
|
||||
case Envelope.SubmissionMessage(submission)
|
||||
if submission.getPayloadCase == DamlSubmission.PayloadCase.PACKAGE_UPLOAD_ENTRY =>
|
||||
for (archive <- submission.getPackageUploadEntry.getArchivesList.asScala) {
|
||||
builder += Decode.decodeArchive(archive)
|
||||
}
|
||||
case Envelope.SubmissionMessage(submission)
|
||||
if submission.getPayloadCase == DamlSubmission.PayloadCase.TRANSACTION_ENTRY =>
|
||||
builder += submission.getTransactionEntry.getTransaction
|
||||
case Envelope.SubmissionBatchMessage(batch) =>
|
||||
for (submission <- batch.getSubmissionsList.asScala) {
|
||||
decodeEnvelope(submission.getSubmission)
|
||||
}
|
||||
case _ =>
|
||||
()
|
||||
}
|
||||
|
||||
val importer = ProtobufBasedLedgerDataImporter(source)
|
||||
try {
|
||||
for ((submissionInfo, _) <- importer.read()) {
|
||||
decodeEnvelope(submissionInfo.submissionEnvelope)
|
||||
}
|
||||
} finally {
|
||||
importer.close()
|
||||
}
|
||||
|
||||
submissions = builder.result()
|
||||
}
|
||||
|
||||
private val relativeReferenceLedgerExportPath: String =
|
||||
"ledger/participant-state/kvutils/reference-ledger-export.out"
|
||||
|
||||
private val referenceLedgerExportPath: String =
|
||||
BazelRunfiles.rlocation(relativeReferenceLedgerExportPath)
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.benchmark
|
||||
|
||||
import com.daml.lf.CompiledPackages
|
||||
import com.daml.lf.data.Ref.PackageId
|
||||
import com.daml.lf.language.Ast.Package
|
||||
import com.daml.lf.transaction.TransactionOuterClass.Transaction
|
||||
|
||||
private[lf] object Submissions {
|
||||
|
||||
def newBuilder(): SubmissionsBuilder =
|
||||
new SubmissionsBuilder(Map.newBuilder[PackageId, Package], Vector.newBuilder[Transaction])
|
||||
|
||||
}
|
||||
|
||||
private[lf] final case class Submissions(
|
||||
compiledPackages: CompiledPackages,
|
||||
transactions: Vector[EncodedTransaction],
|
||||
) {
|
||||
def values: Iterator[EncodedValueWithType] = {
|
||||
val extract = new TypedValueExtractor(compiledPackages.signatures)
|
||||
transactions.iterator.flatMap(extract.fromTransaction)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.benchmark
|
||||
|
||||
import com.daml.lf.PureCompiledPackages
|
||||
import com.daml.lf.data.Ref.PackageId
|
||||
import com.daml.lf.language.Ast.Package
|
||||
import com.daml.lf.transaction.TransactionOuterClass.Transaction
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
final class SubmissionsBuilder(
|
||||
packages: mutable.Builder[(PackageId, Package), Map[PackageId, Package]],
|
||||
transactions: mutable.Builder[Transaction, Vector[Transaction]],
|
||||
) {
|
||||
def +=(fullPackage: (PackageId, Package)): Unit = {
|
||||
packages += fullPackage
|
||||
()
|
||||
}
|
||||
def +=(transaction: Transaction): Unit = {
|
||||
transactions += transaction
|
||||
()
|
||||
}
|
||||
def result(): Submissions =
|
||||
Submissions(
|
||||
PureCompiledPackages(packages.result()).fold(sys.error, identity),
|
||||
transactions.result(),
|
||||
)
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.benchmark
|
||||
|
||||
import com.daml.lf.language.Ast.Type
|
||||
|
||||
private[benchmark] final case class TypedValue[A](value: A, valueType: Type) {
|
||||
def mapValue[B](f: A => B): TypedValue[B] = TypedValue(f(value), valueType)
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.benchmark
|
||||
|
||||
import com.daml.lf.data.Ref._
|
||||
import com.daml.lf.language.Ast.{PackageSignature, TTyCon}
|
||||
import com.daml.lf.value.ValueOuterClass.Identifier
|
||||
|
||||
import scala.collection.JavaConverters.{asScalaIteratorConverter, iterableAsScalaIterableConverter}
|
||||
|
||||
final class TypedValueExtractor(signatures: PartialFunction[PackageId, PackageSignature]) {
|
||||
|
||||
def fromTransaction(transaction: EncodedTransaction): Iterator[EncodedValueWithType] =
|
||||
transaction.getNodesList.iterator.asScala.flatMap { node =>
|
||||
if (node.hasCreate) {
|
||||
val create = node.getCreate
|
||||
val (packageId, qualifiedName) =
|
||||
validateIdentifier(create.getContractInstance.getTemplateId)
|
||||
val template =
|
||||
signatures(packageId).lookupTemplate(qualifiedName).fold(sys.error, identity)
|
||||
val argument =
|
||||
TypedValue(
|
||||
create.getContractInstance.getValue,
|
||||
TTyCon(TypeConName(packageId, qualifiedName)),
|
||||
)
|
||||
val key =
|
||||
template.key.map(key => TypedValue(create.getKeyWithMaintainers.getKey, key.typ))
|
||||
argument :: key.toList
|
||||
} else if (node.hasExercise) {
|
||||
val exercise = node.getExercise
|
||||
val (packageId, qualifiedName) =
|
||||
validateIdentifier(exercise.getTemplateId)
|
||||
val template =
|
||||
signatures(packageId).lookupTemplate(qualifiedName).fold(sys.error, identity)
|
||||
val choice = ChoiceName.assertFromString(exercise.getChoice)
|
||||
val argument =
|
||||
TypedValue(
|
||||
exercise.getChosenValue,
|
||||
template.choices(choice).argBinder._2,
|
||||
)
|
||||
val result =
|
||||
if (exercise.hasReturnValue)
|
||||
List(
|
||||
TypedValue(
|
||||
exercise.getReturnValue,
|
||||
template.choices(choice).returnType,
|
||||
)
|
||||
)
|
||||
else
|
||||
Nil
|
||||
argument :: result
|
||||
} else {
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
private def validateIdentifier(templateId: Identifier): (PackageId, QualifiedName) = {
|
||||
val packageId = PackageId.assertFromString(templateId.getPackageId)
|
||||
val qualifiedName = QualifiedName(
|
||||
ModuleName.assertFromSegments(templateId.getModuleNameList.asScala),
|
||||
DottedName.assertFromSegments(templateId.getNameList.asScala),
|
||||
)
|
||||
(packageId, qualifiedName)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.transaction.TransactionCoder.{
|
||||
NidDecoder,
|
||||
NidEncoder,
|
||||
decodeTransaction,
|
||||
encodeTransaction
|
||||
}
|
||||
import com.daml.lf.transaction.TransactionOuterClass.Transaction
|
||||
import com.daml.lf.transaction.{NodeId, VersionedTransaction}
|
||||
import com.daml.lf.value.Value.ContractId
|
||||
import com.daml.lf.value.ValueCoder._
|
||||
import com.daml.lf.value.ValueOuterClass.VersionedValue
|
||||
import com.daml.lf.value.{Value, ValueVersion}
|
||||
import com.google.protobuf.ByteString
|
||||
|
||||
package object benchmark {
|
||||
|
||||
/**
|
||||
* This is the output of a successful call to
|
||||
* [[com.daml.lf.transaction.TransactionCoder.encodeTransaction]].
|
||||
* It's the in-memory representation of the Protobuf message that
|
||||
* describes a transaction, not its serialized form.
|
||||
*/
|
||||
private[lf] type EncodedTransaction = Transaction
|
||||
private[lf] object EncodedTransaction {
|
||||
def deserialize(bytes: ByteString): EncodedTransaction = Transaction.parseFrom(bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the output of a successful call to
|
||||
* [[com.daml.lf.value.ValueCoder.encodeValue]].
|
||||
* It's the in-memory representation of the Protobuf message that
|
||||
* describes a value, not its serialized form.
|
||||
*/
|
||||
private[lf] type EncodedValue = VersionedValue
|
||||
private[lf] object EncodedValue {
|
||||
def deserialize(bytes: ByteString): EncodedValue = VersionedValue.parseFrom(bytes)
|
||||
}
|
||||
|
||||
private[lf] type EncodedValueWithType = TypedValue[EncodedValue]
|
||||
private[lf] type DecodedValueWithType = TypedValue[DecodedValue]
|
||||
|
||||
/**
|
||||
* This is the output of a successful call to
|
||||
* [[com.daml.lf.transaction.TransactionCoder.decodeTransaction]].
|
||||
* It's the DAML-LF representation of a transaction.
|
||||
*/
|
||||
private[lf] type DecodedTransaction = VersionedTransaction[NodeId, ContractId]
|
||||
|
||||
/**
|
||||
* This is the output of a successful call to
|
||||
* [[com.daml.lf.value.ValueCoder.decodeValue]].
|
||||
* It's the DAML-LF representation of a value.
|
||||
*/
|
||||
private[lf] type DecodedValue = Value[ContractId]
|
||||
|
||||
private[lf] def assertDecode(transaction: EncodedTransaction): DecodedTransaction =
|
||||
assertDecode(decode(transaction))
|
||||
|
||||
private[lf] def assertDecode(value: EncodedValue): DecodedValue =
|
||||
assertDecode(decode(value))
|
||||
|
||||
private[lf] def assertEncode(transaction: DecodedTransaction): EncodedTransaction =
|
||||
assertEncode(encode(transaction))
|
||||
|
||||
private[lf] def assertEncode(value: DecodedValue): EncodedValue =
|
||||
assertEncode(encode(value))
|
||||
|
||||
private type DecodeResult[A] = Either[DecodeError, A]
|
||||
private type EncodeResult[A] = Either[EncodeError, A]
|
||||
|
||||
private def assertDecode[A](result: DecodeResult[A]): A =
|
||||
result.fold(e => sys.error(e.errorMessage), identity)
|
||||
|
||||
private def decode(transaction: EncodedTransaction): DecodeResult[DecodedTransaction] =
|
||||
decodeTransaction(NidDecoder, CidDecoder, transaction)
|
||||
|
||||
private def decode(value: EncodedValue): DecodeResult[DecodedValue] =
|
||||
decodeValue(CidDecoder, value)
|
||||
|
||||
private def assertEncode[A](result: EncodeResult[A]): A =
|
||||
result.fold(e => sys.error(e.errorMessage), identity)
|
||||
|
||||
private def encode(transaction: DecodedTransaction): EncodeResult[EncodedTransaction] =
|
||||
encodeTransaction(NidEncoder, CidEncoder, transaction)
|
||||
|
||||
private def encode(value: DecodedValue): EncodeResult[EncodedValue] =
|
||||
encodeVersionedValue(CidEncoder, value, ValueVersion.DevOutputVersions)
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.engine
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, DecodedValue, assertDecode}
|
||||
import com.daml.lf.engine.preprocessing.ValueTranslator
|
||||
import com.daml.lf.speedy.SValue
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class SpeedyToValueBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
private var speedyValues: Vector[SValue] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
val decodedValues = submissions.values.map(_.mapValue(assertDecode)).toVector
|
||||
val translator = new ValueTranslator(submissions.compiledPackages)
|
||||
speedyValues = decodedValues.map(assertTranslate(translator))
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[DecodedValue] =
|
||||
speedyValues.map(_.toValue)
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.engine
|
||||
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, DecodedValueWithType, assertDecode}
|
||||
import com.daml.lf.engine.preprocessing.ValueTranslator
|
||||
import com.daml.lf.speedy.SValue
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class ValueTranslatorBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
private var translator: ValueTranslator = _
|
||||
private var decodedValues: Vector[DecodedValueWithType] = _
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
decodedValues = submissions.values.map(_.mapValue(assertDecode)).toVector
|
||||
translator = new ValueTranslator(submissions.compiledPackages)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[SValue] =
|
||||
decodedValues.map(assertTranslate(translator))
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf
|
||||
|
||||
import com.daml.lf.benchmark.DecodedValueWithType
|
||||
import com.daml.lf.engine.preprocessing.ValueTranslator
|
||||
import com.daml.lf.speedy.SValue
|
||||
|
||||
package object engine {
|
||||
|
||||
private[engine] def assertTranslate(translator: ValueTranslator)(
|
||||
value: DecodedValueWithType,
|
||||
): SValue =
|
||||
translator.translateValue(value.valueType, value.value).fold(e => sys.error(e.msg), identity)
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package com.daml.lf.speedy
|
||||
|
||||
import com.daml.lf.CompiledPackages
|
||||
import com.daml.lf.benchmark.{BenchmarkWithLedgerExport, DecodedValue, assertDecode}
|
||||
import com.daml.lf.data.Time
|
||||
import com.daml.lf.speedy.Speedy.Machine
|
||||
import org.openjdk.jmh.annotations.{Benchmark, Setup}
|
||||
|
||||
class MachineImportValueBenchmark extends BenchmarkWithLedgerExport {
|
||||
|
||||
private var machine: Speedy.Machine = _
|
||||
private var decodedValues: Vector[DecodedValue] = _
|
||||
|
||||
// Construct a machine for testing.
|
||||
private def testingMachine(
|
||||
compiledPackages: CompiledPackages,
|
||||
): Machine = Machine(
|
||||
compiledPackages = compiledPackages,
|
||||
submissionTime = Time.Timestamp.MinValue,
|
||||
initialSeeding = InitialSeeding.NoSeed,
|
||||
expr = null,
|
||||
globalCids = Set.empty,
|
||||
committers = Set.empty,
|
||||
)
|
||||
|
||||
@Setup
|
||||
override def setup(): Unit = {
|
||||
super.setup()
|
||||
decodedValues = submissions.values.map(_.value).map(assertDecode).toVector
|
||||
machine = testingMachine(submissions.compiledPackages)
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
def run(): Vector[Unit] =
|
||||
decodedValues.map(machine.importValue)
|
||||
|
||||
}
|
@ -102,7 +102,7 @@ private[benchmark] final class Adapter(
|
||||
}
|
||||
pkgIds.toSeq match {
|
||||
case Seq(pkgId) => Right(id.copy(packageId = pkgId))
|
||||
case Seq() => Left(s"no package foud for ${id.qualifiedName}")
|
||||
case Seq() => Left(s"no package found for ${id.qualifiedName}")
|
||||
case _ => Left(s"2 or more packages found for ${id.qualifiedName}")
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user