All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scalameter.InvocationCount.scala Maven / Gradle / Ivy

package org.scalameter

import java.io.File
import org.scalameter.Key._
import org.scalameter.execution.invocation.InvocationCountMatcher
import org.scalameter.execution.invocation.instrumentation.{Instrumentation, MethodInvocationCounter, MethodSignature}
import scala.collection.{Seq, mutable}


/** Mixin for all [[org.scalameter.Measurer]] implementations that perform any kind of
 *  method invocation counting.
 */
trait InvocationCount extends Measurer[Map[String, Long]] {
  def matcher: InvocationCountMatcher

  def measure[T](context: Context, measurements: Int, setup: (T) => Any,
    tear: (T) => Any, regen: () => T, snippet: (T) => Any):
  Seq[Quantity[Map[String, Long]]] = {
    val invocations = mutable.ListBuffer.empty[Quantity[Map[String, Long]]]
    var obj: Any = null.asInstanceOf[Any]
    val methodTable = context.goe(exec.measurers.methodInvocationLookupTable,
      sys.error("Measurer.prepareContext should be called before Measurer.measure"))
    val numMethods = methodTable.length

    def measureSnippet(value: T): Any = {
      MethodInvocationCounter.setup(numMethods)
      setup(value)

      MethodInvocationCounter.start()
      val obj = snippet(value)
      MethodInvocationCounter.stop()
      tear(value)

      invocations += Quantity(
        methodTable.map(_.toString).zip(MethodInvocationCounter.counts())
          .groupBy(_._1).map { case (k, v) =>
          k -> v.iterator.map(_._2).sum
        }(collection.breakOut), "#"
      )
      obj
    }

    if (context(exec.assumeDeterministicRun)) {
      obj = measureSnippet(regen())
      val count = invocations.head
      invocations ++= List.fill(measurements - 1)(count)
    } else {
      var iteration = 0
      while (iteration < measurements) {
        obj = measureSnippet(regen())
        iteration += 1
      }
    }

    log.verbose("Measurements: " + invocations.mkString(", "))
    invocations.result()
  }

  override def usesInstrumentedClasspath: Boolean = true

  /** Creates the [[Key.exec.measurers.instrumentedJarPath]] with an abstract temporary
   *  file, the [[Key.exec.measurers.methodInvocationLookupTable]] with an empty
   *  [[scala.collection.mutable.AbstractBuffer]], and the [[Key.finalClasspath]]
   *  with a classpath that consists of an instrumented jar and the [[Key.classpath]].
   *
   *  @param context [[org.scalameter.Context]] that should the setup tree context
   */

  override def prepareContext(context: Context): Context = {
    val cl = context(classpath)
    val jar = File.createTempFile(s"scalameter-bench-", "-instrumented.jar")
    jar.deleteOnExit()

    context ++ Context(
      exec.measurers.methodInvocationLookupTable ->
        mutable.ArrayBuffer.empty[MethodSignature],
      exec.measurers.instrumentedJarPath -> jar,
      finalClasspath -> (jar +: cl)
    )
  }

  /** Creates a jar with instrumented classes under the location pointed by
   *  [[Key.exec.measurers.instrumentedJarPath]], and saves the internal method lookup
   *  table under the [[Key.exec.measurers.methodInvocationLookupTable]].
   *
   *  @param context [[org.scalameter.Context]] that should be a result of the
   *                 [[prepareContext]]
   */
  override def beforeExecution(context: Context) = {
    val jar = context.goe(exec.measurers.instrumentedJarPath,
      sys.error(
        "Measurer.beforeExecution should be called after Measurer.prepareContext"))
    val lookupTable = context.goe(exec.measurers.methodInvocationLookupTable,
      sys.error(
        "Measurer.beforeExecution should be called after Measurer.prepareContext"))

    lookupTable ++= Instrumentation.writeInstrumentedClasses(
      ctx = context, matcher = matcher, to = jar)
  }

  /** Removes instrumented jar from filesystem.
   *
   *  @param context [[org.scalameter.Context]] that should be a result of the
   *                 [[prepareContext]]
   */
  override def afterExecution(context: Context) = {
    val jar = context.goe(exec.measurers.instrumentedJarPath,
      sys.error(
        "Measurer.afterExecution should be called after Measurer.prepareContext"))
    jar.delete()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy