I have an entity that generates Scala functions compiled dynamically using Scala 2’s runtime reflection. My case is slightly more convoluted, but the following showcases the issue:
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
object Generator {
val toolbox =
reflect.runtime.currentMirror.mkToolBox()
def generate(value: Long): Long => Long =
toolbox.eval(q"(x: Long) => x + $value").asInstanceOf[Long => Long]
}
I have observed that evaluation performance degrades significantly the more compiled functions are being executed in sequence. For instance, the following JMH benchmark:
import java.util.concurrent.TimeUnit
import scala.util.Random
import org.openjdk.jmh.annotations._
@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.NANOSECONDS)
class BenchmarkGenerator {
@Param(Array("1", "10", "100", "1000", "10000"))
var nFunctions: String = _
var evalF: List[Long => Long] = _
@Setup
def setup() =
evalF = (0 until nFunctions.toInt).map(_ => Generator.generate(Random.nextLong(100000000L))).toList
@Benchmark
def evaluate() =
evalF.foreach(_(1L))
}
Yields the following results in my machine:
Benchmark (nFunctions) Mode Cnt Score Error Units
BenchmarkGenerator.evaluate 1 avgt 5 1.320 ± 0.020 ns/op
BenchmarkGenerator.evaluate 10 avgt 5 38.683 ± 0.249 ns/op
BenchmarkGenerator.evaluate 100 avgt 5 410.243 ± 4.137 ns/op
BenchmarkGenerator.evaluate 1000 avgt 5 14797.026 ± 1003.635 ns/op
BenchmarkGenerator.evaluate 10000 avgt 5 869938.386 ± 307011.008 ns/op
I was expecting a near-linear growth of the execution times, but that’s not the case here.
I don’t think this is related to the number of functions being compiled, since if I compile any number of functions but just repeatedly execute a single one I get the same execution times back. I suspect the compiled functions are being unloaded by the JVM, which makes things significantly slower the next time they need to be executed.
Is there a way to inspect what is going on and to address this issue (possibly by tuning the JVM)?
2