1. Overview

Sometimes we need to measure how much time a single method is taking on our code. In this tutorial, we’ll learn how to calculate the elapsed time of a method in Scala using different approaches.

2. Calculate the Elapsed Time of a Method

There are a few ways of doing this, so let’s go through each.

2.1. Using System Time

The most naive approach relies on using the Java API method System.currentTimeMillis():

scala> val before = System.currentTimeMillis; myMethod(1000000); val totalTime=System.currentTimeMillis-before
before: Long = 1694035209622
totalTime: Long = 803

The System.currentTimeMillis() method returns the current system time in milliseconds. So we can measure the time our method takes as the difference between the moment right before calling our method and the moment right after it completes.

2.2. Using a Wrapper Function

The previous approach offers us an insight into the performance of a method, but it’s a bit cumbersome to use. We can improve it using Scala language features by creating a wrapper function.

scala> def time[T](block: => T): T = {
     |           val before = System.currentTimeMillis
     |           val result = block
     |           val after = System.currentTimeMillis
     |           println("Elapsed time: " + (after - before) + "ms")
     |           result
     | }

We can now call the method using our wrapper:

scala> time(myMethod(1000000))
Elapsed time: 779ms
res0: Unit

This solution is more elegant than the previous one because it hides the timed logic in the wrapper function.

2.3. Micro Benchmarking Using JMH

The previous approaches provide some guidance on how long a method takes to run, but if we want to measure actual production code, we should not rely on such a naive approach.

Because we’re using JVM to run our code, and because the JVM does a ton of performance optimizations to our code, doing performance benchmarks using that approach won’t provide reliable results.

Fortunately, there’s a library for that called JMH. The tool handles things like JVM warm-up and code-optimization paths, making benchmarking as simple as possible. We can find more details about its usage in this guide.

We must take into account that measuring a method’s run time can become much more complicated very easily. For instance, in code where the method has multiple return points. More combinations means it’s harder to measure. We may have to move measurements somewhere else, which may not always be easy.

4. Conclusion

In this article, we’ve learned a naive approach to measure our method’s run time and also briefly discussed a better way – using the micro benchmarking world of JMH.

Comments are closed on this article!