Sierra Toolkit  Version of the Day
UseCaseEnvironment.cpp
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2010 Sandia Corporation. */
3 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */
4 /* license for use of this work by or on behalf of the U.S. Government. */
5 /* Export of this program may require a license from the */
6 /* United States Government. */
7 /*------------------------------------------------------------------------*/
8 
9 #include <iostream>
10 #include <iomanip>
11 
12 #include <stk_util/diag/Writer.hpp>
13 #include <stk_util/diag/PrintTimer.hpp>
14 
15 #include <stk_util/util/Bootstrap.hpp>
16 #include <stk_util/util/IndentStreambuf.hpp>
17 
18 #include <stk_util/parallel/ParallelReduce.hpp>
19 
20 #include <stk_util/use_cases/UseCaseEnvironment.hpp>
21 
22 namespace {
23 
24 namespace bopt = boost::program_options;
25 
26 // Parse command line bit masks and produce -h documentation. (Probably moved to Util at some point)
27 typedef unsigned long OptionMask;
28 
29 struct OptionMaskName
30 {
31  OptionMaskName()
32  : m_name(""),
33  m_mask(0),
34  m_description("")
35  {}
36 
37  OptionMaskName(const std::string &name, const OptionMask &mask, const std::string &description = "No description available")
38  : m_name(name),
39  m_mask(mask),
40  m_description(description)
41  {}
42 
43  virtual ~OptionMaskName()
44  {}
45 
46  std::string m_name;
47  OptionMask m_mask;
48  std::string m_description;
49 };
50 
51 
52 class OptionMaskNameMap: public std::map<std::string, OptionMaskName>
53 {
54 public:
55  void mask(const std::string &name, const OptionMask mask, const std::string &description) {
56  iterator it = find(name);
57  if (it == end())
58  insert(std::make_pair(name, OptionMaskName(name, mask, description)));
59  else {
60  (*it).second.m_mask = mask;
61  (*it).second.m_description = description;
62  }
63  }
64 };
65 
66 class OptionMaskParser
67 {
68 public:
69  typedef OptionMask Mask;
70 
71 public:
76  OptionMaskParser(const std::string &description)
77  : m_optionMaskNameMap(),
78  m_description(description),
79  m_optionMask(0),
80  m_status(true)
81  {}
82 
83  virtual ~OptionMaskParser()
84  {}
85 
86  Mask parse(const char *mask) const;
87 
88  virtual void parseArg(const std::string &name) const;
89 
90  std::string describe() const {
91  std::ostringstream strout;
92  strout << m_description << std::endl;
93  for (OptionMaskNameMap::const_iterator it = m_optionMaskNameMap.begin(); it != m_optionMaskNameMap.end(); ++it)
94  strout << " " << (*it).first << std::setw(14 - (*it).first.size()) << " " << (*it).second.m_description << std::endl;
95  return strout.str();
96  }
97 
98  void mask(const std::string &name, const Mask mask, const std::string &description) {
99  m_optionMaskNameMap.mask(name, mask, description);
100  }
101 
102 protected:
103  OptionMaskNameMap m_optionMaskNameMap;
104  std::string m_description;
105  mutable OptionMask m_optionMask;
106  mutable bool m_status;
107 };
108 
109 
110 OptionMaskParser::Mask
111 OptionMaskParser::parse(
112  const char * mask) const
113 {
114  if (mask) {
115  const std::string mask_string(mask);
116 
117  m_status = true;
118 
119  std::string::const_iterator it0 = mask_string.begin();
120  std::string::const_iterator it1;
121  std::string::const_iterator it2;
122  std::string::const_iterator it3;
123  do {
124  // Trim preceeding spaces
125  while (it0 != mask_string.end() && *it0 == ' ')
126  it0++;
127 
128  if (it0 == mask_string.end())
129  break;
130 
131  for (it1 = it0; it1 != mask_string.end(); ++it1) {
132  if (*it1 == '(' || *it1 == ':' || *it1 == ',')
133  break;
134  }
135 
136  // Trim trailing spaces
137  it2 = it1;
138  while (it2 != it0 && *(it2 - 1) == ' ')
139  --it2;
140 
141  std::string name(it0, it2);
142 
143  // Get argument list
144  if (*it1 == '(') {
145  it2 = it1 + 1;
146 
147  // Trim preceeding spaces
148  while (it2 != mask_string.end() && *it2 == ' ')
149  ++it2;
150 
151  int paren_count = 0;
152 
153  for (; it1 != mask_string.end(); ++it1) {
154  if (*it1 == '(')
155  ++paren_count;
156  else if (*it1 == ')') {
157  --paren_count;
158  if (paren_count == 0)
159  break;
160  }
161  }
162  it3 = it1;
163 
164  // Trim trailing spaces
165  while (it3 != it2 && *(it3 - 1) == ' ')
166  --it3;
167 
168  // Find next argument start
169  for (; it1 != mask_string.end(); ++it1)
170  if (*it1 == ':' || *it1 == ',')
171  break;
172  }
173  else
174  it2 = it3 = it1;
175 
176  const std::string arg(it2, it3);
177 
178  parseArg(name);
179 
180  it0 = it1 + 1;
181  } while (it1 != mask_string.end());
182  }
183 
184  return m_optionMask;
185 }
186 
187 
188 void
189 OptionMaskParser::parseArg(
190  const std::string & name) const
191 {
192  OptionMaskNameMap::const_iterator mask_entry = m_optionMaskNameMap.find(name);
193 
194  if (mask_entry != m_optionMaskNameMap.end()) m_optionMask |= (*mask_entry).second.m_mask;
195  else {
196  Mask mask_hex = 0;
197  std::istringstream mask_hex_stream(name.c_str());
198  if (mask_hex_stream >> std::resetiosflags(std::ios::basefield) >> mask_hex)
199  m_optionMask |= mask_hex;
200  else
201  m_status = false;
202  }
203 }
204 
205 // Build output logging description for binding output streams
206 std::string
207 build_log_description(
208  const bopt::variables_map & vm,
209  const std::string & working_directory,
210  int parallel_rank,
211  int parallel_size)
212 {
213  std::ostringstream output_description;
214 
215  // On processor 0:
216  // [outfile=path] [poutfile=path.n.r] [doutfile=path.n.r] out>{-|cout|cerr|outfile}+pout pout>{null|poutfile} dout>{out|doutfile}
217 
218  // On processor 1..n:
219  // [poutfile=path.n.r] [doutfile=path.n.r] out>pout pout>{null|poutfile} dout>{out|doutfile}
220 
221  std::string out_path = "-";
222  if (vm.count("output-log"))
223  out_path = vm["output-log"].as<std::string>();
224  if (out_path == "-")
225  out_path = "cout";
226 
227  std::string out_ostream;
228 
229  if (!stk_classic::get_log_ostream(out_path))
230  if (out_path.size() && out_path[0] != '/')
231  out_path = working_directory + out_path;
232 
233  if (parallel_rank == 0) {
234  if (!stk_classic::get_log_ostream(out_path)) {
235  output_description << "outfile=\"" << out_path << "\"";
236  out_ostream = "outfile";
237  }
238  else
239  out_ostream = out_path;
240  }
241  else
242  out_ostream = "null";
243 
244  std::string pout_ostream = "null";
245  if (vm.count("pout")) {
246  std::string pout_path = vm["pout"].as<std::string>();
247  if (pout_path == "-") {
248  std::ostringstream s;
249 
250  if (stk_classic::get_log_ostream(out_path))
251  s << working_directory << "sierra.log." << parallel_size << "." << parallel_rank;
252  else
253  s << out_path << "." << parallel_size << "." << parallel_rank;
254  pout_path = s.str();
255  }
256  else if (pout_path.find("/") == std::string::npos && !stk_classic::get_log_ostream(pout_path)) {
257  std::ostringstream s;
258 
259  s << working_directory << pout_path << "." << parallel_size << "." << parallel_rank;
260  pout_path = s.str();
261  }
262 
263  if (!stk_classic::get_log_ostream(pout_path)) {
264  output_description << " poutfile=\"" << pout_path << "\"";
265  pout_ostream = "poutfile";
266  }
267  else
268  pout_ostream = pout_path;
269  }
270 
271  std::string dout_ostream;
272  if (vm.count("dout")) {
273  std::string dout_path = vm["dout"].as<std::string>();
274  if (!dout_path.empty() && stk_classic::is_registered_ostream(dout_path))
275  dout_ostream = dout_path;
276  else {
277  std::ostringstream s;
278  if (dout_path.size() && dout_path[0] != '/')
279  s << working_directory << dout_path << "." << parallel_size << "." << parallel_rank;
280  else
281  s << dout_path << parallel_size << "." << parallel_rank;
282  dout_path = s.str();
283  output_description << " doutfile=\"" << dout_path << "\"";
284  dout_ostream = "doutfile";
285  }
286  }
287  else
288  dout_ostream = "out";
289 
290  if (parallel_rank == 0)
291  output_description << " out>" << out_ostream << "+pout";
292  else
293  output_description << " out>pout";
294 
295  output_description << " pout>" << pout_ostream << " dout>" << dout_ostream;
296 
297  return output_description.str();
298 }
299 
300 OptionMaskParser dw_option_mask("use case diagnostic writer");
301 OptionMaskParser timer_option_mask("use case timers");
302 
303 void
304 bootstrap()
305 {
308  dw_option_mask.mask("search", use_case::LOG_SEARCH, "log search diagnostics");
309  dw_option_mask.mask("transfer", use_case::LOG_TRANSFER, "log transfer diagnostics");
310  dw_option_mask.mask("timer", use_case::LOG_TIMER, "log timer diagnostics");
311 
312  timer_option_mask.mask("mesh", use_case::TIMER_MESH, "mesh operations timers");
313  timer_option_mask.mask("meshio", use_case::TIMER_MESH_IO, "mesh I/O timers");
314  timer_option_mask.mask("transfer", use_case::TIMER_TRANSFER, "transfer timers");
315  timer_option_mask.mask("search", use_case::TIMER_SEARCH, "search timers");
316 
317  boost::program_options::options_description desc("Use case environment options");
318  desc.add_options()
319  ("help,h", "produce help message")
320  ("directory,d", boost::program_options::value<std::string>(), "working directory")
321  ("output-log,o", boost::program_options::value<std::string>(), "output log path")
322  ("pout", boost::program_options::value<std::string>()->implicit_value("-"), "per-processor log file path")
323  ("dout", boost::program_options::value<std::string>()->implicit_value("out"), "diagnostic output stream one of: 'cout', 'cerr', 'out' or a file path")
324  ("dw", boost::program_options::value<std::string>(), dw_option_mask.describe().c_str())
325  ("timer", boost::program_options::value<std::string>(), timer_option_mask.describe().c_str())
326  ("runtest,r", boost::program_options::value<std::string>(), "runtest pid file");
327 
329 }
330 
331 stk_classic::Bootstrap x(bootstrap);
332 
333 } // namespace <empty>
334 
335 namespace use_case {
336 
337 // Output streams
338 std::ostream &
339 out() {
340  static std::ostream s_out(std::cout.rdbuf());
341 
342  return s_out;
343 }
344 
345 
346 std::ostream &
347 pout() {
348  static std::ostream s_pout(std::cout.rdbuf());
349 
350  return s_pout;
351 }
352 
353 
354 std::ostream &
355 dout() {
356  static std::ostream s_dout(std::cout.rdbuf());
357 
358  return s_dout;
359 }
360 
361 
362 std::ostream &
363 tout() {
364  static std::ostream s_tout(std::cout.rdbuf());
365 
366  return s_tout;
367 }
368 
369 
370 std::ostream &
371 dwout() {
372  static stk_classic::indent_streambuf s_dwoutStreambuf(std::cout.rdbuf());
373  static std::ostream s_dwout(&s_dwoutStreambuf);
374 
375  return s_dwout;
376 }
377 
378 
379 // Diagnostic writer
381 dw()
382 {
383  static stk_classic::diag::Writer s_diagWriter(dwout().rdbuf(), 0);
384 
385  return s_diagWriter;
386 }
387 
388 
389 // Message reporting
390 std::ostream &
391 operator<<(
392  std::ostream & os,
393  message_type type)
394 {
395  switch (type & stk_classic::MSG_TYPE_MASK) {
396  case MSG_WARNING:
397  os << "Warning";
398  break;
399  case MSG_FATAL:
400  os << "Fatal error";
401  break;
402  case MSG_INFORMATION:
403  os << "Information";
404  break;
405  case MSG_EXCEPTION:
406  os << "Exception";
407  break;
408  case MSG_PARALLEL_EXCEPTION:
409  os << "Parallel exception";
410  break;
411  }
412  return os;
413 }
414 
415 
416 void
417 report_handler(
418  const char * message,
419  int type)
420 {
421  if (type & stk_classic::MSG_DEFERRED)
422  pout() << "Deferred " << (message_type) type << ": " << message << std::endl;
423 
424  else
425  out() << (message_type) type << ": " << message << std::endl;
426 }
427 
428 
429 // Timers
431 timerSet()
432 {
433  static stk_classic::diag::TimerSet s_timerSet(TIMER_ALL);
434 
435  return s_timerSet;
436 }
437 
438 
439 stk_classic::diag::Timer &timer() {
440  static stk_classic::diag::Timer s_timer = stk_classic::diag::createRootTimer("Use Cases", timerSet());
441 
442  return s_timer;
443 }
444 
445 
446 UseCaseEnvironment::UseCaseEnvironment(
447  int * argc,
448  char *** argv)
449  : m_comm(stk_classic::parallel_machine_init(argc, argv)),
450  m_need_to_finalize(true)
451 {
452  initialize(argc, argv);
453 }
454 
455 UseCaseEnvironment::UseCaseEnvironment(
456  int * argc,
457  char *** argv,
459  : m_comm(comm),
460  m_need_to_finalize(false)
461 {
462  initialize(argc, argv);
463 }
464 
465 void UseCaseEnvironment::initialize(int* argc, char*** argv)
466 {
467  stk_classic::register_log_ostream(std::cout, "cout");
468  stk_classic::register_log_ostream(std::cerr, "cerr");
469 
474 
475  static_cast<stk_classic::indent_streambuf *>(dwout().rdbuf())->redirect(dout().rdbuf());
476 
477  stk_classic::set_report_handler(report_handler);
478 
480 
481  for (int i = 0; i < *argc; ++i) {
482  const std::string s((*argv)[i]);
483  if (s == "-h" || s == "-help" || s == "--help") {
484  std::cout << "Usage: " << (*argv)[0] << " [options...]" << std::endl;
485  std::cout << stk_classic::get_options_description() << std::endl;
486  return; // So application can handle app-specific options.
487  }
488  }
489 
490  // Broadcast argc and argv to all processors.
493 
494  stk_classic::BroadcastArg b_arg(m_comm, *argc, *argv);
495 
496  // Parse broadcast arguments
497  bopt::variables_map &vm = stk_classic::get_variables_map();
498  try {
499  bopt::store(bopt::command_line_parser(b_arg.m_argc, b_arg.m_argv).options(stk_classic::get_options_description()).allow_unregistered().run(), vm);
500  bopt::notify(vm);
501  }
502  catch (std::exception &x) {
504  }
505 
506  // Parse diagnostic messages to display
507  if (vm.count("dw"))
508  dw().setPrintMask(dw_option_mask.parse(vm["dw"].as<std::string>().c_str()));
509 
510  // Parse timer metrics and classes to display
511  stk_classic::diag::setEnabledTimerMetricsMask(stk_classic::diag::METRICS_CPU_TIME | stk_classic::diag::METRICS_WALL_TIME);
512  if (vm.count("timer"))
513  timerSet().setEnabledTimerMask(timer_option_mask.parse(vm["timer"].as<std::string>().c_str()));
514 
515  // Set working directory
516  m_workingDirectory = "./";
517  if (vm.count("directory"))
518  m_workingDirectory = vm["directory"].as<std::string>();
519  if (m_workingDirectory.length() && m_workingDirectory[m_workingDirectory.length() - 1] != '/')
520  m_workingDirectory += "/";
521 
522  std::string output_description = build_log_description(vm, m_workingDirectory, parallel_rank, parallel_size);
523 
524  stk_classic::bind_output_streams(output_description);
525 
526  dout() << "Output log binding: " << output_description << std::endl;
527 
528  // Start use case root timer
529  timer().start();
530 }
531 
532 UseCaseEnvironment::~UseCaseEnvironment()
533 {
535 
536 // Stop use case root timer
537  timer().stop();
538 
539  stk_classic::diag::printTimersTable(out(), timer(), stk_classic::diag::METRICS_CPU_TIME | stk_classic::diag::METRICS_WALL_TIME, false, m_comm);
540 
541  stk_classic::diag::deleteRootTimer(timer());
542 
543  static_cast<stk_classic::indent_streambuf *>(dwout().rdbuf())->redirect(std::cout.rdbuf());
544 
549 
552 
553  if (m_need_to_finalize) {
555  }
556 }
557 
558 bool print_status(stk_classic::ParallelMachine comm, bool success)
559 {
560  int error_flag = success ? 0 : 1;
561  stk_classic::all_reduce( comm , stk_classic::ReduceMax<1>( & error_flag ) );
562  bool all_success = !error_flag;
563 
564  int rank = stk_classic::parallel_machine_rank(comm);
565  if (rank == 0) {
566  std::cout << ( all_success ? "STK_USECASE_PASS" : "Use case failed.") << std::endl;
567  }
568 
569  return all_success;
570 }
571 
572 } // namespace use_case
Message is an exception.
std::ostream & dout()
Diagnostic output stream.
Definition: OutputLog.cpp:674
std::ostream & dwout()
Diagnostic writer stream.
Definition: OutputLog.cpp:690
Message is informational.
Class BroadcastArg creates a copy of argc and argv after broadcasting them from processor 0...
_resetiosflags resetiosflags(std::ios_base::fmtflags flags)
Function resetiosflags clears the ios flags as a manipulator.
const std::string working_directory()
Function working_directory returns the current working directory of this application execution...
Definition: Env.cpp:252
std::ostream & pout()
Per-processor output stream (See RuntimeDeferredx)
Definition: OutputLog.cpp:666
std::ostream & out()
Normal output stream.
Definition: OutputLog.cpp:658
void setEnabledTimerMask(TimerMask timer_mask)
Definition: Timer.hpp:157
int parallel_rank()
function parallel_rank returns the rank of this processor in the current mpi communicator.
Definition: Env.cpp:318
unsigned parallel_machine_rank(ParallelMachine parallel_machine)
Member function parallel_machine_rank ...
Definition: Parallel.cpp:29
boost::program_options::options_description & get_options_description()
Function get_options_description is a singleton used to store the command line option descriptions fo...
std::ostream & operator<<(std::ostream &s, const Bucket &k)
Print the part names for which this bucket is a subset.
Definition: Bucket.cpp:239
Class basic_indent_streambuf implements a output streambuf that performs indentation, blank line removal and outline bracing, sending the result character stream to another output stream buffer.
static void bootstrap()
Member function bootstrap runs through the stored bootstrap function pointers and executes each funct...
Definition: Bootstrap.cpp:21
void bind_output_streams(const std::string &output_description)
Function bind_output_streams parses the output_description and opens and registers the log streams an...
Definition: OutputLog.cpp:644
Message is a warning.
unsigned parallel_machine_size(ParallelMachine parallel_machine)
Member function parallel_machine_size ...
Definition: Parallel.cpp:18
bool is_registered_ostream(const std::string &name)
Function is_registered_ostream returns true if an output stream of the specified name is registered...
Definition: OutputLog.cpp:356
_setw setw(int width)
Function setw sets the width for the next field as a manipulator.
Definition: WriterManip.hpp:44
void parallel_machine_finalize()
parallel_machine_finalize calls MPI_Finalize.
Definition: Parallel.hpp:64
Class TimerSet implements a set of timer classifications. A time classification consists of a bit mas...
Definition: Timer.hpp:117
Sierra Toolkit.
Writer & setPrintMask(PrintMask mask=0)
Member function setPrintMask sets the print output mask.
Definition: Writer.hpp:255
Class Writer implements a runtime selectable diagnostic output writer to aid in the development and d...
Definition: Writer.hpp:49
MPI_Comm ParallelMachine
Definition: Parallel.hpp:32
std::ostream & tout()
Regression test textual output stream.
Definition: OutputLog.cpp:682
Class Bootstrap serves as a bootstrapping mechanism for products in the sierra toolkit and elsewhere...
Definition: Bootstrap.hpp:35
boost::program_options::variables_map & get_variables_map()
Function get_variabel_map is a singleton used to store the variables parsed from the line option desc...
ParallelMachine parallel_machine_init(int *argc, char ***argv)
parallel_machine_init calls MPI_Init.
Definition: Parallel.hpp:54
Class RuntimeDoomedSymmetric reports a fatal error message to the report system.
int parallel_size()
function parallel_size returns the number of processors in the current mpi communicator.
Definition: Env.cpp:314
void all_reduce(ParallelMachine, const ReduceOp &)
Part * find(const PartVector &parts, const std::string &name)
Find a part by name in a collection of parts.
Definition: Part.cpp:22
REH set_report_handler(REH reh)
Function set_report_handler sets the exception report function to be called when an report_exception(...
std::ostream * get_log_ostream(const std::string &name)
Function get_log_file_ostream return the output stream of the log file with the specified name from t...
Definition: OutputLog.cpp:263
Message is deferred.
void report_deferred_messages(ParallelMachine comm)
Function report_deferred_messages aggregates and reports the message on the root processor.
void unregister_ostream(std::ostream &os)
Function unregister_ostream unregisters an output stream.
Definition: OutputLog.cpp:300
void unregister_log_ostream(std::ostream &os)
Function register_log_ostream takes an existing std::ostream and makes it available for output redire...
Definition: OutputLog.cpp:228
void register_log_ostream(std::ostream &os, const std::string &name)
Function register_log_ostream takes an existing std::ostream and makes it available for output redire...
Definition: OutputLog.cpp:205
bool insert(PartVector &v, Part &part)
Insert a part into a properly ordered collection of parts. Returns true if this is a new insertion...
Definition: Part.cpp:85
Class Timer implements a diagnostic timer and timer container for the collection and display of execu...
Definition: Timer.hpp:185
void register_ostream(std::ostream &os, const std::string &name)
Function register_ostream registers an output stream with the output stream registry. The registration process creates an intermediate tee streambuf.
Definition: OutputLog.cpp:275