1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
\name{RcppProgress-package}
\alias{RcppProgress-package}
\alias{RcppProgress}
\docType{package}
\title{
An interruptible progress bar with OpenMP support for c++ in R packages
}
\description{
This package allows to display a progress bar in the R
console for long running computations taking place in c++ code,
and provides support for interrupting those computations even in a multithreaded code.
}
\details{
When implementing CPU intensive computations in C++ in R packages, it is natural to want to monitor
the progress of those computations, and to be able to interrupt them, even when using
multithreading for example with OpenMP.
Another feature is that it can be done so that the code will still work even without OpenMP support.
This package offers some facilities to help implementing those features.
It it biased towards the use of OpenMP, but it should be compatible when using
multithreading in other ways.
\subsection{quick try}{
There are two tests functions provided by the package to get a quick overview
of what can be done.
These tests are:
\describe{
\item{ RcppProgress:::test_sequential(max, nb, display_progress) }{ - a sequential code, i.e. single threaded }
\item{ RcppProgress:::test_multithreaded(max, nb, threads, display_progress) }{ - a multithreaded code using OpenMP}
}
They both are wrappers for examples implemented in the RcppProgressExample package
located in the \code{examples} directory of the RcppProgress installed package.
Both tests call the very same function that implements a long computation.
The \bold{max} parameter controls the number of computations, and \bold{nb} controls the duration of a single computation,
that is quadratic in \bold{nb}.
The \bold{threads} is as expected the number of threads to use for the computation.
The \bold{progress} parameter toggles the display of the progress bar.
On my platform,
\preformatted{
system.time( RcppProgress:::test_multithreaded(100, 3000, 4) )
}
is a good start.
}
\subsection{c++ usage}{
There are usually two locations in the c++ code that needs to be modified.
The first one is the main loop, typically on the number of jobs or tasks. This loop is a good candidate to
be parallelized using OpenMP.
I will comment the code corresponding to the tests included with the package.
\preformatted{
void test_multithreaded_omp(int max, int nb, int threads
, bool display\_progress) \{
\#ifdef _OPENMP
if ( threads > 0 )
omp_set_num_threads( threads );
REprintf(\"Number of threads=\%i\n\", omp_get_max_threads());
\#endif
Progress p(max, display_progress); // create the progress monitor
#pragma omp parallel for schedule(dynamic)
for (int i = 0; i < max; ++i) \{
if ( ! p.is_aborted() ) \{ // the only way to exit an OpenMP loop
long_computation(nb);
p.increment(); // update the progress
\}
\}
\}
}
Here we create a Progress object with the number of tasks to perform, then
before performing a task we test for abortion (\code{p.is_aborted()}), because we can not exit an
OpenMP loop the usual way, suing a break for example, then
when after the computation, we increment the progress monitor.
Then let us look at the computation function (that is completely useless) :
\preformatted{
double long_computation(int nb) \{
double sum = 0;
for (int i = 0; i < nb; ++i) \{
if ( Progress::check_abort() ) // check for user abort
return -1;
for (int j = 0; j < nb; ++j) \{
sum += Rf_dlnorm(i+j, 0.0, 1.0, 0);
\}
\}
\}
return sum;
\}
}
Here the only interesting line is the \code{Progress::check_abort()} call.
If called from the master thread, it will check for user interruption, and if needed
set the abort status code.
When called from another thread it will just check the status.
So all the art is to decide where to put his call: it should not be called not too often
or not frequently enough.
As a rule of thumb it should be called roughly evevry second.
}
\subsection{Using RcppProgress in your package}{
Please note that we provide the \bold{RcppProgressExample} example package along with this package,
located in the \code{examples} directory of the installed package.
Here are the steps to use RcppProgress in a new package:
\describe{
\item{ skeleton }{
create a package skeleton using Rcpp
\preformatted{
library(Rcpp)
Rcpp.package.skeleton("RcppProgressExample")}
}
\item{ DESCRIPTION }{ edit the \bold{DESCRIPTION} file and add RcppProgress to
the \strong{Depends:} and \strong{LinkingTo:} lines. e.g.
\preformatted{
Depends: Rcpp (>= 0.9.4), RcppProgress (>= 0.1)
LinkingTo: Rcpp, RcppProgress
}
}
\item{ MakeVars }{ edit \bold{src/MakeVars} and replace its content by
PKG_LIBS = `$(R_HOME)/bin/Rscript -e "Rcpp:::LdFlags()"` $(SHLIB_OPENMP_CXXFLAGS) `$(R_HOME)/bin/Rscript -e "RcppProgress:::CxxFlags()"`
and
PKG_CXXFLAGS +=-Ilibsrc $(SHLIB_OPENMP_CXXFLAGS) `$(R_HOME)/bin/Rscript -e "RcppProgress:::CxxFlags()"`
}
\item{ c++ code }{
Put your code in \bold{src}.
You may for instance copy the RcppProgressExample/src/tests.cpp file in \bold{src}, and RcppProgressExample/R/tests.R in
\bold{R}, and try to
compile the package (\code{R CMD INSTALL -l test .}) and execute the tests:
\preformatted{
%R
>library(RcppProgressExample, lib.loc="test")
>RcppProgressExample::test_multithreaded(100, 600, 4)
}
}
}
} % subsection
\subsection{Using RcppProgress with RcppArmadillo}{
We also provide the \bold{RcppProgressArmadillo} example package along with this package,
located in the \code{examples} directory of the installed package.
The peculiarity is that you have to include the RcppArmadillo.h header before the
progress.hpp RcppProgress header, and add the RcppArmadillo in the LinkingTo:
field of the package DESCRIPTION file.
} % subsection
} % details
\seealso{
\describe{
\item{ OpenMP }{API specification for parallel programming: \url{http://openmp.org} }
\item{ Rcpp }{\url{http://r-forge.r-project.org/projects/rcpp}}
}
}
\author{
Karl Forner
Maintainer: Karl Forner <karl.forner@quartzbio.com>
}
\examples{
# these are implemented as examples inside RcppProgress provided
# example package: examples/RcppProgressExample
# check the source code
# the underlying test_test_multithreaded c++ function is multithreaded
# , has a progress bar and is still interruptible
\dontrun{
RcppProgress:::test_multithreaded(nb = 300, threads = 4, recompile = TRUE)
}
}
\keyword{ package }
|