A library for working with phylogenetic and population genetic data.
v0.32.0
options.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_CORE_OPTIONS_H_
2 #define GENESIS_UTILS_CORE_OPTIONS_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2024 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lucas.czech@sund.ku.dk>
23  University of Copenhagen, Globe Institute, Section for GeoGenetics
24  Oster Voldgade 5-7, 1350 Copenhagen K, Denmark
25 */
26 
36 
37 #include <atomic>
38 #include <cassert>
39 #include <chrono>
40 #include <memory>
41 #include <random>
42 #include <stdexcept>
43 #include <string>
44 #include <utility>
45 #include <vector>
46 
47 namespace genesis {
48 namespace utils {
49 
50 // =================================================================================================
51 // Options
52 // =================================================================================================
53 
57 class Options
58 {
59 public:
60 
61  // -------------------------------------------------------------------------
62  // Instance
63  // -------------------------------------------------------------------------
64 
68  inline static Options& get()
69  {
70  // Meyers-Singleton
71  static Options instance;
72  return instance;
73  }
74 
75  // -------------------------------------------------------------------------
76  // Command Line
77  // -------------------------------------------------------------------------
78 
82  inline std::vector<std::string> const& command_line() const
83  {
84  return command_line_;
85  }
86 
90  std::string command_line_string() const
91  {
92  std::string ret = "";
93  for (size_t i = 0; i < command_line_.size(); ++i) {
94  std::string a = command_line_[i];
95  ret += (i==0 ? "" : " ") + a;
96  }
97  return ret;
98  }
99 
106  void command_line( int const argc, char const* const* argv )
107  {
108  // Store all arguments in the array.
109  command_line_.clear();
110  for (int i = 0; i < argc; i++) {
111  command_line_.push_back(argv[i]);
112  }
113  }
114 
115  // -------------------------------------------------------------------------
116  // Random Seed & Engine
117  // -------------------------------------------------------------------------
118 
124  inline unsigned long random_seed() const
125  {
126  return random_seed_;
127  }
128 
147  inline void random_seed( unsigned long const seed )
148  {
149  if( thread_pool_ ) {
150  throw std::domain_error(
151  "Cannot re-seed global random engine after having spawned the global thread pool, "
152  "as the threads would not be aware of the re-seeding. "
153  "Call Options::get().random_seed() before Options::get().init_global_thread_pool() "
154  "to fix this."
155  );
156  }
157  random_seed_ = seed;
158  thread_local_random_engine_().seed( seed );
159  }
160 
168  inline std::default_random_engine& random_engine()
169  {
170  return thread_local_random_engine_();
171  }
172 
178  inline size_t seed_counter() const
179  {
180  return seed_counter_.load();
181  }
182 
183 private:
184 
185  inline unsigned long generate_thread_seed_()
186  {
187  return random_seed_ + seed_counter_.fetch_add( 1, std::memory_order_relaxed );
188  }
189 
190  inline std::default_random_engine& thread_local_random_engine_()
191  {
192  // Private method to access the thread-local engine
193  thread_local std::default_random_engine engine( generate_thread_seed_() );
194  return engine;
195  }
196 
197 public:
198 
199  // -------------------------------------------------------------------------
200  // Global Thread Pool
201  // -------------------------------------------------------------------------
202 
216  {
217  // Automatic guessing of the correct number of threads.
218  // We then reduce it by one to account for the main thread doing work as well.
219  auto const num_threads = guess_number_of_threads();
220  assert( num_threads > 0 );
221  if( num_threads == 0 ) {
223  } else {
224  init_global_thread_pool( num_threads - 1 );
225  }
226  }
227 
244  void init_global_thread_pool( size_t num_threads, size_t max_queue_size = 0 )
245  {
246  if( thread_pool_ ) {
247  throw std::runtime_error(
248  "Global thread pool has already been initialized. "
249  "Cannot call Options::get().init_global_thread_pool() multiple times."
250  );
251  }
252  thread_pool_ = std::make_shared<utils::ThreadPool>( num_threads, max_queue_size );
253  }
254 
268  std::shared_ptr<ThreadPool> global_thread_pool() const
269  {
270  if( ! thread_pool_ ) {
271  throw std::runtime_error(
272  "Global thread pool has not been initialized. "
273  "Call Options::get().init_global_thread_pool() first."
274  );
275  }
276  return thread_pool_;
277  }
278 
284  size_t global_thread_pool_size() const
285  {
286  if( ! thread_pool_ ) {
287  return 1;
288  }
289  return thread_pool_->size() + 1;
290  }
291 
292  // -------------------------------------------------------------------------
293  // Input Reader Threads
294  // -------------------------------------------------------------------------
295 
300  {
309  kStrict,
310 
322 
331  kAllAsync
332  };
333 
338  {
339  input_reading_thread_policy_ = policy;
340  }
341 
346  {
347  return input_reading_thread_policy_;
348  }
349 
350  // -------------------------------------------------------------------------
351  // File Output
352  // -------------------------------------------------------------------------
353 
359  inline bool allow_file_overwriting() const
360  {
361  return allow_file_overwriting_;
362  }
363 
377  inline void allow_file_overwriting( bool value )
378  {
379  allow_file_overwriting_ = value;
380  }
381 
382  // -------------------------------------------------------------------------
383  // Data Members
384  // -------------------------------------------------------------------------
385 
386 private:
387 
388  // CLI
389  std::vector<std::string> command_line_;
390 
391  // Random engine seeding
392  unsigned long random_seed_;
393  std::atomic<size_t> seed_counter_{0};
394 
395  // Global thread pool
396  std::shared_ptr<ThreadPool> thread_pool_;
398 
399  // File handling
400  bool allow_file_overwriting_ = false;
401 
402  // -------------------------------------------------------------------------
403  // Hidden Class Members
404  // -------------------------------------------------------------------------
405 
406 private:
407 
408  // Everything private, as it is a singleton.
409 
413  Options()
414  {
415  // Initialize random seed with time.
416  random_seed( std::chrono::system_clock::now().time_since_epoch().count() );
417  }
418 
419  ~Options() = default;
420 
421  Options( const Options& ) = delete;
422  Options( Options&& ) = delete;
423  Options& operator= ( const Options& ) = delete;
424  Options& operator= ( Options&& ) = delete;
425 
426 };
427 
428 } // namespace utils
429 } // namespace genesis
430 
431 #endif // include guard
genesis::utils::Options::allow_file_overwriting
void allow_file_overwriting(bool value)
Set whether Genesis is allowed to overwrite files when outputting data.
Definition: options.hpp:377
genesis::utils::Options::init_global_thread_pool
void init_global_thread_pool(size_t num_threads, size_t max_queue_size=0)
Initialize the global thread pool to be used for parallel computations.
Definition: options.hpp:244
genesis::utils::Options::command_line
void command_line(int const argc, char const *const *argv)
Set arguments to the program's command line options.
Definition: options.hpp:106
genesis::utils::guess_number_of_threads
size_t guess_number_of_threads(bool use_openmp, bool use_slurm, bool physical_cores)
Make an educated guess on the number of threads to use for multi-threaded functionality.
Definition: info.cpp:1078
genesis::utils::Options::random_seed
unsigned long random_seed() const
Returns the random seed that was used to initialize the engine.
Definition: options.hpp:124
genesis::utils::Options::InputReadingThreadPolicy
InputReadingThreadPolicy
Decide how to use threads for input reading.
Definition: options.hpp:299
genesis::utils::Options::global_thread_pool
std::shared_ptr< ThreadPool > global_thread_pool() const
Return a global thread pool to be used for parallel computations.
Definition: options.hpp:268
genesis::utils::Options::command_line
std::vector< std::string > const & command_line() const
Returns an array of strings containing the program's command line arguments.
Definition: options.hpp:82
genesis::utils::Options::input_reading_thread_policy
void input_reading_thread_policy(InputReadingThreadPolicy policy)
Set the policy for the threading of input source reading.
Definition: options.hpp:337
genesis::utils::Options::seed_counter
size_t seed_counter() const
Return the number of seeds used to initialize thread-local random engines.
Definition: options.hpp:178
genesis::utils::Options::command_line_string
std::string command_line_string() const
Returns a string containing the program's command line arguments.
Definition: options.hpp:90
info.hpp
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::Options
Simple Options class for application-wide configuration and settings.
Definition: options.hpp:57
genesis::utils::Options::InputReadingThreadPolicy::kAllAsync
@ kAllAsync
All reading from input sources gets their own thread.
genesis::utils::Options::global_thread_pool_size
size_t global_thread_pool_size() const
Get the number of threads allocatd in the pool, plus one for the main thread.
Definition: options.hpp:284
genesis::utils::Options::random_engine
std::default_random_engine & random_engine()
Return a thread-local engine for random number generation.
Definition: options.hpp:168
genesis::utils::Options::init_global_thread_pool
void init_global_thread_pool()
Initialize the global thread pool to be used for parallel computations.
Definition: options.hpp:215
genesis::utils::Options::input_reading_thread_policy
InputReadingThreadPolicy input_reading_thread_policy()
Get the policy for the threading of input source reading.
Definition: options.hpp:345
genesis::utils::Options::InputReadingThreadPolicy::kTrivialAsync
@ kTrivialAsync
Use async threads for trivial input sources, such as simple files, but use the global thread pool for...
genesis::utils::Options::InputReadingThreadPolicy::kStrict
@ kStrict
All input reading uses the global thread pool.
genesis::utils::Options::get
static Options & get()
Returns a single instance of this class.
Definition: options.hpp:68
thread_pool.hpp
genesis::utils::Options::allow_file_overwriting
bool allow_file_overwriting() const
Get whether Genesis is allowed to overwrite files when outputting data.
Definition: options.hpp:359
genesis::utils::Options::random_seed
void random_seed(unsigned long const seed)
Set a specific global seed for the random engine initialization.
Definition: options.hpp:147