Author: Jonathan Berrisch
Date: 2024-09-21

# Advanced Usage of rcpptimer

#### Jonathan Berrisch

#### 2024-09-21

## Accessing Unprocessed Data

The `stop()` method returns the aggregated data as a `DataFrame`. However, you can also access the raw data if you need to. The `timer` class stores the timings in two vectors: `durations` and `tags`, both public class members. The snippet below demonstrates how to access them:

    Rcpp::cppFunction('
    DataFrame demo_rnorm()
    {
      Rcpp::Timer timer;
      double x=0;
      for(int i = 0; i < 7; i++)
      {
        timer.tic("rnorm");
        x += rnorm(1, 1)[0];
        timer.toc("rnorm");
      }
      DataFrame times = DataFrame::create(
              Named("Durations") = timer.durations,
              Named("Tags") = timer.tags);
      return(times);
    }',
      depends = "rcpptimer"
    )

    demo_rnorm()

    ##   Durations  Tags
    ## 1      6767 rnorm
    ## 2       205 rnorm
    ## 3        89 rnorm
    ## 4       162 rnorm
    ## 5       149 rnorm
    ## 6        88 rnorm
    ## 7        86 rnorm

You can see that the `tags` vector contains the names of the timings, and the `durations` vector contains the actual timings (in nanoseconds).

## Updating the Results

Sometimes, you may want to access the results of your `Timer` instance before all timers have finished. This is possible. Due to the way the `Timer` class processes the data, it is also very efficient. The `.aggregate()` method (called by `.stop()`) will update the results if new timings have been observed. The snippet below demonstrates this:

    List test_update()
    {
      Rcpp::Timer timer;
      timer.autoreturn = false;
      List L = List::create();
      {
        Rcpp::Timer::ScopedTimer scoped_timer(timer, "t1");
        timer.tic("t2");
        std::this_thread::sleep_for(std::chrono::nanoseconds(5));
        timer.toc("t2");
        DataFrame results1 = timer.stop();
        timer.print_warnings();
        L.push_back(results1);
        timer.tic("t2");
        std::this_thread::sleep_for(std::chrono::nanoseconds(500));
        timer.toc("t2");
        timer.tic("t3");
        std::this_thread::sleep_for(std::chrono::nanoseconds(500));
        timer.toc("t3");
      }
      DataFrame results2 = timer.stop();
      L.push_back(results2);
      return (L);
    }

We use the above function in rcpptimer for testing purposes:

    rcpptimer:::test_update()

    ## Warning in rcpptimer:::test_update(): Timer "t1" not stopped yet.
    ## Use toc("t1") to stop the timer.

    ## [[1]]
    ##    Microseconds SD    Min    Max Count
    ## t2       54.481  0 54.481 54.481     1
    ##
    ## [[2]]
    ##    Microseconds    SD     Min     Max Count
    ## t1      572.870 0.000 572.870 572.870     1
    ## t2       54.233 0.351  53.985  54.481     2
    ## t3       52.186 0.000  52.186  52.186     1

You can see that the timer “t2” has been updated with the new timing. This example also shows that it is unnecessary to stop all timers before calling `.stop()`. In this example, timer “t1” is started before calculating the results for the first time, but it is stopped before calling `.stop()` a second time.

Also, note that we need to manually call `.print_warnings()` if we want to print warnings early. Otherwise, they will only be printed upon destruction of the `Timer` instance (e.g., when your `Timer` object goes out of scope).

## Resetting the Timer

You can reset the timer at any time by calling the `reset()` method. This method will clear your instance of the `Timer` class and reset the internal state. The example below demonstrates how to use it:

    List test_reset()
    {
      Rcpp::Timer timer;
      {
        Rcpp::Timer::ScopedTimer scoped_timer(timer, "t1");
        timer.autoreturn = false;
        timer.tic("t2");
        std::this_thread::sleep_for(std::chrono::nanoseconds(5));
        timer.toc("t2");
      }
      DataFrame results1 = timer.stop();
      timer.reset();
      timer.tic("t3");
      List L = List::create();
      L.push_back(results1);
      timer.toc("t3");
      DataFrame results2 = timer.stop();
      L.push_back(results2);
      return (L);
    }

We use the above function in rcpptimer for testing purposes:

    rcpptimer:::test_reset()

    ## [[1]]
    ##    Microseconds SD    Min    Max Count
    ## t1       58.640  0 58.640 58.640     1
    ## t2       57.427  0 57.427 57.427     1
    ##
    ## [[2]]
    ##    Nanoseconds SD Min Max Count
    ## t3         530  0 530 530     1