Skip to content

Commit

Permalink
Merge pull request #3 from BerriJ/dev
Browse files Browse the repository at this point in the history
Release 1.1.0
  • Loading branch information
BerriJ committed Mar 20, 2024
2 parents 323ec74 + 40c253d commit 9eb3bd7
Show file tree
Hide file tree
Showing 13 changed files with 253 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/R-CMD-check-Dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: 'true'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: 'true'

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: 'true'

Expand Down
6 changes: 3 additions & 3 deletions CRAN-SUBMISSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Version: 1.0.0
Date: 2024-03-01 20:00:09 UTC
SHA: 661f935d8c63eb220f5880575af1515b3cc6ae43
Version: 1.1.0
Date: 2024-03-20 09:00:27 UTC
SHA: 3f33f5f732711d5bed614a3b14432aac5f102cbb
9 changes: 6 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Package: rcpptimer
Type: Package
Title: 'Rcpp' Tic-Toc Timer with 'OpenMP' Support
Version: 1.0.0
Date: 2024-02-29
Version: 1.1.0
Date: 2024-03-20
Authors@R: c(
person(given = "Jonathan",
family = "Berrisch",
Expand All @@ -17,7 +17,10 @@ Imports: Rcpp
LinkingTo: Rcpp
RoxygenNote: 7.3.1
Suggests:
testthat (>= 3.0.0)
testthat (>= 3.0.0),
knitr,
rmarkdown
Config/testthat/edition: 3
Roxygen: list(markdown = TRUE)
VignetteBuilder: knitr
Language: en-US
31 changes: 25 additions & 6 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
rcpptimer 1.1.0
==============

## Improvements

* Add new `Rcpp::CppTimer::ScopedTimer` class. This can be used to time the lifespan of an object until it goes out of scope. This is useful for timing the duration of a function or a loop. The `fibonacci` example was updated to use this new class.
* Warn about timers that are not stopped when aggregate is called (no matching `toc()` statement).
* Warn about timers for which no matching `tic()` statement was found.
* Add `verbose` parameter to the `Timer` class to control whether above warnings should be printed or not (defaults to `true`).
* Add introductory vignette to the package.

## Fixes

* Fixed cases where only `toc()` was called without matching `tic()`.
* This led to a segfault in the previous version.
* Fix `reset()` method which was not working properly in some cases where timers spread out over multiple methods.
* Fix non-default constructors of the `Timer` class. They were not working properly in the previous version.

rcpptimer 1.0.0
==============

This is the initial release of `rcpptimer`. It is based on `RcppClock` but contains a number of improvements:
- OpenMP support
- Auomatically returns results to R as soon as the C++ Object goes out of scope
- Fast computation of Mean and Standard Deviation of the results in C++
- Uses `tic` and `toc` instead of `tick` and `tock` to be consistent with R's `tictoc` package
- Allways reports microseconds resolution
- Many more performance improvements

* OpenMP support
* Auomatically returns results to R as soon as the C++ Object goes out of scope
* Fast computation of Mean and Standard Deviation of the results in C++
* Uses `tic` and `toc` instead of `tick` and `tock` to be consistent with R's `tictoc` package
* Allways reports microseconds resolution
* Many more performance improvements
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,34 @@ Nothing has to be changed with respect to your `timer` instance. The timings sho
5 fib_body 908.919 0.000 1
```

## Scoped Timer

We also added a new `Rcpp::CppTimer::ScopedTimer`. This can be used to time the lifespan of an object until it goes out of scope. This is useful for timing the duration of a function or a loop. Below is the `fibonacci` example from above. However, we replace the "fib_body" tic-toc timer with the scoped version.

```c++
std::vector<int> fibonacci(std::vector<int> n)
{
Rcpp::Timer timer;

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

std::vector<int> results = n;

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);
}
```
Note that you can name your object (in this example `scpdtmr`) however you like. `Rcpp::CppTimer::ScopedTimer` acts as a wrapper, so it will call `.tic` upon construction and `.toc` will be called automatically upon destruction.
`Rcpp::CppTimer::ScopedTimer` is useful to time the duration of a function or a loop.
## Limitations
Processes taking less than a microsecond cannot be timed.
Expand Down
5 changes: 3 additions & 2 deletions cran-comments.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## R CMD check results

0 errors | 0 warnings | 1 note
── R CMD check results ──────────────────────────────────── rcpptimer 1.1.0 ────
Duration: 23.1s

* This is a new release.
0 errors ✔ | 0 warnings ✔ | 0 notes ✔
14 changes: 14 additions & 0 deletions inst/include/chameleon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef CHAMELEON
#define CHAMELEON

#include <Rcpp.h>

namespace chameleon
{
inline void warn(std::string msg)
{
Rcpp::warning(msg.c_str());
}
};

#endif
2 changes: 1 addition & 1 deletion inst/include/cpptimer
Submodule cpptimer updated 1 files
+83 −11 cpptimer.h
10 changes: 10 additions & 0 deletions inst/include/rcpptimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ namespace Rcpp
public:
bool autoreturn = true;

// This ensures that there are no implicit conversions in the constructors
// That means, the types must exactly match the constructor signature
// template <typename T>
// Timer(T &&) = delete;

Timer() : CppTimer() {} // Will use "times", true
Timer(const char *name) : CppTimer(name) {}
Timer(bool verbose) : CppTimer(verbose) {}
Timer(std::string name, bool verbose) : CppTimer(name, verbose) {}

// Pass data to R / Python
void stop()
{
Expand Down
19 changes: 12 additions & 7 deletions src/fibonacci.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,20 @@ int fib(int n)
//[[Rcpp::export]]
std::vector<int> fibonacci(std::vector<int> n)
{

Rcpp::Timer timer;
timer.tic("fib_body");

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

std::vector<int> results = n;

for (int i = 0; i < n.size(); ++i)
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]));
}
timer.toc("fib_body");

return (results);
}

Expand Down Expand Up @@ -71,16 +73,19 @@ std::vector<int> fibonacci_omp(std::vector<int> n)
{

Rcpp::Timer timer;
timer.tic("fib_body");

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

std::vector<int> results = n;

#pragma omp parallel for
for (int i = 0; i < n.size(); ++i)
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]));
}
timer.toc("fib_body");

return (results);
}
148 changes: 148 additions & 0 deletions vignettes/rcpptimer.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
---
title: "Introduction"
author: Jonathan Berrisch
date: "`r Sys.Date()`"
output:
rmarkdown::html_vignette:
number_sections: no
toc: no
vignette: >
%\VignetteIndexEntry{Introduction}
%\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)
```

# A Short Introduction to rcpptimer

This package provides a simple timer for Rcpp code. It is similar to the [tictoc](https://CRAN.R-project.org/package=tictoc) R package.

The Package wraps [cpptimer](https://github.com/BerriJ/cpptimer) which is a header only library that contains a class called `CppTimer`. 'rcpptimer' adds this class as `Timer` to the `Rcpp` namespace.

## Basic usage of the Timer with Rcpp::cppFunction

With `Rcpp::cppFunction` we have to add the `depends` argument to the function. To tell the compiler that we want to link the 'rcpptimer' library to the 'Rcpp' code. That is, we can construct an instance if the `Timer` class and use the `tic` and `toc` methods to measure the time it takes to execute a function. Here, we just allocate some memory to have something to measure:

```{r, eval = TRUE}
Rcpp::cppFunction('
int mem()
{
Rcpp::Timer timer;
timer.tic("mem");
std::string s;
s.reserve(1048576);
timer.toc("mem");
return(0);
}',
depends = "rcpptimer"
)
mem()
print(times)
```

The results will be passed to the R environment as a dataframe named `times`. If you want to give the dataframe a different name you can pass that name to the constructor:

```{r, eval = TRUE}
Rcpp::cppFunction('
int mem()
{
Rcpp::Timer timer("mytimes");
timer.tic("mem");
std::string s;
s.reserve(1048576);
timer.toc("mem");
return(0);
}',
depends = "rcpptimer"
)
mem()
print(mytimes)
```

## Warnings and how to disable them

The default setting will warn about timers that have not been stopped and `toc` calls for timers that have not yet been started using a matching call to `tic`:

```{r, eval = TRUE}
Rcpp::cppFunction('
int mem()
{
Rcpp::Timer timer;
timer.tic("start");
std::string s;
timer.tic("reserve");
s.reserve(1048576);
timer.toc("reserve");
timer.toc("finish");
return(0);
}',
depends = "rcpptimer"
)
mem()
print(times)
```

Note that this does not affect correctly terminated timers such as `reserve`. These warnings occur at runtime. Unfortunately, we can't check for this at compile time since the `tic` and `toc` calls might spread over various functions so that (in some cases) we do not know the execution flow upfront.

However, if you are sure that you are using the timer correctly you can disable these warnings by passing `false` to the constructor:

```{r, eval = TRUE}
Rcpp::cppFunction('
int mem()
{
Rcpp::Timer timer(false); // Disable warnings
timer.tic("start");
std::string s;
timer.tic("reserve");
s.reserve(1048576);
timer.toc("reserve");
timer.toc("finish");
return(0);
}',
depends = "rcpptimer"
)
mem()
```

## Rcpp::Timer::ScopedTimer

We offer an alternative to the tic-toc interface. The `ScopedTimer` lets you measure the time it takes for the object to go out of scope. We can adjust the above example to use the `ScopedTimer` instead:

```{r, eval = TRUE}
Rcpp::cppFunction('
int mem()
{
Rcpp::Timer timer;
Rcpp::Timer::ScopedTimer scoped_timer(timer, "mem");
std::string s;
s.reserve(1048576);
return(0);
}',
depends = "rcpptimer"
)
mem()
print(times)
```

Note that you only need to initialize the ScopedTimer. Once it goes out of scope it will call `timer.toc("mem")` automatically.

We will add vignettes on how to use the package with Rcpp::sourceCpp and how to add it to your package soon.

0 comments on commit 9eb3bd7

Please sign in to comment.