Skip to content

Instantly share code, notes, and snippets.

@dalegaspi
Last active May 7, 2018 01:45
Show Gist options
  • Save dalegaspi/ce6167dc529cb8246e8f0be0f615c91b to your computer and use it in GitHub Desktop.
Save dalegaspi/ce6167dc529cb8246e8f0be0f615c91b to your computer and use it in GitHub Desktop.
A simple stopwatch implementation for wall-clock time measurement of a sync of async method in scala
import com.typesafe.scalalogging.StrictLogging
import monix.eval.Task
import monix.execution.Scheduler
import scala.concurrent.Future
object Stopwatch extends StrictLogging {
/**
* http://biercoff.com/easily-measuring-code-execution-time-in-scala/
*
* @param block
* @param reporter
* @tparam R
* @return
*/
def time[R](block: => R,
taskName: String = "process",
reporter: (String, Long) => Unit = (name, elapsedNanos) => {
logger.info(s"${name} elapsed time ${elapsedNanos} ns")
}): R = {
val t0 = System.nanoTime()
val result = block
val t1 = System.nanoTime()
reporter(taskName, t1 - t0)
result
}
/**
* async version of [[time]]
*
* ok this warrants a bit of explanation since this is something i added
*
* measuring execution time a Future directly is impossible unless you jerry-rig your Future
* with a parameter to kick off the t0 value (which is inelegant).
* why? because Futures are eagerly-evaluated--i.e., they are executed as soon
* as they are evaluated. also, any successive evaluation of the same future
* returns a memoized value.
*
* as of this writing there isn't a native lazily-evaluated Future object. luckily
* there is this awesome library called Monix that has an entity called [[Task]]
* that's essentially a "lazily-evaluated Future". it requires a [[Scheduler]] which is
* more-or-less the [[scala.concurrent.ExecutionContext]] used for execution of the
* resulting [[Future]]
*
* this returns a [[Future]] instead of a [[Task]] since for most use cases you want
* to just time it as is or chain them with other [[Future]]s.
*
* @param block
* @param taskName
* @param reporter
* @param scheduler
* @tparam R
* @return
*/
def timeAsync[R](block: => Task[R],
taskName: String = "process",
reporter: (String, Long) => Unit = (name, elapsedNanos) => {
logger.info(s"${name} elapsed time ${elapsedNanos} ns")
})(implicit scheduler: Scheduler): Future[R] = {
val t0 = System.nanoTime()
val result = block.runAsync
result onComplete {
_ => val t1 = System.nanoTime()
reporter(taskName, t1 - t0)
}
result
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment