# 23 Measuring performance

## 23.1 Profiling

1. Q: Profile the following function with torture = TRUE. What is surprising? Read the source code of rm() to figure out what’s going on.

f <- function(n = 1e5) {
x <- rep(1, n)
rm(x)
}

A: Unfortunately, the current version of profvis throws an error

profvis::profvis(f(), torture = TRUE)

f()
Error in stri_split_regex(string, pattern, n = n, simplify = simplify,  :
unimplemented type 'integer' in 'coerceToInteger'

## 23.2 Microbenchmarking

1. Q: Instead of using bench::mark(), you could use the built-in function system.time(). But system.time() is much less precise, so you’ll need to repeat each operation many times with a loop, and then divide to find the average time of each operation, as in the code below.

n <- 1e6
system.time(for (i in 1:n) sqrt(x)) / n
system.time(for (i in 1:n) x ^ 0.5) / n

How do the estimates from system.time() compare to those from bench::mark()? Why are they different?

A: As bench::mark() doesn’t calculate the mean value, we calculate it from the time list-column in the tibble output.

n <- 1e6
x <- runif(100)

bench_res <- bench::mark(
sqrt(x),
x ^ 0.5
)

# Compute mean across all runs
t_sqrt_bench  <- mean(unlist(bench_res[1, "time"]))
t_power_bench <- mean(unlist(bench_res[2, "time"]))

t_sqrt_systime  <- system.time(for (i in 1:n) sqrt(x)) / n
t_power_systime <- system.time(for (i in 1:n) x ^ 0.5) / n

# Compare the results
t_sqrt_systime["elapsed"]
#>  elapsed
#> 1.02e-06
t_sqrt_bench
#>  1.44e-06

t_power_systime["elapsed"]
#>  elapsed
#> 9.54e-06
t_power_bench
#>  1e-05

Both approaches get the order of magnitude right. The results differ a little and bench::mark() is generally more precise.

1. Q: Here are two other ways to compute the square root of a vector. Which do you think will be fastest? Which will be slowest? Use microbenchmarking to test your answers.

x ^ (1 / 2)
exp(log(x) / 2)

A: Here, we’ll bench::mark the relative execution time of these expressions, with the fastest expression standardized to 1.

x <- runif(100)

bench::mark(x ^ (1 / 2),
exp(log(x) / 2),
relative = TRUE) %>%
dplyr::select(expression, median)
#> # A tibble: 2 x 2
#>   expression    median
#>   <bch:expr>     <dbl>
#> 1 x^(1/2)         1.67
#> 2 exp(log(x)/2)   1

We can see, that x ^ (1 / 2) takes about twice as long as exp(log(x)/2) to calculate the square root of x.