Interface Documentation
Version: invalid
context.hh
Go to the documentation of this file.
1 /*
2  @@@@@@@@ @@ @@@@@@ @@@@@@@@ @@
3  /@@///// /@@ @@////@@ @@////// /@@
4  /@@ /@@ @@@@@ @@ // /@@ /@@
5  /@@@@@@@ /@@ @@///@@/@@ /@@@@@@@@@/@@
6  /@@//// /@@/@@@@@@@/@@ ////////@@/@@
7  /@@ /@@/@@//// //@@ @@ /@@/@@
8  /@@ @@@//@@@@@@ //@@@@@@ @@@@@@@@ /@@
9  // /// ////// ////// //////// //
10 
11  Copyright (c) 2016, Triad National Security, LLC
12  All rights reserved.
13  */
14 #pragma once
15 
18 #if !defined(__FLECSI_PRIVATE__)
19 #error Do not include this file directly!
20 #endif
21 
22 #include "flecsi/data/layout.hh"
24 #include "flecsi/run/types.hh"
25 #include "flecsi/topo/core.hh"
27 #include <flecsi/flog.hh>
28 
29 #include <boost/optional.hpp>
30 #include <boost/program_options.hpp>
31 
32 #include <cstddef>
33 #include <functional>
34 #include <map>
35 #include <set>
36 #include <string>
37 #include <unordered_map>
38 #include <utility>
39 #include <vector>
40 
41 namespace flecsi {
42 
43 inline log::devel_tag context_tag("context");
44 
45 namespace run {
46 
47 struct context_t; // supplied by backend
48 
49 enum status : int {
50  success,
51  help,
52  control,
53  command_line_error,
54  error, // add specific error modes
55 }; // initialization_codes
56 
64 struct context {
65 
66  /*--------------------------------------------------------------------------*
67  Public types.
68  *--------------------------------------------------------------------------*/
69 
70  using field_info_store_t = data::fields;
71 
79  size_t index_subspace;
80  size_t capacity;
81  size_t size = 0;
82  }; // struct index_subspace_info_t
83 
84  /*--------------------------------------------------------------------------*
85  Deleted contructor and assignment interfaces.
86  *--------------------------------------------------------------------------*/
87 
88  context(const context &) = delete;
89  context & operator=(const context &) = delete;
90  context(context &&) = delete;
91  context & operator=(context &&) = delete;
92 
93  /*
94  Meyer's singleton instance.
95  */
96 
97  static inline context_t & instance();
98 
99  bool initialized() {
100  return initialized_;
101  }
102 
103  /*--------------------------------------------------------------------------*
104  Program options interface.
105  *--------------------------------------------------------------------------*/
106 
107  boost::program_options::positional_options_description &
108  positional_description() {
109  return positional_desc_;
110  }
111 
112  std::map<std::string, std::string> & positional_help() {
113  return positional_help_;
114  }
115 
116  boost::program_options::options_description & hidden_options() {
117  return hidden_options_;
118  }
119 
120  std::map<std::string,
121  std::pair<bool, std::function<bool(boost::any const &)>>> &
122  option_checks() {
123  return option_checks_;
124  }
125 
126  std::vector<char *> & argv() {
127  return argv_;
128  }
129 
130  std::string const & program() {
131  return program_;
132  }
133 
134  auto & descriptions_map() {
135  return descriptions_map_;
136  }
137 
138  std::vector<std::string> const & unrecognized_options() {
139  flog_assert(initialized_,
140  "unitialized program options -> "
141  "invoke flecsi::initialize_program_options");
142  return unrecognized_options_;
143  }
144 
145  /*--------------------------------------------------------------------------*
146  Runtime interface.
147  *--------------------------------------------------------------------------*/
148 
149  inline int initialize_generic(int argc, char ** argv, bool dependent) {
150 
151  initialize_dependent_ = dependent;
152 
153  // Save command-line arguments
154  for(auto i(0); i < argc; ++i) {
155  argv_.push_back(argv[i]);
156  } // for
157 
158  program_ = argv[0];
159  program_ = program_.substr(program_.rfind('/') + 1);
160 
161  boost::program_options::options_description master("Basic Options");
162  master.add_options()("help,h", "Print this message and exit.");
163 
164  // Add externally-defined descriptions to the main description
165  for(auto & od : descriptions_map_) {
166  if(od.first != "FleCSI Options") {
167  master.add(od.second);
168  } // if
169  } // for
170 
171  boost::program_options::options_description flecsi_desc =
172  descriptions_map_.count("FleCSI Options")
173  ? descriptions_map_["FleCSI Options"]
174  : boost::program_options::options_description("FleCSI Options");
175 
176  flecsi_desc.add_options()("backend-args",
177  boost::program_options::value(&backend_)->default_value(""),
178  "Pass arguments to the runtime backend. The single argument is a quoted "
179  "string of backend-specific options.");
180 #if defined(FLECSI_ENABLE_FLOG)
181  // Add FleCSI options
182  flecsi_desc.add_options() // clang-format off
183  (
184  "flog-tags",
185  boost::program_options::value(&flog_tags_)
186  ->default_value("all"),
187  "Enable the specified output tags, e.g., --flog-tags=tag1,tag2."
188  )
189  (
190  "flog-verbose",
191  boost::program_options::value(&flog_verbose_)
192  ->implicit_value(1)
193  ->default_value(0),
194  "Enable verbose output. Passing '-1' will strip any additional"
195  " decorations added by flog and will only output the user's message."
196  )
197  (
198  "flog-process",
199  boost::program_options::value(&flog_output_process_)->default_value(-1),
200  "Restrict output to the specified process id."
201  ); // clang-format on
202 #endif
203 
204  // Make an options description to hold all options. This is useful
205  // to exlude hidden options from help.
206  boost::program_options::options_description all("All Options");
207  all.add(master);
208  all.add(flecsi_desc);
209  all.add(hidden_options_);
210 
211  boost::program_options::parsed_options parsed =
212  boost::program_options::command_line_parser(argc, argv)
213  .options(all)
214  .positional(positional_desc_)
215  .allow_unregistered()
216  .run();
217 
218  auto print_usage = [this](std::string program,
219  auto const & master,
220  auto const & flecsi) {
221  if(process_ == 0) {
222  std::cout << "Usage: " << program << " ";
223 
224  size_t positional_count = positional_desc_.max_total_count();
225  size_t max_label_chars = std::numeric_limits<size_t>::min();
226 
227  for(size_t i{0}; i < positional_count; ++i) {
228  std::cout << "<" << positional_desc_.name_for_position(i) << "> ";
229 
230  const size_t size = positional_desc_.name_for_position(i).size();
231  max_label_chars = size > max_label_chars ? size : max_label_chars;
232  } // for
233 
234  max_label_chars += 2;
235 
236  std::cout << std::endl << std::endl;
237 
238  if(positional_count) {
239  std::cout << "Positional Options:" << std::endl;
240 
241  for(size_t i{0}; i < positional_desc_.max_total_count(); ++i) {
242  auto const & name = positional_desc_.name_for_position(i);
243  auto help = positional_help_.at(name);
244  std::cout << " " << name << " ";
245  std::cout << std::string(max_label_chars - name.size() - 2, ' ');
246 
247  if(help.size() > 78 - max_label_chars) {
248  std::string first = help.substr(
249  0, help.substr(0, 78 - max_label_chars).find_last_of(' '));
250  std::cout << first << std::endl;
251  help =
252  help.substr(first.size() + 1, help.size() - first.size() + 1);
253 
254  while(help.size() > 78 - max_label_chars) {
255  std::string part = help.substr(
256  0, help.substr(0, 78 - max_label_chars).find_last_of(' '));
257  std::cout << std::string(max_label_chars + 1, ' ') << part
258  << std::endl;
259  help = help.substr(part.size() + 1, help.size() - part.size());
260  } // while
261 
262  std::cout << std::string(max_label_chars + 1, ' ') << help
263  << std::endl;
264  }
265  else {
266  std::cout << help << std::endl;
267  } // if
268 
269  } // for
270 
271  std::cout << std::endl;
272  } // if
273 
274  std::cout << master << std::endl;
275  std::cout << flecsi << std::endl;
276 
277 #if defined(FLECSI_ENABLE_FLOG)
278  auto const & tm = log::flog_t::instance().tag_map();
279 
280  if(tm.size()) {
281  std::cout << "Available FLOG Tags (FleCSI Logging Utility):"
282  << std::endl;
283  } // if
284 
285  for(auto t : tm) {
286  std::cout << " " << t.first << std::endl;
287  } // for
288 #endif
289  } // if
290  }; // print_usage
291 
292  try {
293  boost::program_options::variables_map vm;
294  boost::program_options::store(parsed, vm);
295 
296  if(vm.count("help")) {
297  print_usage(program_, master, flecsi_desc);
298  return status::help;
299  } // if
300 
301  boost::program_options::notify(vm);
302 
303  // Call option check methods
304  for(auto const & [name, boost_any] : vm) {
305  auto const & ita = option_checks_.find(name);
306  if(ita != option_checks_.end()) {
307  auto const & [positional, check] = ita->second;
308 
309  if(!check(boost_any.value())) {
310  std::string dash = positional ? "" : "--";
311  std::cerr << FLOG_COLOR_LTRED << "ERROR: " << FLOG_COLOR_RED
312  << "invalid argument for '" << dash << name
313  << "' option!!!" << FLOG_COLOR_PLAIN << std::endl;
314  print_usage(program_, master, flecsi_desc);
315  return status::help;
316  } // if
317  } // if
318  } // for
319  }
320  catch(boost::program_options::error & e) {
321  std::string error(e.what());
322 
323  auto pos = error.find("--");
324  if(pos != std::string::npos) {
325  error.replace(pos, 2, "");
326  } // if
327 
328  std::cerr << FLOG_COLOR_LTRED << "ERROR: " << FLOG_COLOR_RED << error
329  << "!!!" << FLOG_COLOR_PLAIN << std::endl
330  << std::endl;
331  print_usage(program_, master, flecsi_desc);
332  return status::command_line_error;
333  } // try
334 
335  unrecognized_options_ = boost::program_options::collect_unrecognized(
336  parsed.options, boost::program_options::include_positional);
337 
338 #if defined(FLECSI_ENABLE_FLOG)
340  flog_tags_, flog_verbose_, flog_output_process_)) {
341  return status::error;
342  } // if
343 #endif
344 
345 #if defined(FLECSI_ENABLE_KOKKOS)
346  if(initialize_dependent_) {
347  // Need to capture status from this
348  Kokkos::initialize(argc, argv);
349  } // if
350 #endif
351 
352  initialized_ = true;
353 
354  return status::success;
355  } // initialize_generic
356 
357  inline void finalize_generic() {
358 #if defined(FLECSI_ENABLE_FLOG)
359  log::flog_t::instance().finalize();
360 #endif
361 
362  if(initialize_dependent_) {
363 #if defined(FLECSI_ENABLE_KOKKOS)
365 #endif
366  } // if
367  } // finalize_generic
368 
369 #ifdef DOXYGEN // these functions are implemented per-backend
370  /*
371  Documented in execution.hh
372  */
373 
374  int initialize(int argc, char ** argv, bool dependent);
375 
382  void finalize();
383 
393  int start(const std::function<int(int, char **)> action &);
394 
399  std::size_t process() const;
400 
405  std::size_t processes() const;
406 
411  std::size_t threads_per_process() const;
412 
421  std::size_t threads() const;
422 
429  static std::size_t task_depth();
430 
435  std::size_t color() const;
436 
441  std::size_t colors() const;
442 #endif
443 
448  int & exit_status() {
449  return exit_status_;
450  }
451 
452  void register_init(void callback()) {
453  init_registry.push_back(callback);
454  }
455 
456  /*--------------------------------------------------------------------------*
457  Topology interface.
458  *--------------------------------------------------------------------------*/
459 
469  bool topology_fields_registered(size_t type_key, size_t instance_key) {
470  return !registered_topology_fields_
471  .insert(std::make_pair(type_key, instance_key))
472  .second;
473  } // topology_fields_registered
474 
475  /*--------------------------------------------------------------------------*
476  Field interface.
477  *--------------------------------------------------------------------------*/
478 
486  template<class Topo, std::size_t Index>
487  void add_field_info(const data::field_info_t & field_info) {
488  constexpr std::size_t NIndex = topo::index_spaces<Topo>;
489  static_assert(Index < NIndex, "No such index space");
490  topology_field_info_map_.try_emplace(topo::id<Topo>(), NIndex)
491  .first->second[Index]
492  .push_back(&field_info);
493  } // add_field_information
494 
502  template<class Topo, std::size_t Index = topo::default_space<Topo>>
503  field_info_store_t const & get_field_info_store() const {
504  static_assert(Index < topo::index_spaces<Topo>, "No such index space");
505 
506  static const field_info_store_t empty;
507 
508  auto const & tita = topology_field_info_map_.find(topo::id<Topo>());
509  if(tita == topology_field_info_map_.end())
510  return empty;
511 
512  return tita->second[Index];
513  } // get_field_info_store
514 
526  void add_index_subspace(size_t index_subspace, size_t capacity) {
528  info.index_subspace = index_subspace;
529  info.capacity = capacity;
530 
531  index_subspace_map_.emplace(index_subspace, std::move(info));
532  }
533 
544  index_subspace_map_.emplace(info.index_subspace, info);
545  }
546 
554  std::map<size_t, index_subspace_info_t> & index_subspace_info() {
555  return index_subspace_map_;
556  }
557 
558  /*--------------------------------------------------------------------------*
559  Task Launch iterface.
560  *--------------------------------------------------------------------------*/
561 
566  size_t const & tasks_executed() const {
567  return tasks_executed_;
568  } // tasks_executed
569 
574  size_t & tasks_executed() {
575  return tasks_executed_;
576  } // tasks_executed
577 
578 protected:
579  context() = default;
580  // Invoke initialization callbacks.
581  // Call from hiding function in derived classses.
582  void start() {
583  for(auto ro : init_registry)
584  ro();
585  }
586 
587 #ifdef DOXYGEN
588  /*
589  Clear the runtime state of the context.
590 
591  Notes:
592  - This does not clear objects that cannot be serialized, e.g.,
593  std::function objects.
594  */
595 
596  void clear();
597 #endif
598 
599  /*--------------------------------------------------------------------------*
600  Program options data members.
601  *--------------------------------------------------------------------------*/
602 
603  std::string program_;
604  std::vector<char *> argv_;
605  std::string backend_;
606 
607  std::string flog_tags_;
608  int flog_verbose_;
609  int64_t flog_output_process_;
610 
611  bool initialize_dependent_ = true;
612 
613  // Option Descriptions
614  std::map<std::string, boost::program_options::options_description>
615  descriptions_map_;
616 
617  // Positional options
618  boost::program_options::positional_options_description positional_desc_;
619  boost::program_options::options_description hidden_options_;
620  std::map<std::string, std::string> positional_help_;
621 
622  // Validation functions
623  std::map<std::string,
624  std::pair<bool, std::function<bool(boost::any const &)>>>
625  option_checks_;
626 
627  std::vector<std::string> unrecognized_options_;
628 
629  /*--------------------------------------------------------------------------*
630  Basic runtime data members.
631  *--------------------------------------------------------------------------*/
632 
633  bool initialized_ = false;
634  size_t process_ = std::numeric_limits<size_t>::max();
635  size_t processes_ = std::numeric_limits<size_t>::max();
636  size_t threads_per_process_ = std::numeric_limits<size_t>::max();
637  size_t threads_ = std::numeric_limits<size_t>::max();
638 
639  int exit_status_ = 0;
640 
641  /*--------------------------------------------------------------------------*
642  Function data members.
643  *--------------------------------------------------------------------------*/
644 
645  std::unordered_map<size_t, void *> function_registry_;
646 
647  /*--------------------------------------------------------------------------*
648  Topology data members.
649  *--------------------------------------------------------------------------*/
650 
651  std::set<std::pair<size_t, size_t>> registered_topology_fields_;
652 
653  /*--------------------------------------------------------------------------*
654  Field data members.
655  *--------------------------------------------------------------------------*/
656 
657  /*
658  This type allows storage of runtime field information per topology type.
659  The size_t key is the topology ID; the vector index is the index space.
660  */
661 
662  std::unordered_map<size_t, std::vector<field_info_store_t>>
663  topology_field_info_map_;
664 
665  /*
666  This type allows storage of runtime index subspace information.
667  The size_t key is the index subspace identifier.
668  */
669 
670  std::map<size_t, index_subspace_info_t> index_subspace_map_;
671 
672  /*--------------------------------------------------------------------------*
673  Task count.
674  *--------------------------------------------------------------------------*/
675 
676  size_t tasks_executed_ = 0;
677 
678 private:
679  std::vector<void (*)()> init_registry;
680 }; // struct context
681 
682 } // namespace run
683 } // namespace flecsi
Definition: field_info.hh:36
std::size_t color() const
std::string const & program()
Definition: execution.hh:276
std::map< size_t, index_subspace_info_t > & index_subspace_info()
Definition: context.hh:554
std::size_t threads_per_process() const
void add_field_info(const data::field_info_t &field_info)
Definition: context.hh:487
std::size_t threads() const
#define flog_assert(test, message)
Definition: flog.hh:411
void add_index_subspace(size_t index_subspace, size_t capacity)
Definition: context.hh:526
size_t const & tasks_executed() const
Definition: context.hh:566
int start(const std::function< int()> &action)
Definition: execution.hh:69
void add_index_subspace(const index_subspace_info_t &info)
Definition: context.hh:543
static flog_t & instance()
Definition: state.hh:73
std::size_t colors() const
int initialize(int argc, char **argv, bool dependent=true)
Definition: execution.hh:55
field_info_store_t const & get_field_info_store() const
Definition: context.hh:503
void finalize()
Definition: execution.hh:80
int & exit_status()
Definition: context.hh:448
Definition: context.hh:64
size_t & tasks_executed()
Definition: context.hh:574
std::size_t processes() const
bool topology_fields_registered(size_t type_key, size_t instance_key)
Definition: context.hh:469
Definition: context.hh:63
static std::size_t task_depth()
const std::unordered_map< std::string, size_t > & tag_map()
Definition: state.hh:193
Definition: control.hh:31
std::size_t process() const