[Dune] Sequential Streams for Console Output of Parallell Programs
Martin Rückl
mrueckl at physik.hu-berlin.de
Mon Apr 15 11:54:12 CEST 2013
Hi Jayesh,
I don't know if this is what you want, but I wrote some small
streambuffer redirecting tool which is capable of piping all std::cout
output of ranks other than master to /dev/null or somewhere else.
HtH, Martin
#include <dune/common/mpihelper.hh>
#include <ostream>
/*
* helper class for easy logging to std::cout in parallel applications
*/
class CoutReplacement
{
public:
static const CoutReplacement & initialize(std::string path)
{
static CoutReplacement instance(path);
return instance;
}
private:
/*
* All credits for this subclass go to Thomas (??)
* from http://wordaligned.org/articles/cpp-streambufs
*/
class teebuf: public std::streambuf
{
public:
// Construct a streambuf which tees output to both input
// streambufs.
teebuf(std::streambuf * sb1, std::streambuf * sb2)
: sb1(sb1)
, sb2(sb2)
{
}
private:
// This tee buffer has no buffer. So every character "overflows"
// and can be put directly into the teed buffers.
virtual int overflow(int c)
{
if (c == EOF)
{
return !EOF;
}
else
{
int const r1 = sb1->sputc(c);
int const r2 = sb2->sputc(c);
return r1 == EOF || r2 == EOF ? EOF : c;
}
}
// Sync both teed buffers.
virtual int sync()
{
int const r1 = sb1->pubsync();
int const r2 = sb2->pubsync();
return r1 == 0 && r2 == 0 ? 0 : -1;
}
private:
std::streambuf * sb1;
std::streambuf * sb2;
};
CoutReplacement(std::string path) :
tee(NULL),
cout_strbuf(std::cout.rdbuf()), // remember cout's old stream buffer
cerr_strbuf(std::cerr.rdbuf()), // remember cout's old stream buffer
output_file(NULL)
{
bool flg_pipe_slave_to_dev_null = true;
if(Dune::MPIHelper::getCollectiveCommunication().rank()==0)
{
// create the new stream to "redirect" cout's output to
output_file = new std::ofstream(path + "/cout_rank_0.txt",
std::ios::out);
// create tee buffer which duplicates to console and to output
file
tee = new teebuf(cout_strbuf, output_file->rdbuf());
// set the std::cout buffer to the tee buffer
std::cout.rdbuf(tee);
}
else
{
// determine if we want logfile or not
std::stringstream ss;
ss << path << "/cout_rank_" <<
Dune::MPIHelper::getCollectiveCommunication().rank() << ".txt";
std::string filename = (flg_pipe_slave_to_dev_null ?
"/dev/null" : ss.str());
// open stream
output_file = new std::ofstream(filename, std::ios::out);
std::cout << "Rank #" <<
Dune::MPIHelper::getCollectiveCommunication().rank() << ": std::cout
will now be piped to: " << path << std::endl;
// redirect out buffer
std::cout.rdbuf(output_file->rdbuf());
}
if(!output_file->is_open()) throw CalciumException("Failed to
open file for std::cout redirection!");
}
virtual ~CoutReplacement()
{
// replace cout's original streambuf when we're done. It will
// crash otherwise, since cout and stringstream will both
// destroy the same streambuf.
output_file->close();
delete output_file;
// we can delete this since its destructor does nothing
delete tee;
std::cout.rdbuf(cout_strbuf);
std::cerr.rdbuf(cerr_strbuf);
}
teebuf* tee;
std::streambuf* cout_strbuf;
std::streambuf* cerr_strbuf;
std::ofstream *output_file;
};
int main(int argc, char** argv)
{
try{
// initialize MPIHelper
Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv);
} catch(...){}
// set up cout redirecting for parallel runs
CoutReplacement::initialize(opath);
// if(Dune::MPIHelper::getCollectiveCommunication().rank()==0)//
we dont need this anymore
std::cout <<"std::cout will now go to console and to logfile for
rank #0, all other ranks output will be supressed and
discarded."<<std::endl;
}
More information about the Dune
mailing list