From d39973c49f033853db60850043e90c260a827252 Mon Sep 17 00:00:00 2001 From: Matt Bovel Date: Wed, 1 May 2024 17:59:40 +0200 Subject: [PATCH] Simplify AnnotationsMappingBenchmark --- bench-micro/scripts/compare.sh | 38 +++++ bench-micro/scripts/run.sh | 21 --- .../AnnotationsMappingBenchmark.scala | 149 +----------------- 3 files changed, 40 insertions(+), 168 deletions(-) create mode 100755 bench-micro/scripts/compare.sh delete mode 100755 bench-micro/scripts/run.sh diff --git a/bench-micro/scripts/compare.sh b/bench-micro/scripts/compare.sh new file mode 100755 index 000000000000..b8c3bbd7af87 --- /dev/null +++ b/bench-micro/scripts/compare.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +name=$1 +commit_1=$2 +commit_2=$3 +runs=2 + +if [ -z "$name" ] || [ -z "$commit_1" ] || [ -z "$commit_2" ]; then + echo "Usage: $0 " + exit 1 +fi + +run_benchmark() { + jvm=$1 + jvm_coursier_id=$2 + run=$3 + hash=$4 + json_file=results/$name-$jvm-$run.json + txt_file=results/$name-$jvm-$run.txt + echo "Running $name benchmark with JVM $jvm at commit $hash, run $run out of $runs" + git checkout $hash + git clean -fdx + eval "$(coursier java --jvm "$jvm_coursier_id" --env)" + rm -rf "$json_file" "$stdout_file" .bloop .sbt .bsp .metals target + sbt "clean; scala3-bench-micro / Jmh / run -rf JSON -rff $json_file -o $txt_file $name" +} + +read -p "WARNING: this script will brutally reset your Dotty repo (git clean -fdx). Type 'y' to continue." -n 1 -r +echo # new line +if [[ $REPLY =~ ^[Yy]$ ]] +then + for run in $(seq 1 $runs); do + for hash in $commit_1 $commit_2; do + run_benchmark openjdk "adoptium:1.17.0.11" $run $hash + run_benchmark graal "graalvm-java17:22.3.3" $run $hash + done + done +fi diff --git a/bench-micro/scripts/run.sh b/bench-micro/scripts/run.sh deleted file mode 100755 index 06b2445d2391..000000000000 --- a/bench-micro/scripts/run.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -name=$1 -runs=2 - -run_benchmark() { - jvm=$1 - jvm_coursier_id=$2 - run=$3 - json_file=results/$name-$jvm-$run.json - txt_file=results/$name-$jvm-$run.txt - - eval "$(coursier java --jvm "$jvm_coursier_id" --env)" - rm -rf "$json_file" "$stdout_file" .bloop .sbt .bsp .metals target - sbt "clean; scala3-bench-micro / Jmh / run -rf JSON -rff $json_file -o $txt_file $name" -} - -for run in $(seq 1 $runs); do - run_benchmark openjdk "adoptium:1.17.0.11" $run - run_benchmark graal "graalvm-java17:22.3.3" $run -done diff --git a/bench-micro/src/main/scala/dotty/tools/benchmarks/AnnotationsMappingBenchmark.scala b/bench-micro/src/main/scala/dotty/tools/benchmarks/AnnotationsMappingBenchmark.scala index dd2967790454..b320c43fd1e4 100644 --- a/bench-micro/src/main/scala/dotty/tools/benchmarks/AnnotationsMappingBenchmark.scala +++ b/bench-micro/src/main/scala/dotty/tools/benchmarks/AnnotationsMappingBenchmark.scala @@ -38,17 +38,11 @@ class AnnotationsMappingBenchmark: @Param(Array("v1", "v2", "v3", "v4")) var valName: String = null - @Param(Array("current", "oldCheck", "newCheckEquals", "newCheckEq", "noCheck", "noCheckCopySymbols")) - var typeMapName: String = null - @Param(Array("id", "mapInts")) var typeFunctionName: String = null @Setup(Level.Iteration) def setup(): Unit = - /** A custom phase that is used to retrieve the `Type`s and `Context` to be - * used in the benchmark. - */ val testPhase = new Phase: final override def phaseName = "testPhase" @@ -58,20 +52,15 @@ class AnnotationsMappingBenchmark: specialIntTp = pkg.requiredClass("Test").requiredType("SpecialInt").typeRef context = ctx - /** A custom compiler that only runs the `Parser`, `TyperPhase` and - * `testPhase`. - */ val compiler = new Compiler: private final val baseCompiler = new Compiler() final override def phases = List(List(Parser()), List(TyperPhase()), List(testPhase)) - /** A custom driver that uses `compiler`. */ val driver = new Driver: final override def newCompiler(using Context): Compiler = compiler - // Runs the driver with the test file. driver.process(Array("-classpath", System.getProperty("BENCH_CLASS_PATH"), "tests/someAnnotatedTypes.scala")) typeFunction = @@ -80,142 +69,8 @@ class AnnotationsMappingBenchmark: case "mapInts" => tp => (if tp frozen_=:= defn.IntType then specialIntTp else tp) case _ => throw new IllegalArgumentException(s"Unknown type function: $typeFunctionName") - /** Creates a new `TypeMap` that uses `mapConcreteAnnotationWith` to map - * concrete annotations. It is used to compare several ways to map these - * annotations. - */ - def makeTypeMap(mapConcreteAnnotationWith: (ConcreteAnnotation, TypeMap) => Context ?=> Annotation) = + typeMap = new TypeMap(using context): final override def apply(tp: Type): Type = typeFunction(mapOver(tp)) - final override def mapOver(tp: Type) = - tp match - case tp @ AnnotatedType(underlying, annot) => - val underlying1 = this(underlying) - val annot1 = - annot match - case annot: ConcreteAnnotation => mapConcreteAnnotationWith(annot, this) - case _ => annot.mapWith(this) - if annot1 eq EmptyAnnotation then underlying1 - else derivedAnnotatedType(tp, underlying1, annot1) - case _ => super.mapOver(tp) - - /** Retrieves all argument from a tree. This old implementation does not - * include type arguments. - */ - def oldAllArguments(tree: Tree)(using Context): List[Tree] = - tpd.unsplice(tree) match - case Apply(fn, args) => oldAllArguments(fn) ::: args - case TypeApply(fn, _) => oldAllArguments(fn) - case Block(_, expr) => oldAllArguments(expr) - case _ => Nil - - /** This is the old (<= d1489734b7) implementation of `Annotation.mapWith`. - * It 1. does not include type arguments and 2. uses `frozen_=:=` to - * compare types and 3. does not copy all symbols. - */ - def oldMapWith(annot: ConcreteAnnotation, tm: TypeMap)(using Context): Annotation = - val tree = annot.tree - val args = oldAllArguments(tree) - if args.isEmpty then annot - else - val findDiff = new TreeAccumulator[Type]: - def apply(x: Type, tree: Tree)(using Context): Type = - if tm.isRange(x) then x - else - val tp1 = tm(tree.tpe) - foldOver(if tp1 frozen_=:= tree.tpe then x else tp1, tree) - val diff = findDiff(NoType, args) - if tm.isRange(diff) then EmptyAnnotation - else if diff.exists then annot.derivedAnnotation(tm.mapOver(tree)) - else annot - - /** Retrieves all argument from a tree, including type arguments. */ - def newAllArguments(tree: Tree)(using Context): List[Tree] = - tpd.unsplice(tree) match - case Apply(fn, args) => newAllArguments(fn) ::: args - case TypeApply(fn, args) => newAllArguments(fn) ::: args - case Block(_, expr) => newAllArguments(expr) - case _ => Nil - - /** This is the new implementation of `Annotation.mapWith`. It 1. includes - * type arguments and 2. uses `==` to compare types and 3. copies all - * symbols by using a custom `TreeTypeMap` that overrides `withMappedSyms`. - */ - def newMapWithEquals(annot: ConcreteAnnotation, tm: TypeMap)(using Context): Annotation = - val tree = annot.tree - val args = newAllArguments(tree) - if args.isEmpty then annot - else - val findDiff = new TreeAccumulator[Type]: - def apply(x: Type, tree: Tree)(using Context): Type = - if tm.isRange(x) then x - else - val tp1 = tm(tree.tpe) - foldOver(if tp1 == tree.tpe then x else tp1, tree) - val diff = findDiff(NoType, args) - if tm.isRange(diff) then EmptyAnnotation - else if diff.exists then - val ttm = - new TreeTypeMap(tm): - final override def withMappedSyms(syms: List[Symbol]): TreeTypeMap = - withMappedSyms(syms, mapSymbols(syms, this, mapAlways = true)) - annot.derivedAnnotation(ttm.transform(tree)) - else annot - - /** Exactly the same as `newMapWithEquals`, but uses `eq` instead of `==` to - * compare types. - */ - def newMapWithEq(annot: ConcreteAnnotation, tm: TypeMap)(using Context): Annotation = - val tree = annot.tree - val args = newAllArguments(tree) - if args.isEmpty then annot - else - val findDiff = new TreeAccumulator[Type]: - def apply(x: Type, tree: Tree)(using Context): Type = - if tm.isRange(x) then x - else - val tp1 = tm(tree.tpe) - foldOver(if tp1 eq tree.tpe then x else tp1, tree) - val diff = findDiff(NoType, args) - if tm.isRange(diff) then EmptyAnnotation - else if diff.exists then - val ttm = - new TreeTypeMap(tm): - final override def withMappedSyms(syms: List[Symbol]): TreeTypeMap = - withMappedSyms(syms, mapSymbols(syms, this, mapAlways = true)) - annot.derivedAnnotation(ttm.transform(tree)) - else annot - - def noCheckMapWith(annot: ConcreteAnnotation, tm: TypeMap)(using Context): Annotation = - annot.derivedAnnotation(tm.mapOver(annot.tree)) - - def noCheckCopySymbolsMapWith(annot: ConcreteAnnotation, tm: TypeMap)(using Context): Annotation = - val ttm = - new TreeTypeMap(tm): - final override def withMappedSyms(syms: List[Symbol]): TreeTypeMap = - withMappedSyms(syms, mapSymbols(syms, this, mapAlways = true)) - annot.derivedAnnotation(ttm.transform(annot.tree)) - - typeMap = - typeMapName match - case "current" => - new TypeMap(using context): - final override def apply(tp: Type): Type = typeFunction(mapOver(tp)) - case "oldCheck" => - makeTypeMap(oldMapWith) - case "newCheckEquals" => - // This should be the same as `current`, modulo a few indirections. - makeTypeMap(newMapWithEq) - case "newCheckEq" => - makeTypeMap(newMapWithEq) - case "noCheck" => - makeTypeMap(noCheckMapWith) - case "noCheckCopySymbols" => - makeTypeMap(noCheckCopySymbolsMapWith) - case _ => - throw new IllegalArgumentException(s"Unknown type map: $typeMapName") - @Benchmark - def applyTypeMap() = - val res = typeMap.apply(tp) - // println(res.show(using context)) + @Benchmark def applyTypeMap() = typeMap.apply(tp)