Skip to content

quote pattern match too slow compared to low-level api #22432

Open
@xuwei-k

Description

@xuwei-k

Compiler version

3.6.3

Minimized example

xuwei-k/quote-pattern-match-benchmark@b2f2993

project/plugins.sbt

addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7")

build.sbt

scalaVersion := "3.6.3"

enablePlugins(JmhPlugin)

libraryDependencies += "org.scala-lang" %% "scala3-tasty-inspector" % scalaVersion.value

Main.scala

package example

import scala.quoted._
import scala.tasty.inspector._
import org.openjdk.jmh.annotations.Benchmark

object Main {
  val compilerJarPath: String =
    dotty.tools.dotc.Main.getClass.getProtectionDomain.getCodeSource.getLocation.toURI.toURL.getFile
}

class Main {
  inline def expected: Int = 125

  @Benchmark
  def lowLevelReflection(): Int = {
    var count: Int = 0
    val inspector: Inspector = new Inspector {
      override def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
        import quotes.reflect.*
        val traverser = new quotes.reflect.TreeTraverser {
          override def traverseTree(tree: Tree)(owner: Symbol): Unit = {
            if (tree.isExpr) {
              tree match {
                case Select(obj, "get") if obj.tpe <:< TypeRepr.of[Option[?]] =>
                  count += 1
                case _ =>
                  super.traverseTree(tree)(owner)
              }
            } else {
              super.traverseTree(tree)(owner)
            }
          }
        }
        tastys.foreach { t =>
          traverser.traverseTree(t.ast)(Symbol.spliceOwner)
        }
      }
    }
    TastyInspector.inspectTastyFilesInJar(Main.compilerJarPath)(inspector)
    assert(count == expected)
    count
  }

  @Benchmark
  def quoteMatch(): Int = {
    var count: Int = 0
    val inspector: Inspector = new Inspector {
      override def inspect(using Quotes)(tastys: List[Tasty[quotes.type]]): Unit = {
        import quotes.reflect.*
        val traverser = new quotes.reflect.TreeTraverser {
          override def traverseTree(tree: Tree)(owner: Symbol): Unit = {
            if (tree.isExpr) {
              tree.asExpr match {
                case '{ ($x: Option[t]).get } =>
                  count += 1
                case _ =>
                  super.traverseTree(tree)(owner)
              }
            } else {
              super.traverseTree(tree)(owner)
            }
          }
        }
        tastys.foreach { t =>
          traverser.traverseTree(t.ast)(Symbol.spliceOwner)
        }
      }
    }
    TastyInspector.inspectTastyFilesInJar(Main.compilerJarPath)(inspector)
    assert(count == expected)
    count
  }

}

run sbt "Jmh/run -i 10 -f1 -t1"

Output

[info] Benchmark                 Mode  Cnt  Score   Error  Units
[info] Main.lowLevelReflection  thrpt   10  0.346 ± 0.006  ops/s
[info] Main.quoteMatch          thrpt   10  0.052 ± 0.002  ops/s

0.346 / 0.052 = 6.65

Note

wartremover use many quote pattern matching. but I realized too slow quote pattern matching. I have added workaround

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions