A library for working with phylogenetic and population genetic data.
v0.27.0
options.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2022 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lczech@carnegiescience.edu>
20  Department of Plant Biology, Carnegie Institution For Science
21  260 Panama Street, Stanford, CA 94305, USA
22 */
23 
32 
34 
35 #include <cassert>
36 #include <chrono>
37 #include <cstdint>
38 #include <cstdio>
39 
40 #if defined( _WIN32 ) || defined( _WIN64 )
41 # include <io.h>
42 # include <windows.h>
43 #else
44 #ifndef __aarch64__
45 # include <cpuid.h>
46 #endif
47 # include <stdio.h>
48 # include <sys/ioctl.h>
49 # include <unistd.h>
50 #endif
51 
52 #ifdef GENESIS_OPENMP
53 # include <omp.h>
54 #endif
55 
56 #ifdef GENESIS_PTHREADS
57 # include <thread>
58 #endif
59 
60 namespace genesis {
61 namespace utils {
62 
63 // =================================================================================================
64 // Initialization
65 // =================================================================================================
66 
67 #if defined( DEBUG ) && defined( NDEBUG )
68  static_assert( false, "Cannot compile with both DEBUG and NDEBUG flags set." );
69 #endif
70 
71 #if ! defined( DEBUG ) && ! defined( NDEBUG )
72  static_assert( false, "Cannot compile with neiher DEBUG nor NDEBUG flag set." );
73 #endif
74 
75 Options::Options()
76 {
77  // Initialize number of threads to hardware cores.
79 
80  // Initialize random seed with time.
81  random_seed( std::chrono::system_clock::now().time_since_epoch().count() );
82 }
83 
84 // =================================================================================================
85 // Command Line
86 // =================================================================================================
87 
88 std::string Options::command_line_string () const
89 {
90  std::string ret = "";
91  for (size_t i = 0; i < command_line_.size(); ++i) {
92  std::string a = command_line_[i];
93  ret += (i==0 ? "" : " ") + a;
94  }
95  return ret;
96 }
97 
98 void Options::command_line( int const argc, char const* const* argv )
99 {
100  // Store all arguments in the array.
101  command_line_.clear();
102  for (int i = 0; i < argc; i++) {
103  command_line_.push_back(argv[i]);
104  }
105 }
106 
107 // =================================================================================================
108 // Number of Threads
109 // =================================================================================================
110 
111 void Options::number_of_threads( unsigned int number )
112 {
113  if( number == 0 ) {
114  #ifdef GENESIS_PTHREADS
115  number = std::thread::hardware_concurrency();
116  if( number == 0 ) {
117  number = 1;
118  }
119  #else
120  number = 1;
121  #endif
122  }
123  number_of_threads_ = number;
124 
125  #if defined( GENESIS_OPENMP )
126 
127  // If we use OpenMp, set the thread number there, too.
128  omp_set_num_threads( number );
129 
130  #endif
131 }
132 
134 {
135  // Get CPU info.
136  int32_t info[4];
137  #ifdef __aarch64__
138  (void)info;
139  return false;
140  #elif defined( _WIN32 )
141  __cpuid( info, 1 );
142  #else
143  __cpuid_count( 1, 0, info[0], info[1], info[2], info[3] );
144  #endif
145 
146  return (bool) (info[3] & (0x1 << 28));
147 }
148 
149 unsigned int Options::guess_number_of_threads( bool use_openmp ) const
150 {
151  // Dummy to avoid compiler warnings.
152  (void) use_openmp;
153 
154  // Default to single threaded.
155  unsigned int guess = 1;
156 
157  #if defined( GENESIS_OPENMP )
158 
159  // Use number of OpenMP threads, which might be set through the
160  // `OMP_NUM_THREADS` environment variable.
161  // If there was an error there, fix it.
162  if( use_openmp ) {
163  guess = omp_get_max_threads();
164  }
165  if( guess == 0 ) {
166  guess = 1;
167  }
168 
169  #endif
170 
171  #if defined( GENESIS_PTHREADS )
172 
173  // Initialize threads with actual number of cores.
174  auto const lcores = std::thread::hardware_concurrency();
175 
176  // If hardware concurrency and openmp agree that there is more than one core,
177  // this means that OMP_NUM_THREADS was not set to anything specific, and hence we want
178  // to use all cores. However, in that case, we need to correct for hypterthreading.
179  // Also, if guess == 1 here, openmp was not used above, so in that case we also use
180  // the hardware concurrency as the guess.
181  if((( lcores == guess ) || ( guess == 1 )) && ( lcores > 1 )) {
182  auto const threads_per_core = hyperthreads_enabled() ? 2 : 1;
183  guess = lcores / threads_per_core;
184  }
185 
186  #endif
187 
188  assert( guess >= 1 );
189  return guess;
190 }
191 
192 // =================================================================================================
193 // Random Seed & Engine
194 // =================================================================================================
195 
196 void Options::random_seed(const unsigned long seed)
197 {
198  random_seed_ = seed;
199  random_engine_.seed( seed );
200 }
201 
202 // =================================================================================================
203 // Run Time Environment
204 // =================================================================================================
205 
207 {
208  // Using http://stackoverflow.com/a/1312957/4184258
209  #if defined( _WIN32 ) || defined( _WIN64 )
210  return _isatty( _fileno( stdin ));
211  #else
212  return isatty( fileno( stdin ));
213  #endif
214 }
215 
217 {
218  #if defined( _WIN32 ) || defined( _WIN64 )
219  return _isatty( _fileno( stdout ));
220  #else
221  return isatty( fileno( stdout ));
222  #endif
223 }
224 
226 {
227  #if defined( _WIN32 ) || defined( _WIN64 )
228  return _isatty( _fileno( stderr ));
229  #else
230  return isatty( fileno( stderr ));
231  #endif
232 }
233 
234 std::pair<int, int> Options::terminal_size()
235 {
236  #if defined( _WIN32 ) || defined( _WIN64 )
237 
238  CONSOLE_SCREEN_BUFFER_INFO csbi;
239  int cols, rows;
240  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
241  cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
242  rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
243  return { cols, rows };
244 
245  #else
246 
247  struct winsize w;
248  ioctl( STDOUT_FILENO, TIOCGWINSZ, &w );
249  return { w.ws_col, w.ws_row };
250 
251  #endif
252 }
253 
254 // =================================================================================================
255 // Compile Time Environment
256 // =================================================================================================
257 
259 {
260  #ifdef DEBUG
261  return true;
262  #else
263  return false;
264  #endif
265 }
266 
268 {
269  #ifdef NDEBUG
270  return true;
271  #else
272  return false;
273  #endif
274 }
275 
276 std::string Options::build_type()
277 {
278  #if defined( DEBUG )
279  return "debug";
280  #elif defined( NDEBUG )
281  return "release";
282  #else
283  return "unknown";
284  #endif
285 }
286 
288 {
289  static const uint16_t e = 0x1000;
290  return 0 == *reinterpret_cast< uint8_t const* >( &e );
291 }
292 
294 {
295  static const uint16_t e = 0x0001;
296  return 0 == *reinterpret_cast< uint8_t const* >( &e );
297 }
298 
299 std::string Options::platform()
300 {
301  #if defined _WIN64
302  return "Win64";
303  #elif defined _WIN32
304  return "Win32";
305  #elif defined __linux__
306  return "Linux";
307  #elif defined __APPLE__
308  return "Apple";
309  #elif defined __unix__
310  return "Unix";
311  #else
312  return "Unknown";
313  #endif
314 }
315 
317 {
318  #if defined(__clang__)
319  return "clang";
320  #elif defined(__ICC) || defined(__INTEL_COMPILER)
321  return "icc";
322  #elif defined(__GNUC__) || defined(__GNUG__)
323  return "gcc";
324  #elif defined(__HP_cc) || defined(__HP_aCC)
325  return "hp";
326  #elif defined(__IBMCPP__)
327  return "ilecpp";
328  #elif defined(_MSC_VER)
329  return "msvc";
330  #elif defined(__PGI)
331  return "pgcpp";
332  #elif defined(__SUNPRO_CC)
333  return "sunpro";
334  #else
335  return "unknown";
336  #endif
337 }
338 
340 {
341  #if defined(__clang__)
342  return __clang_version__;
343  #elif defined(__ICC) || defined(__INTEL_COMPILER)
344  return __INTEL_COMPILER;
345  #elif defined(__GNUC__) || defined(__GNUG__)
346  return std::to_string(__GNUC__) + "." +
347  std::to_string(__GNUC_MINOR__) + "." +
348  std::to_string(__GNUC_PATCHLEVEL__)
349  ;
350  #elif defined(__HP_cc) || defined(__HP_aCC)
351  return "";
352  #elif defined(__IBMCPP__)
353  return __IBMCPP__;
354  #elif defined(_MSC_VER)
355  return _MSC_VER;
356  #elif defined(__PGI)
357  return __PGI;
358  #elif defined(__SUNPRO_CC)
359  return __SUNPRO_CC;
360  #else
361  return "unknown";
362  #endif
363 }
364 
365 std::string Options::cpp_version()
366 {
367  #ifdef __cplusplus
368  return std::to_string(__cplusplus);
369  #else
370  return "unknown";
371  #endif
372 }
373 
375 {
376  return std::string( __DATE__ " " __TIME__ );
377 }
378 
380 {
381  #ifdef GENESIS_PTHREADS
382  return true;
383  #else
384  return false;
385  #endif
386 }
387 
389 {
390  #ifdef GENESIS_OPENMP
391  return true;
392  #else
393  return false;
394  #endif
395 }
396 
398 {
399  #ifdef GENESIS_ZLIB
400  return true;
401  #else
402  return false;
403  #endif
404 }
405 
406 // =================================================================================================
407 // Dump & Overview
408 // =================================================================================================
409 
410 std::string Options::info() const
411 {
412  std::string res;
413  res += genesis_header() + "\n";
414  res += info_compile_time() + "\n";
415  res += info_run_time() + "\n";
416  return res;
417 }
418 
419 std::string Options::info_compile_time() const
420 {
421  std::string res;
422  res += "Compile Time Options\n";
423  res += "=============================================\n\n";
424  res += "Platform: " + platform() + "\n";
425  res += "Compiler: " + compiler_family() + " " + compiler_version() + "\n";
426  res += "C++ version: " + cpp_version() + "\n";
427  res += "Build type: " + build_type() + "\n";
428  res += "Endianness: " + std::string( is_little_endian() ? "little endian" : "big endian" ) + "\n";
429  res += "Using Pthreads: " + std::string( using_pthreads() ? "true" : "false" ) + "\n";
430  res += "Using OpenMP: " + std::string( using_openmp() ? "true" : "false" ) + "\n";
431  return res;
432 }
433 
434 std::string Options::info_run_time() const
435 {
436  std::string res;
437  res += "Run Time Options\n";
438  res += "=============================================\n\n";
439  auto const cli_str = command_line_string();
440  res += "Command line: " + ( cli_str.size() > 0 ? cli_str : "(not available)" ) + "\n";
441  res += "Number of threads: " + std::to_string( number_of_threads() ) + "\n";
442  res += "Random seed: " + std::to_string( random_seed_ ) + "\n";
443  return res;
444 }
445 
446 } // namespace utils
447 } // namespace genesis
genesis::utils::Options::info
std::string info() const
Return a list with compile time and run time options with their values.
Definition: options.cpp:410
genesis::utils::Options::compiler_version
static std::string compiler_version()
Return the compiler version that was used to compile genesis.
Definition: options.cpp:339
genesis::utils::Options::info_run_time
std::string info_run_time() const
Return a list of run time options.
Definition: options.cpp:434
genesis::utils::Options::random_seed
unsigned long random_seed() const
Returns the random seed that was used to initialize the engine.
Definition: options.hpp:134
genesis::utils::Options::platform
static std::string platform()
Return the platform under which genesis was compiled.
Definition: options.cpp:299
genesis::utils::Options::guess_number_of_threads
unsigned int guess_number_of_threads(bool use_openmp=true) const
Try to guess the number of hardware threads of the current system.
Definition: options.cpp:149
genesis::utils::Options::command_line
std::vector< std::string > command_line() const
Returns an array of strings containing the program's command line arguments.
Definition: options.hpp:73
genesis::utils::Options::is_debug
static bool is_debug()
Return whether the binary was compiled with build type DEBUG.
Definition: options.cpp:258
genesis::utils::Options::info_compile_time
std::string info_compile_time() const
Return a list of compile time options.
Definition: options.cpp:419
version.hpp
Some stuff that is totally not imporatant, but nice.
genesis::utils::Options::stderr_is_terminal
static bool stderr_is_terminal()
Return true iff the standard error stream is a terminal, and false if not, i.e., if it is a file or a...
Definition: options.cpp:225
genesis::utils::Options::terminal_size
static std::pair< int, int > terminal_size()
Return the width and height of the terminal that is used to run the program, in number of columns and...
Definition: options.cpp:234
genesis::utils::Options::stdout_is_terminal
static bool stdout_is_terminal()
Return true iff the standard output stream is a terminal, and false if not, i.e., if it is a file or ...
Definition: options.cpp:216
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: functions/genome_locus.hpp:48
genesis::utils::Options::compile_date_time
static std::string compile_date_time()
Return the date and time when genesis was compiled.
Definition: options.cpp:374
genesis::utils::Options::hyperthreads_enabled
bool hyperthreads_enabled() const
Try to get whether hyperthreads are enabled in the current system.
Definition: options.cpp:133
genesis::utils::Options::compiler_family
static std::string compiler_family()
Return the compiler family (name) that was used to compile genesis.
Definition: options.cpp:316
genesis::utils::Options::using_openmp
static bool using_openmp()
Return whether the binary was compiled using OpenMP.
Definition: options.cpp:388
genesis::utils::Options::command_line_string
std::string command_line_string() const
Returns a string containing the program's command line arguments.
Definition: options.cpp:88
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::stdin_is_terminal
static bool stdin_is_terminal()
Return true iff the standard input stream is a terminal, and false if not, i.e., if it is a file or a...
Definition: options.cpp:206
genesis::utils::Options::number_of_threads
unsigned int number_of_threads() const
Returns the number of threads.
Definition: options.hpp:98
options.hpp
genesis::utils::Options::is_release
static bool is_release()
Return whether the binary was compiled with build type RELEASE.
Definition: options.cpp:267
genesis::genesis_header
std::string genesis_header()
Return the header for genesis.
Definition: version.hpp:94
genesis::utils::Options::is_little_endian
static bool is_little_endian()
Return whether the system uses little endian memory.
Definition: options.cpp:287
genesis::utils::Options::using_pthreads
static bool using_pthreads()
Return whether the binary was compiled using Pthreads.
Definition: options.cpp:379
genesis::utils::Options::build_type
static std::string build_type()
Return the build type that was used to compile the binary, i.e., "debug" or "release".
Definition: options.cpp:276
genesis::utils::Options::is_big_endian
static bool is_big_endian()
Return whether the system uses big endian memory.
Definition: options.cpp:293
genesis::utils::Options::cpp_version
static std::string cpp_version()
Return the CPP version that was used to compile genesis.
Definition: options.cpp:365
genesis::utils::Options::using_zlib
static bool using_zlib()
Return whether the binary was compiled using zlib.
Definition: options.cpp:397