UseCaseEnvironment.cpp

00001 /*------------------------------------------------------------------------*/
00002 /*                 Copyright 2010 Sandia Corporation.                     */
00003 /*  Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive   */
00004 /*  license for use of this work by or on behalf of the U.S. Government.  */
00005 /*  Export of this program may require a license from the                 */
00006 /*  United States Government.                                             */
00007 /*------------------------------------------------------------------------*/
00008 
00009 #include <iostream>
00010 #include <iomanip>
00011 
00012 #include <stk_util/diag/Writer.hpp>
00013 #include <stk_util/diag/PrintTimer.hpp>
00014 #include <stk_util/util/Bootstrap.hpp>
00015 #include <stk_util/util/IndentStreambuf.hpp>
00016 
00017 #include <stk_util/use_cases/UseCaseEnvironment.hpp>
00018 
00019 namespace {
00020 
00021 namespace bopt = boost::program_options;
00022 
00023 // Parse command line bit masks and produce -h documentation. (Probably moved to Util at some point)
00024 typedef unsigned long OptionMask;
00025 
00026 struct OptionMaskName
00027 {
00028   OptionMaskName()
00029     : m_name(""),
00030       m_mask(0),
00031       m_description("")
00032   {}
00033 
00034   OptionMaskName(const std::string &name, const OptionMask &mask, const std::string &description = "No description available")
00035     : m_name(name),
00036       m_mask(mask),
00037       m_description(description)
00038   {}
00039 
00040   virtual ~OptionMaskName()
00041   {}
00042 
00043   std::string   m_name;
00044   OptionMask    m_mask;
00045   std::string   m_description;
00046 };
00047 
00048 
00049 class OptionMaskNameMap: public std::map<std::string, OptionMaskName>
00050 {
00051 public:
00052   void mask(const std::string &name, const OptionMask mask, const std::string &description) {
00053     iterator it = find(name);
00054     if (it == end())
00055       insert(std::make_pair(name, OptionMaskName(name, mask, description)));
00056     else {
00057       (*it).second.m_mask = mask;
00058       (*it).second.m_description = description;
00059     }
00060   }
00061 };
00062 
00063 class OptionMaskParser
00064 {
00065 public:
00066   typedef OptionMask Mask;    
00067 
00068 public:
00073   OptionMaskParser(const std::string &description)
00074     : m_optionMaskNameMap(),
00075       m_description(description),
00076       m_optionMask(0),
00077       m_status(true)
00078   {}
00079 
00080   virtual ~OptionMaskParser()
00081   {}
00082 
00083   Mask parse(const char *mask) const;
00084 
00085   virtual void parseArg(const std::string &name) const;
00086 
00087   std::string describe() const {
00088     std::ostringstream strout;
00089     strout << m_description << std::endl;
00090     for (OptionMaskNameMap::const_iterator it = m_optionMaskNameMap.begin(); it != m_optionMaskNameMap.end(); ++it)
00091       strout << "  " << (*it).first << std::setw(14 - (*it).first.size()) << " " << (*it).second.m_description << std::endl;
00092     return strout.str();
00093   }
00094   
00095   void mask(const std::string &name, const Mask mask, const std::string &description) {
00096     m_optionMaskNameMap.mask(name, mask, description);
00097   }
00098 
00099 protected:
00100   OptionMaskNameMap   m_optionMaskNameMap;  
00101   std::string                   m_description;          
00102   mutable OptionMask    m_optionMask;   
00103   mutable bool      m_status;   
00104 };
00105 
00106 
00107 OptionMaskParser::Mask
00108 OptionMaskParser::parse(
00109   const char *          mask) const
00110 {
00111   if (mask) {
00112     const std::string mask_string(mask);
00113     
00114     m_status = true;
00115 
00116     std::string::const_iterator it0 = mask_string.begin();
00117     std::string::const_iterator it1;
00118     std::string::const_iterator it2;
00119     std::string::const_iterator it3;
00120     do {
00121       // Trim preceeding spaces
00122       while (it0 != mask_string.end() && *it0 == ' ')
00123         it0++;
00124 
00125       if (it0 == mask_string.end())
00126         break;
00127 
00128       for (it1 = it0; it1 != mask_string.end(); ++it1) {
00129         if (*it1 == '(' || *it1 == ':' || *it1 == ',')
00130           break;
00131       }
00132 
00133       // Trim trailing spaces
00134       it2 = it1;
00135       while (it2 != it0 && *(it2 - 1) == ' ')
00136         --it2;
00137 
00138       std::string name(it0, it2);
00139 
00140       // Get argument list
00141       if (*it1 == '(') {
00142         it2 = it1 + 1;
00143 
00144         // Trim preceeding spaces
00145         while (it2 != mask_string.end() && *it2 == ' ')
00146           ++it2;
00147 
00148         int paren_count = 0;
00149 
00150         for (; it1 != mask_string.end(); ++it1) {
00151           if (*it1 == '(')
00152             ++paren_count;
00153           else if (*it1 == ')') {
00154             --paren_count;
00155             if (paren_count == 0)
00156               break;
00157           }
00158         }
00159         it3 = it1;
00160 
00161         // Trim trailing spaces
00162         while (it3 != it2 && *(it3 - 1) == ' ')
00163           --it3;
00164 
00165         // Find next argument start
00166         for (; it1 != mask_string.end(); ++it1)
00167           if (*it1 == ':' || *it1 == ',')
00168             break;
00169       }
00170       else
00171         it2 = it3 = it1;
00172 
00173       const std::string arg(it2, it3);
00174 
00175       parseArg(name);
00176 
00177       it0 = it1 + 1;
00178     } while (it1 != mask_string.end());
00179   }
00180 
00181   return m_optionMask;
00182 }
00183 
00184 
00185 void
00186 OptionMaskParser::parseArg(
00187   const std::string & name) const
00188 {
00189   OptionMaskNameMap::const_iterator mask_entry = m_optionMaskNameMap.find(name);
00190 
00191   if (mask_entry != m_optionMaskNameMap.end()) m_optionMask |= (*mask_entry).second.m_mask;
00192   else {
00193     Mask  mask_hex = 0;
00194     std::istringstream mask_hex_stream(name.c_str());
00195     if (mask_hex_stream >> std::resetiosflags(std::ios::basefield) >> mask_hex)
00196       m_optionMask |= mask_hex;
00197     else
00198       m_status = false;
00199   }
00200 }
00201 
00202 // Build output logging description for binding output streams
00203 std::string
00204 build_log_description(
00205   const bopt::variables_map &   vm,
00206   const std::string &           working_directory,
00207   int                           parallel_rank,
00208   int                           parallel_size)
00209 {
00210   std::ostringstream output_description;
00211 
00212   // On processor 0:
00213   //   [outfile=path] [poutfile=path.n.r] [doutfile=path.n.r] out>{-|cout|cerr|outfile}+pout pout>{null|poutfile} dout>{out|doutfile}
00214 
00215   // On processor 1..n:
00216   //   [poutfile=path.n.r] [doutfile=path.n.r] out>pout pout>{null|poutfile} dout>{out|doutfile}
00217     
00218   std::string out_path = "-";
00219   if (vm.count("output-log"))
00220     out_path = vm["output-log"].as<std::string>();
00221   if (out_path == "-")
00222     out_path = "cout";
00223     
00224   std::string out_ostream;
00225 
00226   if (!stk::get_log_ostream(out_path))
00227     if (out_path.size() && out_path[0] != '/')
00228       out_path = working_directory + out_path;
00229 
00230   if (parallel_rank == 0) {
00231     if (!stk::get_log_ostream(out_path)) {
00232       output_description << "outfile=\"" << out_path << "\"";
00233       out_ostream = "outfile";
00234     }
00235     else
00236       out_ostream = out_path;
00237   }
00238   else
00239     out_ostream = "null";
00240 
00241   std::string pout_ostream = "null";
00242   if (vm.count("pout")) {
00243     std::string pout_path = vm["pout"].as<std::string>();
00244     if (pout_path == "-") {
00245       std::ostringstream s;
00246 
00247       if (stk::get_log_ostream(out_path))
00248         s << working_directory << "sierra.log." << parallel_size << "." << parallel_rank;
00249       else
00250         s << out_path << "." << parallel_size << "." << parallel_rank;
00251       pout_path = s.str();
00252     }
00253     else if (pout_path.find("/") == std::string::npos && !stk::get_log_ostream(pout_path)) {
00254       std::ostringstream s;
00255 
00256       s << working_directory << pout_path << "." << parallel_size << "." << parallel_rank;
00257       pout_path = s.str();
00258     }
00259       
00260     if (!stk::get_log_ostream(pout_path)) {
00261       output_description << " poutfile=\"" << pout_path << "\"";
00262       pout_ostream = "poutfile";
00263     }
00264     else
00265       pout_ostream = pout_path;
00266   }
00267 
00268   std::string dout_ostream;    
00269   if (vm.count("dout")) {
00270     std::string dout_path = vm["dout"].as<std::string>();
00271     if (!dout_path.empty() && stk::is_registered_ostream(dout_path))
00272       dout_ostream = dout_path;
00273     else {
00274       std::ostringstream s;
00275       if (dout_path.size() && dout_path[0] != '/')
00276         s << working_directory << dout_path << "." << parallel_size << "." << parallel_rank;
00277       else
00278         s << dout_path << parallel_size << "." << parallel_rank;
00279       dout_path = s.str();
00280       output_description << " doutfile=\"" << dout_path << "\"";
00281       dout_ostream = "doutfile";
00282     }
00283   }
00284   else
00285     dout_ostream = "out";
00286 
00287   if (parallel_rank == 0)
00288     output_description << " out>" << out_ostream << "+pout";
00289   else
00290     output_description << " out>pout";
00291 
00292   output_description << " pout>" << pout_ostream << " dout>" << dout_ostream;
00293 
00294   return output_description.str();
00295 }
00296 
00297 OptionMaskParser dw_option_mask("use case diagnostic writer");
00298 OptionMaskParser timer_option_mask("use case timers");
00299 
00300 void
00301 bootstrap()
00302 {
00305   dw_option_mask.mask("search", use_case::LOG_SEARCH, "log search diagnostics");
00306   dw_option_mask.mask("transfer", use_case::LOG_TRANSFER, "log transfer diagnostics");
00307   dw_option_mask.mask("timer", use_case::LOG_TIMER, "log timer diagnostics");
00308   
00309   timer_option_mask.mask("mesh", use_case::TIMER_MESH, "mesh operations timers");
00310   timer_option_mask.mask("meshio", use_case::TIMER_MESH_IO, "mesh I/O timers");
00311   timer_option_mask.mask("transfer", use_case::TIMER_TRANSFER, "transfer timers");
00312   timer_option_mask.mask("search", use_case::TIMER_SEARCH, "search timers");
00313   
00314   boost::program_options::options_description desc("Use case environment options");
00315   desc.add_options()
00316     ("help,h", "produce help message")
00317     ("directory,d", boost::program_options::value<std::string>(), "working directory")
00318     ("output-log,o", boost::program_options::value<std::string>(), "output log path")
00319     ("pout", boost::program_options::value<std::string>()->implicit_value("-"), "per-processor log file path")
00320     ("dout", boost::program_options::value<std::string>()->implicit_value("out"), "diagnostic output stream one of: 'cout', 'cerr', 'out' or a file path")
00321     ("dw", boost::program_options::value<std::string>(), dw_option_mask.describe().c_str())
00322     ("timer", boost::program_options::value<std::string>(), timer_option_mask.describe().c_str())
00323     ("runtest,r", boost::program_options::value<std::string>(), "runtest pid file");
00324   
00325   stk::get_options_description().add(desc);
00326 }
00327 
00328 stk::Bootstrap x(bootstrap);
00329 
00330 } // namespace <empty>
00331 
00332 namespace use_case {
00333 
00334 // Output streams
00335 std::ostream &
00336 out() {
00337   static std::ostream s_out(std::cout.rdbuf());
00338 
00339   return s_out;
00340 }
00341 
00342 
00343 std::ostream &
00344 pout() {
00345   static std::ostream s_pout(std::cout.rdbuf());
00346 
00347   return s_pout;
00348 }
00349 
00350 
00351 std::ostream &
00352 dout() {
00353   static std::ostream s_dout(std::cout.rdbuf());
00354 
00355   return s_dout;
00356 }
00357 
00358 
00359 std::ostream &
00360 tout() {
00361   static std::ostream s_tout(std::cout.rdbuf());
00362 
00363   return s_tout;
00364 }
00365 
00366 
00367 std::ostream &
00368 dwout() {
00369   static stk::indent_streambuf s_dwoutStreambuf(std::cout.rdbuf());
00370   static std::ostream s_dwout(&s_dwoutStreambuf);
00371   
00372   return s_dwout;
00373 }
00374 
00375 
00376 // Diagnostic writer
00377 stk::diag::Writer &
00378 dw()
00379 {
00380   static stk::diag::Writer s_diagWriter(dwout().rdbuf(), 0);
00381 
00382   return s_diagWriter;
00383 }
00384 
00385 
00386 // Message reporting
00387 std::ostream &
00388 operator<<(
00389   std::ostream &  os,
00390   message_type           type)
00391 {
00392   switch (type & stk::MSG_TYPE_MASK) {
00393   case MSG_WARNING:
00394     os << "Warning";
00395     break;
00396   case MSG_FATAL:
00397     os << "Fatal error";
00398     break;
00399   case MSG_INFORMATION:
00400     os << "Information";
00401     break;
00402   case MSG_EXCEPTION:
00403     os << "Exception";
00404     break;
00405   case MSG_PARALLEL_EXCEPTION:
00406     os << "Parallel exception";
00407     break;
00408   }
00409   return os;
00410 }
00411 
00412 
00413 void
00414 report_handler(
00415   const char *    message,
00416   int                   type)
00417 {
00418   if (type & stk::MSG_DEFERRED)
00419     pout() << "Deferred " << (message_type) type << ": " << message << std::endl;
00420   
00421   else
00422     out() << (message_type) type << ": " << message << std::endl;
00423 }
00424 
00425 
00426 // Timers
00427 stk::diag::TimerSet &
00428 timerSet()
00429 {
00430   static stk::diag::TimerSet s_timerSet(TIMER_ALL);
00431 
00432   return s_timerSet;
00433 }
00434 
00435 
00436 stk::diag::Timer &timer() {
00437   static stk::diag::Timer s_timer = stk::diag::createRootTimer("Use Cases", timerSet());
00438 
00439   return s_timer;
00440 }
00441 
00442 
00443 UseCaseEnvironment::UseCaseEnvironment(
00444   int *         argc,
00445   char ***      argv)
00446   : m_comm(stk::parallel_machine_init(argc, argv))
00447 {
00448   stk::register_log_ostream(std::cout, "cout");
00449   stk::register_log_ostream(std::cerr, "cerr");
00450 
00451   stk::register_ostream(out(), "out");
00452   stk::register_ostream(pout(), "pout");
00453   stk::register_ostream(dout(), "dout");
00454   stk::register_ostream(tout(), "tout");
00455 
00456   static_cast<stk::indent_streambuf *>(dwout().rdbuf())->redirect(dout().rdbuf());
00457 
00458   stk::set_report_handler(report_handler);
00459 
00460   stk::Bootstrap::bootstrap();
00461   
00462   for (int i = 0; i < *argc; ++i) {
00463     const std::string s((*argv)[i]);
00464     if (s == "-h" || s == "-help" || s == "--help") {
00465       std::cout << "Usage: " << (*argv)[0] << " [options...]" << std::endl;
00466       std::cout << stk::get_options_description() << std::endl;
00467       std::exit(0);
00468       return; // So application can handle app-specific options.
00469     }
00470   }
00471 
00472 // Broadcast argc and argv to all processors.
00473   int parallel_rank = stk::parallel_machine_rank(m_comm);
00474   int parallel_size = stk::parallel_machine_size(m_comm);
00475     
00476   stk::BroadcastArg b_arg(m_comm, *argc, *argv);
00477 
00478 // Parse broadcast arguments
00479   bopt::variables_map &vm = stk::get_variables_map();  
00480   try {
00481     bopt::store(bopt::parse_command_line(b_arg.m_argc, b_arg.m_argv, stk::get_options_description()), vm);
00482     bopt::notify(vm);
00483   }
00484   catch (std::exception &x) {
00485     stk::RuntimeDoomedSymmetric() << x.what();
00486   }
00487 
00488 // Parse diagnostic messages to display  
00489   if (vm.count("dw"))
00490     dw().setPrintMask(dw_option_mask.parse(vm["dw"].as<std::string>().c_str()));
00491 
00492 // Parse timer metrics and classes to display  
00493   stk::diag::setEnabledTimerMetricsMask(stk::diag::METRICS_CPU_TIME | stk::diag::METRICS_WALL_TIME);
00494   if (vm.count("timer"))
00495     timerSet().setEnabledTimerMask(timer_option_mask.parse(vm["timer"].as<std::string>().c_str()));
00496   
00497 // Set working directory  
00498   m_workingDirectory = "./";
00499   if (vm.count("directory"))
00500     m_workingDirectory = vm["directory"].as<std::string>();
00501   if (m_workingDirectory.length() && m_workingDirectory[m_workingDirectory.length() - 1] != '/')
00502     m_workingDirectory += "/";
00503     
00504   std::string output_description = build_log_description(vm, m_workingDirectory, parallel_rank, parallel_size);
00505   
00506   stk::bind_output_streams(output_description);
00507 
00508   dout() << "Output log binding: " << output_description << std::endl;
00509 
00510 // Start use case root timer  
00511   timer().start();
00512 }
00513 
00514 
00515 UseCaseEnvironment::~UseCaseEnvironment()
00516 {
00517   stk::report_deferred_messages(m_comm);
00518   
00519 // Stop use case root timer  
00520   timer().stop();
00521 
00522   stk::diag::printTimersTable(out(), timer(), stk::diag::METRICS_CPU_TIME | stk::diag::METRICS_WALL_TIME, false, m_comm);
00523 
00524   stk::diag::deleteRootTimer(timer());
00525   
00526   static_cast<stk::indent_streambuf *>(dwout().rdbuf())->redirect(std::cout.rdbuf());
00527   
00528   stk::unregister_ostream(tout());
00529   stk::unregister_ostream(dout());
00530   stk::unregister_ostream(pout());
00531   stk::unregister_ostream(out());
00532 
00533   stk::unregister_log_ostream(std::cerr);
00534   stk::unregister_log_ostream(std::cout);  
00535 
00536   stk::parallel_machine_finalize();
00537 }
00538 
00539 } // namespace use_case
Generated on Wed Apr 13 10:05:49 2011 for Sierra Toolkit by  doxygen 1.6.3