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