|
Sierra Toolkit Version of the Day
|
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 m_need_to_finalize(true) 00448 { 00449 initialize(argc, argv); 00450 } 00451 00452 UseCaseEnvironment::UseCaseEnvironment( 00453 int * argc, 00454 char *** argv, 00455 stk::ParallelMachine comm) 00456 : m_comm(comm), 00457 m_need_to_finalize(false) 00458 { 00459 initialize(argc, argv); 00460 } 00461 00462 void UseCaseEnvironment::initialize(int* argc, char*** argv) 00463 { 00464 stk::register_log_ostream(std::cout, "cout"); 00465 stk::register_log_ostream(std::cerr, "cerr"); 00466 00467 stk::register_ostream(out(), "out"); 00468 stk::register_ostream(pout(), "pout"); 00469 stk::register_ostream(dout(), "dout"); 00470 stk::register_ostream(tout(), "tout"); 00471 00472 static_cast<stk::indent_streambuf *>(dwout().rdbuf())->redirect(dout().rdbuf()); 00473 00474 stk::set_report_handler(report_handler); 00475 00476 stk::Bootstrap::bootstrap(); 00477 00478 for (int i = 0; i < *argc; ++i) { 00479 const std::string s((*argv)[i]); 00480 if (s == "-h" || s == "-help" || s == "--help") { 00481 std::cout << "Usage: " << (*argv)[0] << " [options...]" << std::endl; 00482 std::cout << stk::get_options_description() << std::endl; 00483 std::exit(0); 00484 return; // So application can handle app-specific options. 00485 } 00486 } 00487 00488 // Broadcast argc and argv to all processors. 00489 int parallel_rank = stk::parallel_machine_rank(m_comm); 00490 int parallel_size = stk::parallel_machine_size(m_comm); 00491 00492 stk::BroadcastArg b_arg(m_comm, *argc, *argv); 00493 00494 // Parse broadcast arguments 00495 bopt::variables_map &vm = stk::get_variables_map(); 00496 try { 00497 bopt::store(bopt::parse_command_line(b_arg.m_argc, b_arg.m_argv, stk::get_options_description()), vm); 00498 bopt::notify(vm); 00499 } 00500 catch (std::exception &x) { 00501 stk::RuntimeDoomedSymmetric() << x.what(); 00502 } 00503 00504 // Parse diagnostic messages to display 00505 if (vm.count("dw")) 00506 dw().setPrintMask(dw_option_mask.parse(vm["dw"].as<std::string>().c_str())); 00507 00508 // Parse timer metrics and classes to display 00509 stk::diag::setEnabledTimerMetricsMask(stk::diag::METRICS_CPU_TIME | stk::diag::METRICS_WALL_TIME); 00510 if (vm.count("timer")) 00511 timerSet().setEnabledTimerMask(timer_option_mask.parse(vm["timer"].as<std::string>().c_str())); 00512 00513 // Set working directory 00514 m_workingDirectory = "./"; 00515 if (vm.count("directory")) 00516 m_workingDirectory = vm["directory"].as<std::string>(); 00517 if (m_workingDirectory.length() && m_workingDirectory[m_workingDirectory.length() - 1] != '/') 00518 m_workingDirectory += "/"; 00519 00520 std::string output_description = build_log_description(vm, m_workingDirectory, parallel_rank, parallel_size); 00521 00522 stk::bind_output_streams(output_description); 00523 00524 dout() << "Output log binding: " << output_description << std::endl; 00525 00526 // Start use case root timer 00527 timer().start(); 00528 } 00529 00530 UseCaseEnvironment::~UseCaseEnvironment() 00531 { 00532 stk::report_deferred_messages(m_comm); 00533 00534 // Stop use case root timer 00535 timer().stop(); 00536 00537 stk::diag::printTimersTable(out(), timer(), stk::diag::METRICS_CPU_TIME | stk::diag::METRICS_WALL_TIME, false, m_comm); 00538 00539 stk::diag::deleteRootTimer(timer()); 00540 00541 static_cast<stk::indent_streambuf *>(dwout().rdbuf())->redirect(std::cout.rdbuf()); 00542 00543 stk::unregister_ostream(tout()); 00544 stk::unregister_ostream(dout()); 00545 stk::unregister_ostream(pout()); 00546 stk::unregister_ostream(out()); 00547 00548 stk::unregister_log_ostream(std::cerr); 00549 stk::unregister_log_ostream(std::cout); 00550 00551 if (m_need_to_finalize) { 00552 stk::parallel_machine_finalize(); 00553 } 00554 } 00555 00556 } // namespace use_case