3 Measuring and comparing execution times
The first step before optimizing a code is to measure its execution time, in order to compare timings between different implementations.
For this section and the following we refer to the book Advanced R by Hadley Wickham 3, freely available online.
3.1 Measuring execution times with system.time()
To measure the execution time of an command, you can use the native system.time()
function like this:
obs <- matrix(rep(1.96, 2), nrow=2, ncol=1)
system.time(mvnpdf(x=obs, Log=FALSE))
## user system elapsed
## 0.001 0.000 0.003
The problem that appears in this example is that the execution is so fast that system.time()
displays 0
(or a very close value) that will be impossible to compare to an hopefully faster implementation. Also, we see that there is some variability when we run the command several times.
Thus if we want to compare our code with the mvtnorm::dmvnorm()
function, we can’t use system.time()
:
obs <- rep(1.96, 2)
system.time(mvtnorm::dmvnorm(obs))
## user system elapsed
## 0.003 0.001 0.014
We could imagine that we need to increase the complexity of our calculation to be able to compare them, but there is actually a better way: use the microbenchmark
package !
3.2 Compare execution times with microbenchmark()
As its name indicates, this package allows to compare execution times even when they are very fast. Moreover, each benchmarked expression will be repeatedly evaluated a certain number of times, thus stabilizing its timing estimations.
library(microbenchmark)
mb <- microbenchmark(mvtnorm::dmvnorm(rep(1.96, 2)),
mvnpdf(x = matrix(rep(1.96,2)), Log = FALSE),
times = 1000)
## Warning in microbenchmark(mvtnorm::dmvnorm(rep(1.96, 2)), mvnpdf(x =
## matrix(rep(1.96, : less accurate nanosecond times to avoid potential integer
## overflows
mb
## Unit: microseconds
## expr min lq mean median
## mvtnorm::dmvnorm(rep(1.96, 2)) 20.049 20.992 24.07823 21.566
## mvnpdf(x = matrix(rep(1.96, 2)), Log = FALSE) 18.122 19.188 20.55752 19.639
## uq max neval cld
## 23.247 1598.508 1000 a
## 20.992 103.115 1000 b
Both mvnpdf()
and dmnvorm()
functions being able to take a matrix as input, we can also compare their speeds in this setting:
n <- 100
mb <- microbenchmark(mvtnorm::dmvnorm(matrix(1.96, nrow = n, ncol = 2)),
mvnpdf(x=matrix(1.96, nrow = 2, ncol = n),
Log=FALSE),
times=100)
mb
## Unit: microseconds
## expr min lq
## mvtnorm::dmvnorm(matrix(1.96, nrow = n, ncol = 2)) 23.206 24.518
## mvnpdf(x = matrix(1.96, nrow = 2, ncol = n), Log = FALSE) 266.746 271.338
## mean median uq max neval cld
## 27.9333 25.7275 27.265 79.458 100 a
## 279.4019 274.3720 281.629 331.198 100 b
Something happened… And we will find out what exactly is causing this issue in what comes next.