---
title: "A Short Introduction to rcpptimer"
author: Jonathan Berrisch
date: "`r Sys.Date()`"
output:
  rmarkdown::html_vignette:
    number_sections: no
    toc: no
vignette: >
  %\VignetteIndexEntry{A Short Introduction to rcpptimer}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  # dev = "svg",
  warning = TRUE,
  message = FALSE,
  comment = "#>"
)
Sys.setenv("OMP_THREAD_LIMIT" = 2)
```

This package provides a simple timer for `Rcpp` code. The interface resembles the [tictoc](https://CRAN.R-project.org/package=tictoc) R package. The package wraps [cpptimer](https://github.com/BerriJ/cpptimer), a header-only library that contains a class called `CppTimer`. rcpptimer adds this class as `Timer` to the `Rcpp` namespace. 

This introduction explains how to use `Rcpp::Timer` with `Rcpp::cppFunction` and how:

- You can use multiple (potentially nested) timers
- You can time scopes using `Rcpp::Timer::ScopedTimer`
- You can turn off Warnings

Check out the other vignettes for:

- Using rcpptimer together with `Rcpp::sourceCpp` `vignette("sourceCpp")`
- Adding rcpptimer to a Package `vignette("packages")`
- Automatic and Manual Return of the Timings `vignette("autoreturn")`
- Accessing unprocessed Timings, Resetting and Updating the Timer Results `vignette("advanced")`

## Initialize a Timer

Initializing a timer is simple. There are four constructors available. The default constructor initializes a timer with warnings enabled that will write the results as data.frame called "times" to the R environment:

```c++
Rcpp::Timer timer; // default constructor
Rcpp::Timer timer("my_timer"); // Set a custom name for the results
Rcpp::Timer timer(false); // Disable warnings
Rcpp::Timer timer("my_timer", false); // Set a custom name and disable warnings
```
Below and throughout other vignettes, we will use all four as needed.

## Straightforward Example

With `Rcpp::cppFunction`, we must add the `depends` argument to the function to tell the compiler we want to link the 'rcpptimer' library to the C++ code. Then, we can construct an instance of the `Timer` class and use the `tic` and `toc` methods to measure the time it takes to execute a code block. Here, we allocate some memory to have something to measure:

```{r, eval = TRUE}
Rcpp::cppFunction("
double add(double &x, double &y)
{
 Rcpp::Timer timer;
 timer.tic();
 double z = x + y;
 timer.toc();
 return(z);
}",
  depends = "rcpptimer"
)

add(rnorm(1), runif(1))
```

This function will automatically write a data frame called "times" to the R environment. Read more about that `autoreturn` feature (i.e., how to assign a custom variable name and how to manually handle the results) in `vignette("autoreturn")`. 

The resulting `times` object has two classes: `data.frame` and `rcpptimer`. We provide a custom S3 method for printing the results. If it is registered, it may scale the results to improve readability (see `rcpptimer::print.rcpptimer`). Otherwise, it will print the results using  `base::print.data.frame`.

```{r, eval = TRUE}
print(times)
```

## Multiple Timers

You can also use multiple timers in the same function. The Timers can be nested and overlapping. Just pass a string to the `tic` and `toc` methods to distinguish the timers:

```{r, eval = TRUE}
Rcpp::cppFunction('
double add(double &x, double &y)
{
 Rcpp::Timer timer;
 timer.tic("body");
 timer.tic("add_1");
 timer.tic("add_2");
 double z = x + y;
 timer.toc("add_1");
 timer.toc("add_2");
 timer.toc("body");
 return(z);
}',
  depends = "rcpptimer"
)

add(rnorm(1), runif(1))

print(times)
```

`rcpptimer` will group multiple timers with the same name and calculate summary statistics for them. Consider this more advanced example, which also uses OpenMP:

```c++
// fibonacci.cpp
std::vector<long int> fibonacci_omp(std::vector<long int> n)
{

  Rcpp::Timer timer;

  // This scoped timer measures the total execution time of 'fibonacci'
  Rcpp::Timer::ScopedTimer scpdtmr(timer, "fib_body");

  std::vector<long int> results = n;

#pragma omp parallel for
  for (unsigned int i = 0; i < n.size(); ++i)
  {
    timer.tic("fib_" + std::to_string(n[i]));
    results[i] = fib(n[i]);
    timer.toc("fib_" + std::to_string(n[i]));
  }

  return (results);
}
```

This function is included in rcpptimer, so we can execute it right away: 

```{r, eval = TRUE}
results <- rcpptimer::fibonacci_omp(n = rep(20:25, 10))
print(times)
```

## Timing Scopes with Rcpp::Timer::ScopedTimer

The `ScopedTimer` lets you measure the execution time of scopes. It will call .`.tic()` upon creation and `.toc()` upon destruction. Consider the simple example below:

```{r, eval = TRUE}
Rcpp::cppFunction('
double add(double &x, double &y)
{
 Rcpp::Timer timer;
 Rcpp::Timer::ScopedTimer scoped_timer(timer, "add");
 double z = x + y;
 return(z);
}',
  depends = "rcpptimer"
)

add(rnorm(1), runif(1))

print(times)
```

Note that you only need to initialize the `ScopedTimer`. Once it goes out of scope, the timer will automatically be stopped.

## Warnings and how to Disable them

The default setting will warn about timers that have been started using `.tic` but never stopped using `.toc()` and vice versa. This is useful to catch unmatched `.tic()` and `.toc()` calls that may be unmatched due to missing statements or typos.

For example, the following code will produce two warnings:

```{r, eval = TRUE}
Rcpp::cppFunction('
double add(double &x, double &y)
{
 Rcpp::Timer timer;
 Rcpp::Timer::ScopedTimer scoped_timer(timer, "add");
 timer.tic("add");
 double z = x + y;
 timer.toc("ad");
 return(z);
}',
  depends = "rcpptimer"
)

add(rnorm(1), runif(1))
```

Note that this does not affect terminated timers such as 'mem'. 

```{r, eval = TRUE}
print(times)
```

These warnings occur at runtime. Unfortunately, we can't check for this at compile time.

However, you can turn off these warnings by passing `false` to the constructor. This is useful if you need `.toc()` calls in code blocks that may not get executed, e.g. in conditional statements. The example below will not produce any warnings:

```{r, eval = TRUE}
Rcpp::cppFunction('
double add(double &x, double &y)
{
 Rcpp::Timer timer(false);
 Rcpp::Timer::ScopedTimer scoped_timer(timer, "add");
 timer.tic("add");
 double z = x + y;
 timer.toc("ad");
 return(z);
}',
  depends = "rcpptimer"
)

add(rnorm(1), runif(1))

print(times)
```