|
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 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_classic::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_classic::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_classic::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_classic::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_classic::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_classic::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_classic::get_options_description().add(desc); 00329 } 00330 00331 stk_classic::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_classic::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_classic::diag::Writer & 00381 dw() 00382 { 00383 static stk_classic::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_classic::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_classic::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_classic::diag::TimerSet & 00431 timerSet() 00432 { 00433 static stk_classic::diag::TimerSet s_timerSet(TIMER_ALL); 00434 00435 return s_timerSet; 00436 } 00437 00438 00439 stk_classic::diag::Timer &timer() { 00440 static stk_classic::diag::Timer s_timer = stk_classic::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_classic::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_classic::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_classic::register_log_ostream(std::cout, "cout"); 00468 stk_classic::register_log_ostream(std::cerr, "cerr"); 00469 00470 stk_classic::register_ostream(out(), "out"); 00471 stk_classic::register_ostream(pout(), "pout"); 00472 stk_classic::register_ostream(dout(), "dout"); 00473 stk_classic::register_ostream(tout(), "tout"); 00474 00475 static_cast<stk_classic::indent_streambuf *>(dwout().rdbuf())->redirect(dout().rdbuf()); 00476 00477 stk_classic::set_report_handler(report_handler); 00478 00479 stk_classic::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_classic::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_classic::parallel_machine_rank(m_comm); 00492 int parallel_size = stk_classic::parallel_machine_size(m_comm); 00493 00494 stk_classic::BroadcastArg b_arg(m_comm, *argc, *argv); 00495 00496 // Parse broadcast arguments 00497 bopt::variables_map &vm = stk_classic::get_variables_map(); 00498 try { 00499 bopt::store(bopt::command_line_parser(b_arg.m_argc, b_arg.m_argv).options(stk_classic::get_options_description()).allow_unregistered().run(), vm); 00500 bopt::notify(vm); 00501 } 00502 catch (std::exception &x) { 00503 stk_classic::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_classic::diag::setEnabledTimerMetricsMask(stk_classic::diag::METRICS_CPU_TIME | stk_classic::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_classic::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_classic::report_deferred_messages(m_comm); 00535 00536 // Stop use case root timer 00537 timer().stop(); 00538 00539 stk_classic::diag::printTimersTable(out(), timer(), stk_classic::diag::METRICS_CPU_TIME | stk_classic::diag::METRICS_WALL_TIME, false, m_comm); 00540 00541 stk_classic::diag::deleteRootTimer(timer()); 00542 00543 static_cast<stk_classic::indent_streambuf *>(dwout().rdbuf())->redirect(std::cout.rdbuf()); 00544 00545 stk_classic::unregister_ostream(tout()); 00546 stk_classic::unregister_ostream(dout()); 00547 stk_classic::unregister_ostream(pout()); 00548 stk_classic::unregister_ostream(out()); 00549 00550 stk_classic::unregister_log_ostream(std::cerr); 00551 stk_classic::unregister_log_ostream(std::cout); 00552 00553 if (m_need_to_finalize) { 00554 stk_classic::parallel_machine_finalize(); 00555 } 00556 } 00557 00558 bool print_status(stk_classic::ParallelMachine comm, bool success) 00559 { 00560 int error_flag = success ? 0 : 1; 00561 stk_classic::all_reduce( comm , stk_classic::ReduceMax<1>( & error_flag ) ); 00562 bool all_success = !error_flag; 00563 00564 int rank = stk_classic::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