[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