[Rcpp-devel] mpi and RInside
Jianping Hua
talich at gmail.com
Tue Feb 9 01:13:28 CET 2010
Hello:
I'm quite new to R and I'd like to run some R program inside my C++
code. So I installed Rcpp and RInside recently. Since many of my work
involves mpi, so I'm wondering if RInside works with mpi. It looks mpi
works, although with some glitch. So I think I might post my
experiences here, for anyone who is interested, and possibly, further
discussions and suggestions.
First, some background. I have a MacbookPro running Leopard. To make
Rcpp and RInside work, I have installed it from source (Thanks Dirk
for tipping me out!!!) The mpic++ is Mac's own g++-4.0.1. Here is an
very simple example code which I modified from the example code 0 of
RInside package:
////////////Start of Example///////////////
// Simple example showing in R console information about current node
#include "mpi.h" // mpi header
#include "RInside.h" // for the embedded R via RInside
#include "Rcpp.h" // for the R / Cpp interface used for transfer
int main(int argc, char *argv[]) {
// mpi related
int myrank, nodesize; // node information
MPI_Init(&argc,&argv); // mpi initialization
MPI_Comm_rank(MPI_COMM_WORLD, &myrank); // obtain current node rank
MPI_Comm_size(MPI_COMM_WORLD, &nodesize); // obtain total nodes running.
RInside R(argc, argv); // create an embedded R instance
std::stringstream txt;
txt << "Hello from node " << myrank // node information
<< " of " << nodesize << " nodes!" << std::endl;
R.assign( txt.str(), "txt"); // assign string var to
R variable 'txt'
std::string evalstr = "cat(txt)"; // show node information
R.parseEvalQ(evalstr); // eval the init string,
ignoring any returns
MPI_Finalize(); // mpi finalization
exit(0);
}
/////////////End of Example///////////////
The tricky part is I found I have to put mpi.h before Rinside.h and
Rcpp.h, otherwise the compiler will report syntax error in mpi.h.
For the makefile, I just changed two lines related to CXX in the
example makefile
CXX := mpic++
CXXFLAGS := $(RCPPFLAGS) $(RCPPINCL) $(RINSIDEINCL) -g -O2
In the first line, I switch compiler from gcc-4.2 to mpic++. In the
second line, I removed mtune=core2 parameter.
I submitted it to 6 slots through mpirun:
mpirun -np 6 rinside_sample0
And the outcome should be something like:
Hello from node 4 of 6 nodes!
Hello from node 3 of 6 nodes!
Hello from node 1 of 6 nodes!
Hello from node 0 of 6 nodes!
Hello from node 2 of 6 nodes!
Hello from node 5 of 6 nodes!
Note that in the above example there is no data passing at all. In the
following example I add data gathering and it also works:
///////Start of example/////////////////
// Simple mpi example: simulate sampling/averaging on multiple nodes
and gathering the results.
#include "mpi.h" // mpi header file
#include "RInside.h" // for the embedded R via RInside
#include "Rcpp.h" // for the R / Cpp interface used for transfer
int main(int argc, char *argv[]) {
// mpi related
int myrank, nodesize; // node information
int sndcnt = 1, rcvcnt = 1; // # of elements in
send/recv buffer
MPI_Init(&argc,&argv); // mpi initialization
MPI_Comm_rank(MPI_COMM_WORLD, &myrank); // obtain current node rank
MPI_Comm_size(MPI_COMM_WORLD, &nodesize); // obtain total nodes running.
double sendValue; // value to be
collected in current node
double *allvalues = new double( nodesize ); // to save all results
//simulation info
// to sample from a uniform distribution
int rangeMin = 0, rangeMax = 10; // range of uniform distribution
int sampleSize = 2; // points in each sample
try
{
RInside R(argc, argv); // create an embedded R instance
SEXP ans; // return value
std::stringstream txt;
txt << "x <- " << rangeMin << std::endl;
R.parseEvalQ( txt.str() ); // assign x with lower range
of uniform distribution
txt << "y <- " << rangeMax << std::endl;
R.parseEvalQ( txt.str() ); // assign y with upper range
of uniform distribution
txt << "n <- " << sampleSize << std::endl;
R.parseEvalQ( txt.str() ); // assign n with the size of sample
std::string evalstr = " mean(runif(n,x,y))"; // sampling,
compute the mean
if ( R.parseEval(evalstr, ans) ) // eval the
evalstr string, return results
throw std::runtime_error( "R cannot evalueate '" + evalstr + "'" );
RcppVector<double> m(ans); // convert SEXP variable to an
RcppVector
sendValue = m( 0 ); // assign the return value to
the variable to be gathered
//gather together values from all processes to allvalues
MPI_Gather(&sendValue,sndcnt,MPI_DOUBLE,&allvalues[0],rcvcnt,MPI_DOUBLE,0,MPI_COMM_WORLD);
// show what inidividual node's contribution
std::cout << "node " << myrank << " has mean " << m(0) << std::endl;
// show gathered results in node 0
if ( myrank == 0 )
{
std::cout << "values of all " << nodesize << " trials: "
<< std::endl;
for ( int i = 0; i < nodesize; i++ )
std::cout << allvalues[ i ] << ", ";
std::cout << std::endl;
}
} catch(std::exception& ex) {
std::cerr << "Exception caught: " << ex.what() << std::endl;
} catch(...) {
std::cerr << "Unknown exception caught" << std::endl;
}
// clean up
delete[] allvalues;
MPI_Finalize(); // mpi finalization
exit(0);
}
//////////End of Example////////////////
The running results, again if running on 6 slots, should be something like this:
node 5 has mean 6.13918
node 2 has mean 5.21227
node 1 has mean 0.563234
node 4 has mean 5.41173
node 3 has mean 2.41499
node 0 has mean 0.515025
values of all 6 trials:
0.515025, 0.563234, 5.21227, 2.41499, 5.41173, 6.13918,
I hope this information is useful.
Best wishes,
Jianping
More information about the Rcpp-devel
mailing list