A library for working with phylogenetic and population genetic data.
v0.32.0
info.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2024 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 <lucas.czech@sund.ku.dk>
20  University of Copenhagen, Globe Institute, Section for GeoGenetics
21  Oster Voldgade 5-7, 1350 Copenhagen K, Denmark
22 */
23 
24 /*
25  The implementation of the hardware feature detaction is based on FeatureDetector,
26  see https://github.com/Mysticial/FeatureDetector which is published under CC0 1.0 Universal.
27  We have adapted the code to be contained in the classes and functions here.
28 
29  For an alternative approach that seems to support Apple better,
30  see https://github.com/xflouris/libpll-2/blob/master/src/hardware.c
31  and https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
32 
33  For more hardware related information, see
34  https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
35  */
36 
45 
51 
52 #include <algorithm>
53 #include <cassert>
54 #include <cctype>
55 #include <chrono>
56 #include <climits>
57 #include <cstdarg>
58 #include <cstdint>
59 #include <cstdio>
60 #include <cstdlib>
61 #include <cstring>
62 #include <fstream>
63 #include <iomanip>
64 #include <iostream>
65 #include <sstream>
66 #include <stdexcept>
67 #include <string>
68 #include <thread>
69 #include <unordered_set>
70 #include <vector>
71 
72 #include <errno.h>
73 #include <stdio.h>
74 
75 // These potentially need to be adopted for Windows.
76 // Untested, will deal with Windows later. Or never.
77 #include <sys/resource.h>
78 #include <sys/stat.h>
79 #include <sys/time.h>
80 #include <sys/types.h>
81 #include <unistd.h>
82 
83 // -----------------------------------------------------------------------------
84 // OS Specific Includes
85 // -----------------------------------------------------------------------------
86 
87 #if defined( __APPLE__ )
88 # include <sys/sysctl.h>
89 #endif
90 
91 #if defined(__linux__)
92 # include <sched.h>
93 #endif
94 
95 // For processor features and other intrinsics
96 #if defined( _WIN32 ) || defined( _WIN64 )|| defined( _MSC_VER )
97 # include <io.h>
98 # include <intrin.h>
99 # include <windows.h>
100 #elif defined( __GNUC__ ) || defined( __clang__ )
101 # ifndef __aarch64__
102  // Both GCC and LLVM are missing the header guard for this header up until recent versions,
103  // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96238 and https://reviews.llvm.org/D91226
104  // So we guard on our own here, which matters when genesis is compiled in a single unit.
105 # ifndef GENESIS_INCLUDED_CPUID_H_
106 # define GENESIS_INCLUDED_CPUID_H_
107 # include <cpuid.h>
108 # endif
109 # endif
110 # include <stdio.h>
111 # include <sys/ioctl.h>
112 # include <sys/types.h>
113 # include <unistd.h>
114 #else
115 // # warning "No cpuid intrinsic defined for compiler."
116 #endif
117 
118 #if !(defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86))
119 // # warning "No cpuid intrinsic defined for processor architecture."
120 #endif
121 
122 // For current usage
123 #if defined( _WIN32 ) || defined( _WIN64 )|| defined( _MSC_VER )
124 # include <TCHAR.h>
125 # include <pdh.h>
126 # include <psapi.h>
127 # include <windows.h>
128 #elif defined( __APPLE__ )
129 # include <mach/mach_error.h>
130 # include <mach/mach_host.h>
131 # include <mach/mach_init.h>
132 # include <mach/mach_types.h>
133 # include <mach/mach.h>
134 # include <mach/task_info.h>
135 # include <mach/vm_map.h>
136 # include <mach/vm_statistics.h>
137 # include <sys/resource.h>
138 # include <sys/time.h>
139 # include <sys/types.h>
140 // # include <sys/sysinfo.h>
141 #elif defined( __GNUC__ ) || defined( __clang__ ) || defined(__linux__)
142 # include <sys/types.h>
143 # include <sys/sysinfo.h>
144 # include <stdlib.h>
145 # include <stdio.h>
146 # include <string.h>
147 # include <sys/times.h>
148 // # include <sys/vtimes.h>
149 #endif
150 
151 #ifdef GENESIS_OPENMP
152 # include <omp.h>
153 #endif
154 
155 namespace genesis {
156 namespace utils {
157 
158 // =================================================================================================
159 // Compiler Info
160 // =================================================================================================
161 
162 // Some static checking to make sure that our CMake setup is correct.
163 #if defined( DEBUG ) && defined( NDEBUG )
164  static_assert( false, "Cannot compile with both DEBUG and NDEBUG flags set." );
165 #endif
166 
167 #if ! defined( DEBUG ) && ! defined( NDEBUG )
168  static_assert( false, "Cannot compile with neiher DEBUG nor NDEBUG flag set." );
169 #endif
170 
172 {
173  // No need to repeat.
174  static InfoCompiler result;
175  static bool initialized = false;
176  if( initialized ) {
177  return result;
178  }
179 
180  // Compile date and time
181  result.compile_date_time = std::string( __DATE__ " " __TIME__ );
182 
183  // Build type
184  #ifdef DEBUG
185  result.is_debug = true;
186  #else
187  result.is_debug = false;
188  #endif
189  #ifdef NDEBUG
190  result.is_release = true;
191  #else
192  result.is_release = false;
193  #endif
194  #if defined( DEBUG )
195  result.build_type = "debug";
196  #elif defined( NDEBUG )
197  result.build_type = "release";
198  #else
199  result.build_type = "unknown";
200  #endif
201 
202  // Platform
203  #if defined _WIN64
204  result.platform = "Win64";
205  #elif defined _WIN32
206  result.platform = "Win32";
207  #elif defined __linux__
208  result.platform = "Linux";
209  #elif defined __APPLE__
210  result.platform = "Apple";
211  #elif defined __unix__
212  result.platform = "Unix";
213  #else
214  result.platform = "Unknown";
215  #endif
216 
217  // Compiler family
218  #if defined(__clang__)
219  result.compiler_family = "clang";
220  #elif defined(__ICC) || defined(__INTEL_COMPILER)
221  result.compiler_family = "icc";
222  #elif defined(__GNUC__) || defined(__GNUG__)
223  result.compiler_family = "gcc";
224  #elif defined(__HP_cc) || defined(__HP_aCC)
225  result.compiler_family = "hp";
226  #elif defined(__IBMCPP__)
227  result.compiler_family = "ilecpp";
228  #elif defined(_MSC_VER)
229  result.compiler_family = "msvc";
230  #elif defined(__PGI)
231  result.compiler_family = "pgcpp";
232  #elif defined(__SUNPRO_CC)
233  result.compiler_family = "sunpro";
234  #else
235  result.compiler_family = "unknown";
236  #endif
237 
238  // Compiler version
239  #if defined(__clang__)
240  result.compiler_version = __clang_version__;
241  #elif defined(__ICC) || defined(__INTEL_COMPILER)
242  result.compiler_version = __INTEL_COMPILER;
243  #elif defined(__GNUC__) || defined(__GNUG__)
244  result.compiler_version =
245  std::to_string(__GNUC__) + "." +
246  std::to_string(__GNUC_MINOR__) + "." +
247  std::to_string(__GNUC_PATCHLEVEL__)
248  ;
249  #elif defined(__HP_cc) || defined(__HP_aCC)
250  result.compiler_version = "";
251  #elif defined(__IBMCPP__)
252  result.compiler_version = __IBMCPP__;
253  #elif defined(_MSC_VER)
254  result.compiler_version = _MSC_VER;
255  #elif defined(__PGI)
256  result.compiler_version = __PGI;
257  #elif defined(__SUNPRO_CC)
258  result.compiler_version = __SUNPRO_CC;
259  #else
260  result.compiler_version = "unknown";
261  #endif
262 
263  // C++ version
264  #ifdef __cplusplus
265  result.cpp_version = std::to_string(__cplusplus);
266  #elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
267  result.cpp_version = std::to_string(_MSVC_LANG);
268  #else
269  result.cpp_version = "unknown";
270  #endif
271 
272  // OpenMP
273  #ifdef GENESIS_OPENMP
274  result.with_openmp = true;
275  #else
276  result.with_openmp = false;
277  #endif
278 
279  // AVX/AVX2
280  #ifdef GENESIS_AVX
281  result.with_avx = true;
282  #else
283  result.with_avx = false;
284  #endif
285  #ifdef GENESIS_AVX2
286  result.with_avx2 = true;
287  #else
288  result.with_avx2 = false;
289  #endif
290  result.with_avx512 = false;
291 
292  initialized = true;
293  return result;
294 }
295 
296 std::unordered_map<std::string,std::string> const& info_preprocessor_definitions()
297 {
298  // No need to repeat.
299  static std::unordered_map<std::string,std::string> result;
300  static bool initialized = false;
301  if( initialized ) {
302  return result;
303  }
304 
305  // Now check all the macros that we want. There is likely no way to make these one-lines,
306  // as having a preprocessor ifdef within a macro definition itself is not possible.
307  #ifdef __cplusplus
308  result.emplace( "__cplusplus", std::to_string( __cplusplus ));
309  #endif
310  #ifdef _MSVC_LANG
311  result.emplace( "_MSVC_LANG", std::to_string( _MSVC_LANG ));
312  #endif
313  #ifdef __GNUC__
314  result.emplace( "__GNUC__", std::to_string( __GNUC__ ));
315  #endif
316  #ifdef __clang__
317  result.emplace( "__clang__", std::to_string( __clang__ ));
318  #endif
319  #ifdef _MSC_VER
320  result.emplace( "_MSC_VER", std::to_string( _MSC_VER ));
321  #endif
322  #ifdef __APPLE__
323  result.emplace( "__APPLE__", std::to_string( __APPLE__ ));
324  #endif
325  #ifdef __linux__
326  result.emplace( "__linux__", std::to_string( __linux__ ));
327  #endif
328  #ifdef __unix__
329  result.emplace( "__unix__", std::to_string( __unix__ ));
330  #endif
331  #ifdef _WIN32
332  result.emplace( "_WIN32", std::to_string( _WIN32 ));
333  #endif
334  #ifdef _WIN64
335  result.emplace( "_WIN64", std::to_string( _WIN64 ));
336  #endif
337  #ifdef __x86_64__
338  result.emplace( "__x86_64__", std::to_string( __x86_64__ ));
339  #endif
340  #ifdef _M_X64
341  result.emplace( "_M_X64", std::to_string( _M_X64 ));
342  #endif
343  #ifdef __i386
344  result.emplace( "__i386", std::to_string( __i386 ));
345  #endif
346  #ifdef _M_IX86
347  result.emplace( "_M_IX86", std::to_string( _M_IX86 ));
348  #endif
349  #ifdef __ARM_ARCH
350  result.emplace( "__ARM_ARCH", std::to_string( __ARM_ARCH ));
351  #endif
352  #ifdef __arm__
353  result.emplace( "__arm__", std::to_string( __arm__ ));
354  #endif
355  #ifdef __aarch64__
356  result.emplace( "__aarch64__", std::to_string( __aarch64__ ));
357  #endif
358 
359  initialized = true;
360  return result;
361 }
362 
363 std::string info_print_compiler()
364 {
365  auto const& info_comp = info_get_compiler();
366 
367  std::string res;
368  res += "Compiler Information\n";
369  res += "=============================================\n\n";
370  res += "Platform = " + info_comp.platform + "\n";
371  res += "Compiler = " + info_comp.compiler_family + " " + info_comp.compiler_version + "\n";
372  res += "C++ version = " + info_comp.cpp_version + "\n";
373  res += "Build type = " + info_comp.build_type + "\n";
374  res += "With OpenMP = " + std::string( info_comp.with_openmp ? "true" : "false" ) + "\n";
375  res += "With AVX = " + std::string( info_comp.with_avx ? "true" : "false" ) + "\n";
376  res += "With AVX2 = " + std::string( info_comp.with_avx2 ? "true" : "false" ) + "\n";
377 
378  return res;
379 }
380 
381 // =================================================================================================
382 // Hardware Info
383 // =================================================================================================
384 
385 // -----------------------------------------------------------------------------
386 // OS Specific Helper Functions
387 // -----------------------------------------------------------------------------
388 
389 /*
390  The implementation of the hardware feature detaction is based on FeatureDetector,
391  see https://github.com/Mysticial/FeatureDetector which is published under CC0 1.0 Universal.
392  We have adapted the code to be contained in the classes and functions here.
393  */
394 
395 #if defined( _WIN32 ) || defined( _WIN64 )
396 
397  void get_cpuid_(int32_t out[4], int32_t eax, int32_t ecx)
398  {
399  __cpuidex(out, eax, ecx);
400  }
401 
402  __int64 xgetbv(unsigned int x)
403  {
404  return _xgetbv(x);
405  }
406 
407  // Detect 64-bit - Note that this snippet of code for detecting 64-bit has been copied from MSDN.
408  typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
409  BOOL IsWow64()
410  {
411  BOOL bIsWow64 = FALSE;
412 
413  LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
414  GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
415 
416  if (NULL != fnIsWow64Process)
417  {
418  if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
419  {
420  // printf("Error Detecting Operating System.\n");
421  // printf("Defaulting to 32-bit OS.\n\n");
422  bIsWow64 = FALSE;
423  }
424  }
425  return bIsWow64;
426  }
427 
428  bool detect_OS_x64_()
429  {
430  #ifdef _M_X64
431  return true;
432  #else
433  return IsWow64() != 0;
434  #endif
435  }
436 
437 #elif defined(__arm__) || defined(__aarch64__) || defined(__ARM_ARCH) // for M1/M2 chips
438 
439  void get_cpuid_( int32_t out[4], int32_t eax, int32_t ecx )
440  {
441  (void) eax;
442  (void) ecx;
443 
444  // On ARM, for instance MacOS with M1/M2 chips, we do not detect any features at the moment.
445  // That means we will just run vanilla code, but well, can't support everything.
446  // Those processors seem to not have much support for SIMD anyway.
447  out[0] = out[1] = out[2] = out[3] = 0;
448  }
449 
450  uint64_t xgetbv(unsigned int index)
451  {
452  (void) index;
453  return 0;
454  }
455 
456  bool detect_OS_x64_()
457  {
458  // https://stackoverflow.com/a/41666292/4184258
459  #ifdef __aarch64__
460  return true;
461  #else
462  return false;
463  #endif
464  }
465 
466 #else
467 
468  void get_cpuid_(int32_t out[4], int32_t eax, int32_t ecx)
469  {
470  __cpuid_count(eax, ecx, out[0], out[1], out[2], out[3]);
471  }
472 
473  // Alternatiave from https://gist.github.com/hi2p-perim/7855506
474  // void cpuid(int* cpuinfo, int info)
475  // {
476  // __asm__ __volatile__(
477  // "xchg %%ebx, %%edi;"
478  // "cpuid;"
479  // "xchg %%ebx, %%edi;"
480  // :"=a" (cpuinfo[0]), "=D" (cpuinfo[1]), "=c" (cpuinfo[2]), "=d" (cpuinfo[3])
481  // :"0" (info)
482  // );
483  // }
484 
485  uint64_t xgetbv(unsigned int index)
486  {
487  uint32_t eax, edx;
488  __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
489  return ((uint64_t)edx << 32) | eax;
490  }
491 
492  // Detect 64-bit
493  bool detect_OS_x64_() {
494  // We only support x64 on Linux.
495  return true;
496  }
497 
498 #endif
499 
500 #if defined(__linux__)
501 
502  static std::string get_cpu_info_linux_( std::string const& key )
503  {
504  std::string value = "(not found)";
505  std::ifstream fs("/proc/cpuinfo");
506  if( fs.good() ) {
507  std::string line;
508  while( !fs.eof() ) {
509  std::getline(fs, line, '\n');
510  if( strncmp(line.c_str(), key.c_str(), key.length()) == 0 ) {
511  size_t offset = key.length();
512  while(
513  ( isspace(line[offset]) || line[offset] == ':' ) &&
514  ( offset < line.length() )
515  ) {
516  ++offset;
517  }
518  value = line.c_str() + offset;
519  break;
520  }
521  }
522  }
523 
524  return value;
525  }
526 
527 #endif
528 
529 // -----------------------------------------------------------------------------
530 // OS Feature Helper Functions
531 // -----------------------------------------------------------------------------
532 
534 {
535  // Copied from: http://stackoverflow.com/a/22521619/922184
536  bool avxSupported = false;
537 
538  int32_t cpuInfo[4];
539  get_cpuid_(cpuInfo, 1, 0);
540 
541  bool osUsesXSAVE_XRSTORE = (cpuInfo[2] & (1 << 27)) != 0;
542  bool cpuAVXSuport = (cpuInfo[2] & (1 << 28)) != 0;
543 
544  if( osUsesXSAVE_XRSTORE && cpuAVXSuport ) {
545  auto const _XCR_XFEATURE_ENABLED_MASK = 0;
546  uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
547  avxSupported = (xcrFeatureMask & 0x6) == 0x6;
548  }
549 
550  return avxSupported;
551 }
552 
554 {
555  if( !detect_OS_AVX_() ) {
556  return false;
557  }
558 
559 auto const _XCR_XFEATURE_ENABLED_MASK = 0;
560  uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
561  return (xcrFeatureMask & 0xe6) == 0xe6;
562 }
563 
564 std::string get_vendor_string_()
565 {
566  int32_t CPUInfo[4];
567  char name[13];
568 
569  get_cpuid_(CPUInfo, 0, 0);
570  memcpy(name + 0, &CPUInfo[1], 4);
571  memcpy(name + 4, &CPUInfo[3], 4);
572  memcpy(name + 8, &CPUInfo[2], 4);
573  name[12] = '\0';
574 
575  return name;
576 }
577 
578 std::string get_cpu_model_()
579 {
580  std::string model = "unknown CPU model";
581  #if defined(__linux__)
582  model = get_cpu_info_linux_("model name");
583  #elif defined(__APPLE__)
584  char str[256];
585  size_t len = 256;
586  if( sysctlbyname( "machdep.cpu.brand_string", &str, &len, NULL, 0 ) == 0 ) {
587  model = str;
588  }
589  #endif
590  return model;
591 }
592 
593 #if defined(__linux__)
594 
595  size_t get_memtotal_linux_()
596  {
597  // Using http://stackoverflow.com/a/1312957/4184258
598  // And https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
599 
600  struct sysinfo memInfo;
601  if( sysinfo( &memInfo )) {
602  return 0;
603  }
604  return static_cast<size_t>( memInfo.totalram ) * static_cast<size_t>( memInfo.mem_unit );
605  }
606 
607 #endif
608 
610 {
611  // Adapted from https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
612  // which itself is seems to be adapted from vsearch.
613 
614  #if defined( _WIN32 ) || defined( _WIN64 )|| defined( _MSC_VER )
615 
616  MEMORYSTATUSEX memInfo;
617  memInfo.dwLength = sizeof(MEMORYSTATUSEX);
618  GlobalMemoryStatusEx(&memInfo);
619  return memInfo.ullTotalPhys;
620 
621  #elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGESIZE)
622 
623  long phys_pages = sysconf(_SC_PHYS_PAGES);
624  long pagesize = sysconf(_SC_PAGESIZE);
625 
626  if ((phys_pages == -1) || (pagesize == -1)) {
627  #if defined(__linux__)
628  return get_memtotal_linux_();
629  #else
630  return 0;
631  #endif
632  }
633 
634  // sysconf(3) notes that pagesize * phys_pages can overflow, such as when long is
635  // 32-bits and there's more than 4GB RAM. Since we target LP64 systems like
636  // x86_64 linux, this will not arise in practice on the intended platform.
637  if (pagesize > LONG_MAX / phys_pages) {
638  return LONG_MAX;
639  } else {
640  return static_cast<size_t>( pagesize ) * static_cast<size_t>( phys_pages );
641  }
642 
643  #elif defined(__APPLE__)
644 
645  int mib[] = { CTL_HW, HW_MEMSIZE };
646  int64_t ram = 0;
647  size_t length = sizeof(ram);
648  if (-1 == sysctl(mib, 2, &ram, &length, NULL, 0)) {
649  return 0;
650  }
651  return ram;
652 
653  #elif defined(__linux__)
654  // Generic solution
655  return get_memtotal_linux_();
656  #else
657  return 0;
658  #endif
659 }
660 
661 // -----------------------------------------------------------------------------
662 // info_get_hardware
663 // -----------------------------------------------------------------------------
664 
666 {
667  // No need to repeat.
668  static InfoHardware result;
669  static bool initialized = false;
670  if( initialized ) {
671  return result;
672  }
673 
674  // Endianness
675  static const uint16_t little_endian_test = 0x1000;
676  result.is_little_endian = ( 0 == *reinterpret_cast< uint8_t const* >( &little_endian_test ));
677  // static const uint16_t big_endian_test = 0x0001;
678  // result.is_little_endian = ( 0 == *reinterpret_cast< uint8_t const* >( &big_endian_test ));
679 
680  // Memory
681  result.total_memory = get_memtotal_();
682 
683  // ---------------------------------------------------------
684  // Vendor and OS
685  // ---------------------------------------------------------
686 
687  // Vendor
689  if( result.vendor_string == "GenuineIntel" ) {
690  result.vendor_Intel = true;
691  } else if( result.vendor_string == "AuthenticAMD" ) {
692  result.vendor_AMD = true;
693  }
694  result.cpu_model = get_cpu_model_();
697 
698  // OS Features
699  result.OS_x64 = detect_OS_x64_();
700  result.OS_AVX = detect_OS_AVX_();
701  result.OS_AVX512 = detect_OS_AVX512_();
702 
703  // ---------------------------------------------------------
704  // Detect Features
705  // ---------------------------------------------------------
706 
707  // Not used, but kept here for future reference if needed:
708  // Windows Visual Studio detect AVX: https://insufficientlycomplicated.wordpress.com/2011/11/07/detecting-intel-advanced-vector-extensions-avx-in-visual-studio/
709  // See also https://stackoverflow.com/a/28441544/4184258
710 
711  // Now run the feature detection
712 
713  int32_t info[4];
714  get_cpuid_( info, 0, 0 );
715  int nIds = info[0];
716 
717  get_cpuid_( info, 0x80000000, 0 );
718  uint32_t nExIds = info[0];
719 
720  if( nIds >= 0x00000001 ) {
721  get_cpuid_( info, 0x00000001, 0 );
722  result.HW_MMX = (info[3] & ((int)1 << 23)) != 0;
723  result.HW_SSE = (info[3] & ((int)1 << 25)) != 0;
724  result.HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
725  result.HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
726 
727  result.HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
728  result.HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
729  result.HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
730  result.HW_AES = (info[2] & ((int)1 << 25)) != 0;
731 
732  result.HW_AVX = (info[2] & ((int)1 << 28)) != 0;
733  result.HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
734 
735  result.HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
736  }
737  if( nIds >= 0x00000007 ) {
738  get_cpuid_( info, 0x00000007, 0 );
739  result.HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
740 
741  result.HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
742  result.HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
743  result.HW_ADX = (info[1] & ((int)1 << 19)) != 0;
744  result.HW_MPX = (info[1] & ((int)1 << 14)) != 0;
745  result.HW_SHA = (info[1] & ((int)1 << 29)) != 0;
746  result.HW_RDSEED = (info[1] & ((int)1 << 18)) != 0;
747  result.HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
748  result.HW_RDPID = (info[2] & ((int)1 << 22)) != 0;
749 
750  result.HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0;
751  result.HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0;
752  result.HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0;
753  result.HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0;
754 
755  result.HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0;
756  result.HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0;
757  result.HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0;
758 
759  result.HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0;
760  result.HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0;
761 
762  result.HW_AVX512_VPOPCNTDQ = (info[2] & ((int)1 << 14)) != 0;
763  result.HW_AVX512_4VNNIW = (info[3] & ((int)1 << 2)) != 0;
764  result.HW_AVX512_4FMAPS = (info[3] & ((int)1 << 3)) != 0;
765 
766  result.HW_AVX512_VNNI = (info[2] & ((int)1 << 11)) != 0;
767 
768  result.HW_AVX512_VBMI2 = (info[2] & ((int)1 << 6)) != 0;
769  result.HW_GFNI = (info[2] & ((int)1 << 8)) != 0;
770  result.HW_VAES = (info[2] & ((int)1 << 9)) != 0;
771  result.HW_AVX512_VPCLMUL = (info[2] & ((int)1 << 10)) != 0;
772  result.HW_AVX512_BITALG = (info[2] & ((int)1 << 12)) != 0;
773 
774  get_cpuid_( info, 0x00000007, 1 );
775  result.HW_AVX512_BF16 = (info[0] & ((int)1 << 5)) != 0;
776  }
777  if( nExIds >= 0x80000001 ) {
778  get_cpuid_( info, 0x80000001, 0 );
779  result.HW_x64 = (info[3] & ((int)1 << 29)) != 0;
780  result.HW_ABM = (info[2] & ((int)1 << 5)) != 0;
781  result.HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
782  result.HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
783  result.HW_XOP = (info[2] & ((int)1 << 11)) != 0;
784  result.HW_PREFETCHW = (info[2] & ((int)1 << 8)) != 0;
785  }
786 
787  initialized = true;
788  return result;
789 }
790 
791 // -----------------------------------------------------------------------------
792 // info_print_hardware
793 // -----------------------------------------------------------------------------
794 
795 std::string info_print_hardware( bool full )
796 {
797  auto const& info_hardware = info_get_hardware();
798 
799  std::stringstream ss;
800  auto print_ = [&]( char const* label, bool yes )
801  {
802  ss << label;
803  ss << (yes ? "true" : "false") << "\n";
804  };
805 
806  ss << "Hardware Features\n";
807  ss << "=============================================\n\n";
808 
809  ss << "Memory:" << "\n";
810  ss << " Memory = " << to_string_byte_format( info_hardware.total_memory ) << "\n";
811  print_(" 64-bit = ", info_hardware.OS_x64);
812  print_(" Little endian = ", info_hardware.is_little_endian);
813  ss << "\n";
814 
815  ss << "CPU Vendor:" << "\n";
816  ss << " Vendor = " << info_hardware.vendor_string << "\n";
817  ss << " CPU model = " << info_hardware.cpu_model << "\n";
818  print_(" AMD = ", info_hardware.vendor_AMD);
819  print_(" Intel = ", info_hardware.vendor_Intel);
820  ss << " Cores = " << info_hardware.physical_core_count << "\n";
821  print_(" Hyperthreads = ", info_hardware.with_hyperthreading);
822  ss << "\n";
823 
824  if( full ) {
825  ss << "OS Features:" << "\n";
826  print_(" OS AVX = ", info_hardware.OS_AVX);
827  print_(" OS AVX512 = ", info_hardware.OS_AVX512);
828  ss << "\n";
829 
830  ss << "Hardware Features:" << "\n";
831  print_(" MMX = ", info_hardware.HW_MMX);
832  print_(" x64 = ", info_hardware.HW_x64);
833  print_(" ABM = ", info_hardware.HW_ABM);
834  print_(" RDRAND = ", info_hardware.HW_RDRAND);
835  print_(" RDSEED = ", info_hardware.HW_RDSEED);
836  print_(" BMI1 = ", info_hardware.HW_BMI1);
837  print_(" BMI2 = ", info_hardware.HW_BMI2);
838  print_(" ADX = ", info_hardware.HW_ADX);
839  print_(" MPX = ", info_hardware.HW_MPX);
840  print_(" PREFETCHW = ", info_hardware.HW_PREFETCHW);
841  print_(" PREFETCHWT1 = ", info_hardware.HW_PREFETCHWT1);
842  print_(" RDPID = ", info_hardware.HW_RDPID);
843  print_(" GFNI = ", info_hardware.HW_GFNI);
844  print_(" VAES = ", info_hardware.HW_VAES);
845  ss << "\n";
846 
847  ss << "SIMD: 128-bit" << "\n";
848  print_(" SSE = ", info_hardware.HW_SSE);
849  print_(" SSE2 = ", info_hardware.HW_SSE2);
850  print_(" SSE3 = ", info_hardware.HW_SSE3);
851  print_(" SSSE3 = ", info_hardware.HW_SSSE3);
852  print_(" SSE4a = ", info_hardware.HW_SSE4a);
853  print_(" SSE4.1 = ", info_hardware.HW_SSE41);
854  print_(" SSE4.2 = ", info_hardware.HW_SSE42);
855  print_(" AES-NI = ", info_hardware.HW_AES);
856  print_(" SHA = ", info_hardware.HW_SHA);
857  ss << "\n";
858 
859  ss << "SIMD: 256-bit" << "\n";
860  print_(" AVX = ", info_hardware.HW_AVX);
861  print_(" XOP = ", info_hardware.HW_XOP);
862  print_(" FMA3 = ", info_hardware.HW_FMA3);
863  print_(" FMA4 = ", info_hardware.HW_FMA4);
864  print_(" AVX2 = ", info_hardware.HW_AVX2);
865  ss << "\n";
866 
867  ss << "SIMD: 512-bit" << "\n";
868  print_(" AVX512-F = ", info_hardware.HW_AVX512_F);
869  print_(" AVX512-CD = ", info_hardware.HW_AVX512_CD);
870  print_(" AVX512-PF = ", info_hardware.HW_AVX512_PF);
871  print_(" AVX512-ER = ", info_hardware.HW_AVX512_ER);
872  print_(" AVX512-VL = ", info_hardware.HW_AVX512_VL);
873  print_(" AVX512-BW = ", info_hardware.HW_AVX512_BW);
874  print_(" AVX512-DQ = ", info_hardware.HW_AVX512_DQ);
875  print_(" AVX512-IFMA = ", info_hardware.HW_AVX512_IFMA);
876  print_(" AVX512-VBMI = ", info_hardware.HW_AVX512_VBMI);
877  print_(" AVX512-VPOPCNTDQ = ", info_hardware.HW_AVX512_VPOPCNTDQ);
878  print_(" AVX512-4VNNIW = ", info_hardware.HW_AVX512_4VNNIW);
879  print_(" AVX512-4FMAPS = ", info_hardware.HW_AVX512_4FMAPS);
880  print_(" AVX512-VBMI2 = ", info_hardware.HW_AVX512_VBMI2);
881  print_(" AVX512-VPCLMUL = ", info_hardware.HW_AVX512_VPCLMUL);
882  print_(" AVX512-VNNI = ", info_hardware.HW_AVX512_VNNI);
883  print_(" AVX512-BITALG = ", info_hardware.HW_AVX512_BITALG);
884  print_(" AVX512-BF16 = ", info_hardware.HW_AVX512_BF16);
885  ss << "\n";
886  }
887 
888  ss << "SIMD Summary:" << "\n";
889  print_(" Safe to use AVX: ", info_use_avx());
890  print_(" Safe to use AVX2: ", info_use_avx2());
891  print_(" Safe to use AVX512: ", info_use_avx512());
892  ss << "\n";
893 
894  return ss.str();
895 }
896 
898 {
899  // Initialized on first use.
900  static const bool avx_is_safe_ =
904  ;
905  return avx_is_safe_;
906 }
907 
909 {
910  // Initialized on first use.
911  static const bool avx2_is_safe_ =
915  ;
916  return avx2_is_safe_;
917 }
918 
920 {
921  // Initialized on first use.
922  static const bool avx512_is_safe_ =
926  ;
927  return avx512_is_safe_;
928 }
929 
930 // =================================================================================================
931 // Number of Threads
932 // =================================================================================================
933 
934 unsigned int info_task_cpu_cores( bool physical = false )
935 {
936  // Adapted from https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
937  auto ncores = std::thread::hardware_concurrency();
938 
939  #if defined(__linux__)
940  cpu_set_t mask;
941  if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) != -1) {
942  ncores = CPU_COUNT(&mask);
943  }
944  #endif
945 
946  if (physical) {
947  auto const threads_per_core = info_hyperthreads_enabled() ? 2 : 1;
948  ncores /= threads_per_core;
949  }
950 
951  return ncores;
952 }
953 
955 {
956  return sysconf(_SC_NPROCESSORS_ONLN);
957 }
958 
959 size_t read_id_from_file_( std::string const& filename )
960 {
961  std::ifstream f(filename);
962  if( f.good() ) {
963  size_t id;
964  f >> id;
965  return id;
966  } else {
967  throw std::runtime_error("couldn't open sys files");
968  }
969 }
970 
971 size_t get_numa_node_id_( std::string const& cpu_path )
972 {
973  // Adapted from https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
974  // This is ugly, but should be reliable -> please blame Linux kernel developers & Intel!
975  std::string node_path = cpu_path + "../node";
976  for (size_t i = 0; i < 1000; ++i) {
977  if( is_dir(node_path + std::to_string(i)) ) {
978  return i;
979  }
980  }
981 
982  // Fallback solution: return socket_id which is often identical to numa id
983  return read_id_from_file_(cpu_path + "physical_package_id");
984 }
985 
986 size_t get_core_id_( std::string const& cpu_path )
987 {
988  return read_id_from_file_(cpu_path + "core_id");
989 }
990 
991 int get_physical_core_count_( size_t n_cpu )
992 {
993  // Adapted from https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
994  #if defined(__linux__)
995  std::unordered_set<size_t> cores;
996  for (size_t i = 0; i < n_cpu; ++i) {
997  std::string cpu_path = "/sys/devices/system/cpu/cpu" + std::to_string(i) + "/topology/";
998  size_t core_id = get_core_id_(cpu_path);
999  size_t node_id = get_numa_node_id_(cpu_path);
1000  size_t uniq_core_id = (node_id << 16) + core_id;
1001  cores.insert(uniq_core_id);
1002  }
1003  return cores.size();
1004  #else
1005  (void) n_cpu;
1006  return 0;
1007  #endif
1008 }
1009 
1011 {
1012  auto const hw_cores = std::thread::hardware_concurrency();
1013  try {
1014  // Try to get the physical cores, might fail and throw.
1015  auto const phys_cores = get_physical_core_count_( hw_cores );
1016  if( phys_cores > 0 ) {
1017  return phys_cores;
1018  }
1019  } catch ( ... ) {
1020  // Do nothing, just continue with the alternative.
1021  }
1022 
1023  // If the above did not work, use the fallback instead.
1024  auto const threads_per_core = info_hyperthreads_enabled() ? 2 : 1;
1025  return hw_cores / threads_per_core;
1026 }
1027 
1029 {
1030  // Get CPU info.
1031  int32_t info[4];
1032  #ifdef __aarch64__
1033  (void)info;
1034  return false;
1035  #elif defined( _WIN32 )
1036  __cpuid( info, 1 );
1037  #else
1038  __cpuid_count( 1, 0, info[0], info[1], info[2], info[3] );
1039  #endif
1040 
1041  return (bool) (info[3] & (0x1 << 28));
1042 }
1043 
1045 {
1046  size_t openmp_threads = 0;
1047 
1048  #if defined( GENESIS_OPENMP )
1049 
1050  // Use number of OpenMP threads, which might be set through the `OMP_NUM_THREADS`
1051  // environment variable. If there was an error there, fix it.
1052  openmp_threads = static_cast<size_t>( std::max( omp_get_max_threads(), 0 ));
1053 
1054  #else
1055 
1056  // Use the env variable directly if we don't have access to the OpenMP functions.
1057  auto const openmp_ptr = std::getenv( "OMP_NUM_THREADS" );
1058  if( openmp_ptr ) {
1059  openmp_threads = std::atoi( openmp_ptr );
1060  }
1061 
1062  #endif
1063 
1064  return openmp_threads;
1065 }
1066 
1068 {
1069  size_t slurm_cpus = 0;
1070  auto const slurm_ptr = std::getenv( "SLURM_CPUS_PER_TASK" );
1071  if( slurm_ptr ) {
1072  slurm_cpus = std::atoi( slurm_ptr );
1073 
1074  }
1075  return slurm_cpus;
1076 }
1077 
1078 size_t guess_number_of_threads( bool use_openmp, bool use_slurm, bool physical_cores )
1079 {
1080  // Dummy to avoid compiler warnings.
1081  (void) use_openmp;
1082 
1083  // Default to 1 thread. Will be overwritten later.
1084  size_t guess = 1;
1085 
1086  // Initialize threads with actual number of cores.
1087  // The function might return 0 if no number could be determined, in which case we default to 1.
1088  if( physical_cores ) {
1089  auto const phys_cores = info_physical_core_count();
1090  if( phys_cores > 0 ) {
1091  guess = phys_cores;
1092  }
1093  } else {
1094  auto const hw_concur = std::thread::hardware_concurrency();
1095  if( hw_concur > 0 ) {
1096  guess = static_cast<size_t>( hw_concur );
1097  }
1098  }
1099 
1100  // Now try slurm, if specified.
1101  if( use_slurm ) {
1102  auto const slurm_cpus = info_number_of_threads_slurm();
1103  if( slurm_cpus > 0 ) {
1104  guess = static_cast<size_t>( slurm_cpus );
1105  }
1106  }
1107 
1108  // Lastly, try OpenMP, if specified.
1109  if( use_openmp ) {
1110  auto const openmp_threads = info_number_of_threads_openmp();
1111 
1112  // By default, OpenMP uses something like hardware_concurrency, which might include
1113  // hyperthreads, and hence mess up this setup. So we catch that special case.
1114  auto const hw_concur = std::thread::hardware_concurrency();
1115  if( openmp_threads > 0 && openmp_threads == hw_concur && physical_cores ) {
1116  // We do not use the OpenMP threads for the guess in that case.
1117  auto const threads_per_core = info_hyperthreads_enabled() ? 2 : 1;
1118  guess = hw_concur / threads_per_core;
1119  } else if( openmp_threads > 0 ) {
1120  // Here, OpenMP is set to some non-zero number that is not just the hardware_concurrency
1121  guess = static_cast<size_t>( openmp_threads );
1122  }
1123  }
1124 
1125  assert( guess > 0 );
1126  return guess;
1127 }
1128 
1129 // =================================================================================================
1130 // Run Time Environment
1131 // =================================================================================================
1132 
1134 {
1135  // The return type `pid_t` of getpid() is an `int`, guaranteed to be non-negative:
1136  // https://ftp.gnu.org/old-gnu/Manuals/glibc-2.2.3/html_node/libc_554.html
1137  // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_300
1138  // We hence simply convert to `size_t` here.
1139  auto const pid = ::getpid();
1140  assert( pid > 0 );
1141  return static_cast<size_t>( pid );
1142 }
1143 
1145 {
1146  // Using http://stackoverflow.com/a/1312957/4184258
1147  #if defined( _WIN32 ) || defined( _WIN64 )
1148  return _isatty( _fileno( stdin ));
1149  #else
1150  return isatty( fileno( stdin ));
1151  #endif
1152 }
1153 
1155 {
1156  #if defined( _WIN32 ) || defined( _WIN64 )
1157  return _isatty( _fileno( stdout ));
1158  #else
1159  return isatty( fileno( stdout ));
1160  #endif
1161 }
1162 
1164 {
1165  #if defined( _WIN32 ) || defined( _WIN64 )
1166  return _isatty( _fileno( stderr ));
1167  #else
1168  return isatty( fileno( stderr ));
1169  #endif
1170 }
1171 
1172 std::pair<int, int> info_terminal_size()
1173 {
1174  #if defined( _WIN32 ) || defined( _WIN64 )
1175 
1176  CONSOLE_SCREEN_BUFFER_INFO csbi;
1177  int cols, rows;
1178  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
1179  cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
1180  rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1181  return { cols, rows };
1182 
1183  #else
1184 
1185  struct winsize w;
1186  ioctl( STDOUT_FILENO, TIOCGWINSZ, &w );
1187  return { w.ws_col, w.ws_row };
1188 
1189  #endif
1190 }
1191 
1192 // =================================================================================================
1193 // Current Resource Usage
1194 // =================================================================================================
1195 
1196 // -------------------------------------------------------------------------
1197 // Open File Counts
1198 // -------------------------------------------------------------------------
1199 
1201 {
1202  // https://www.man7.org/linux/man-pages/man2/getdtablesize.2.html
1203  return getdtablesize();
1204 
1205  // Alternative way. Not needed, as the above function internally calls the rlimits anyway.
1206  // https://man7.org/linux/man-pages/man2/getrlimit.2.html
1207  // struct rlimit rlimits;
1208  // getrlimit(RLIMIT_NOFILE, &rlimits);
1209  // rlimits.rlim_cur // soft limit
1210  // rlimits.rlim_max // hard limit (ceiling for rlim_cur)
1211 }
1212 
1214 {
1215  // Adapted from https://web.archive.org/web/20150326011742/
1216  // http://blog.lobstertechnology.com/2005/08/22/determine-the-number-of-open-files/
1217 
1218  // We loop over all possible file descriptor numbers...
1219  auto const max_fd_cnt = info_process_max_file_count();
1220 
1221  // ... and check if they are currently in use. If errno returns anything other
1222  // than EBADF 'file descriptor is bad', it increments a count.
1223  size_t fd_counter = 0;
1224  struct stat stats;
1225  for( size_t i = 0; i <= max_fd_cnt; ++i ) {
1226  errno = 0;
1227  fstat( i, &stats );
1228  if( errno != EBADF ) {
1229  ++fd_counter;
1230  }
1231  }
1232  return fd_counter;
1233 }
1234 
1235 #if defined( _WIN32 ) || defined( _WIN64 )|| defined( _MSC_VER )
1236 
1237  // -------------------------------------------------------------------------
1238  // Current Mem/CPU - Windows
1239  // -------------------------------------------------------------------------
1240 
1242  {
1243  // https://stackoverflow.com/q/63166/4184258
1244  // Beware: Completely untested, no error checking.
1245  // Kept here mostly for future reference.
1246 
1247  PROCESS_MEMORY_COUNTERS_EX pmc;
1248  GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
1249  return pmc.WorkingSetSize;
1250  }
1251 
1253  {
1254  // https://stackoverflow.com/q/63166/4184258
1255  // Beware: Completely untested, no error checking.
1256  // Kept here mostly for future reference.
1257 
1258  MEMORYSTATUSEX memInfo;
1259  memInfo.dwLength = sizeof(MEMORYSTATUSEX);
1260  GlobalMemoryStatusEx(&memInfo);
1261  assert( memInfo.ullTotalPhys >= memInfo.ullAvailPhys );
1262  return memInfo.ullTotalPhys - memInfo.ullAvailPhys;
1263  }
1264 
1266  {
1267  // Based on https://stackoverflow.com/q/63166/4184258
1268  // Beware: Completely untested, no error checking.
1269  // Kept here mostly for future reference.
1270 
1271  MEMORYSTATUSEX memInfo;
1272  memInfo.dwLength = sizeof(MEMORYSTATUSEX);
1273  GlobalMemoryStatusEx(&memInfo);
1274  return memInfo.ullAvailPhys;
1275  }
1276 
1277  double info_process_current_cpu_usage( bool all_cores, bool percent )
1278  {
1279  // https://stackoverflow.com/q/63166/4184258
1280  // Beware: Completely untested, no error checking.
1281  // Kept here mostly for future reference.
1282 
1283  static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
1284  static int num_processors;
1285  static HANDLE self;
1286  static bool initialized = false;
1287 
1288  if( ! initialized ) {
1289  SYSTEM_INFO sysInfo;
1290  FILETIME ftime, fsys, fuser;
1291 
1292  GetSystemInfo(&sysInfo);
1293  num_processors = sysInfo.dwNumberOfProcessors;
1294 
1295  GetSystemTimeAsFileTime(&ftime);
1296  memcpy(&lastCPU, &ftime, sizeof(FILETIME));
1297 
1298  self = GetCurrentProcess();
1299  GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);
1300  memcpy(&lastSysCPU, &fsys, sizeof(FILETIME));
1301  memcpy(&lastUserCPU, &fuser, sizeof(FILETIME));
1302 
1303  initialized = true;
1304  return 0.0;
1305  }
1306 
1307  FILETIME ftime, fsys, fuser;
1308  ULARGE_INTEGER now, sys, user;
1309  double result;
1310 
1311  GetSystemTimeAsFileTime(&ftime);
1312  memcpy(&now, &ftime, sizeof(FILETIME));
1313 
1314  GetProcessTimes(self, &ftime, &ftime, &fsys, &fuser);
1315  memcpy(&sys, &fsys, sizeof(FILETIME));
1316  memcpy(&user, &fuser, sizeof(FILETIME));
1317  result = (sys.QuadPart - lastSysCPU.QuadPart) + (user.QuadPart - lastUserCPU.QuadPart);
1318  result /= (now.QuadPart - lastCPU.QuadPart);
1319  if( ! all_cores ) {
1320  result /= num_processors;
1321  }
1322  if( percent ) {
1323  result *= 100;
1324  }
1325 
1326  lastCPU = now;
1327  lastUserCPU = user;
1328  lastSysCPU = sys;
1329 
1330  return result;
1331  }
1332 
1333  double info_system_current_cpu_usage( bool all_cores, bool percent )
1334  {
1335  // Adapted from https://stackoverflow.com/q/63166/4184258
1336  // Beware: Completely untested, no error checking.
1337  // Kept here mostly for future reference.
1338 
1339  static PDH_HQUERY cpuQuery;
1340  static PDH_HCOUNTER cpuTotal;
1341  static int num_processors;
1342  static bool initialized = false;
1343 
1344  if( ! initialized ) {
1345  SYSTEM_INFO sysInfo;
1346  GetSystemInfo(&sysInfo);
1347  num_processors = sysInfo.dwNumberOfProcessors;
1348 
1349  PdhOpenQuery(NULL, NULL, &cpuQuery);
1350  // You can also use L"\\Processor(*)\\% Processor Time" and get individual CPU values
1351  // with PdhGetFormattedCounterArray()
1352  PdhAddEnglishCounter(cpuQuery, L"\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);
1353  PdhCollectQueryData(cpuQuery);
1354 
1355  initialized = true;
1356  }
1357 
1358  PDH_FMT_COUNTERVALUE counterVal;
1359  PdhCollectQueryData(cpuQuery);
1360  PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
1361 
1362  auto result = counterVal.doubleValue;
1363  if( !all_cores ) {
1364  result /= num_processors;
1365  }
1366  if( !percent ) {
1367  result /= 100.0;
1368  }
1369  return result;
1370  }
1371 
1372 #elif defined( __APPLE__ )
1373 
1374  // -------------------------------------------------------------------------
1375  // Current Mem/CPU - Apple
1376  // -------------------------------------------------------------------------
1377 
1379  {
1380  // https://stackoverflow.com/q/63166/4184258
1381 
1382  struct task_basic_info t_info;
1383  mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
1384 
1385  auto const ret = task_info(
1386  mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count
1387  );
1388  if( KERN_SUCCESS != ret ) {
1389  return 0;
1390  }
1391  // resident size is in t_info.resident_size;
1392  // virtual size is in t_info.virtual_size;
1393  return t_info.resident_size;
1394  }
1395 
1397  {
1398  // Adapted from https://stackoverflow.com/a/1911863/4184258
1399 
1400  vm_size_t page_size;
1401  mach_port_t mach_port;
1402  mach_msg_type_number_t count;
1403  vm_statistics64_data_t vm_stats;
1404 
1405  mach_port = mach_host_self();
1406  count = sizeof(vm_stats) / sizeof(natural_t);
1407  if(
1408  KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
1409  KERN_SUCCESS == host_statistics64(
1410  mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count
1411  )
1412  ) {
1413  // Used memory has several types of relevant pages that we need to take into account.
1414  auto const relevant_sum =
1415  static_cast<size_t>( vm_stats.active_count ) +
1416  static_cast<size_t>( vm_stats.inactive_count ) +
1417  static_cast<size_t>( vm_stats.wire_count )
1418  ;
1419  return relevant_sum * static_cast<size_t>( page_size );
1420  }
1421 
1422  return 0;
1423  }
1424 
1426  {
1427  // Adapted from https://stackoverflow.com/a/1911863/4184258
1428 
1429  vm_size_t page_size;
1430  mach_port_t mach_port;
1431  mach_msg_type_number_t count;
1432  vm_statistics64_data_t vm_stats;
1433 
1434  mach_port = mach_host_self();
1435  count = sizeof(vm_stats) / sizeof(natural_t);
1436  if(
1437  KERN_SUCCESS == host_page_size(mach_port, &page_size) &&
1438  KERN_SUCCESS == host_statistics64(
1439  mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count
1440  )
1441  ) {
1442  return static_cast<size_t>( vm_stats.free_count ) * static_cast<size_t>( page_size );
1443  }
1444  return 0;
1445  }
1446 
1447  size_t info_process_number_of_processors_()
1448  {
1449  // This is kind of redundant from the other functions...
1450  // Well, but we keep it this way for now for compatibility with the original code.
1451 
1452  host_basic_info_data_t hostInfo;
1453  mach_msg_type_number_t hostCount = HOST_BASIC_INFO_COUNT;
1454  auto const hi = host_info(
1455  mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &hostCount
1456  );
1457  if( hi != KERN_SUCCESS ) {
1458  return 0;
1459  }
1460  return hostInfo.avail_cpus;
1461  }
1462 
1463  double info_process_current_cpu_usage( bool all_cores, bool percent )
1464  {
1465  // No implementation from stack overflow :-(
1466  // Hopefully, this one works though, provided by ChatGPT.
1467 
1468  static uint64_t last_total_time = 0;
1469  static struct timeval last_time;
1470  static int num_processors = 0;
1471  static bool initialized = false;
1472 
1473  struct task_thread_times_info thread_times;
1474  mach_msg_type_number_t count = TASK_THREAD_TIMES_INFO_COUNT;
1475 
1476  if( !initialized ) {
1477  gettimeofday(&last_time, NULL);
1478  auto const ti = task_info(
1479  mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&thread_times, &count
1480  );
1481  if( ti != KERN_SUCCESS ) {
1482  return 0.0;
1483  }
1484  last_total_time =
1485  thread_times.user_time.seconds * 1000000 +
1486  thread_times.user_time.microseconds +
1487  thread_times.system_time.seconds * 1000000 +
1488  thread_times.system_time.microseconds
1489  ;
1490 
1491  // Get the number of processors
1492  num_processors = info_process_number_of_processors_();
1493 
1494  initialized = true;
1495  return 0.0;
1496  }
1497 
1498  struct timeval current_time;
1499  gettimeofday(&current_time, NULL);
1500  auto const ti = task_info(
1501  mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&thread_times, &count
1502  );
1503  if( ti != KERN_SUCCESS ) {
1504  return 0.0;
1505  }
1506  uint64_t total_time =
1507  thread_times.user_time.seconds * 1000000 +
1508  thread_times.user_time.microseconds +
1509  thread_times.system_time.seconds * 1000000 +
1510  thread_times.system_time.microseconds
1511  ;
1512  uint64_t elapsed_time =
1513  (current_time.tv_sec - last_time.tv_sec) * 1000000 +
1514  (current_time.tv_usec - last_time.tv_usec)
1515  ;
1516  double result = (total_time - last_total_time) / static_cast<double>(elapsed_time);
1517  if( all_cores ) {
1518  result *= num_processors;
1519  }
1520  if( percent ) {
1521  result *= 100;
1522  }
1523 
1524  last_time = current_time;
1525  last_total_time = total_time;
1526 
1527  return result;
1528  }
1529 
1530  double info_system_current_cpu_usage( bool all_cores, bool percent )
1531  {
1532  // Adapted from https://stackoverflow.com/a/49996245/4184258
1533 
1534  static size_t _previousTotalTicks = 0;
1535  static size_t _previousIdleTicks = 0;
1536  static int num_processors = 0;
1537  static bool initialized = false;
1538 
1539  if( ! initialized ) {
1540  num_processors = info_process_number_of_processors_();
1541  initialized = true;
1542  return 0.0;
1543  }
1544 
1545  auto calculate_CPU_load_ = [&](size_t idleTicks, size_t totalTicks)
1546  {
1547  size_t totalTicksSinceLastTime = totalTicks - _previousTotalTicks;
1548  size_t idleTicksSinceLastTime = idleTicks - _previousIdleTicks;
1549  _previousTotalTicks = totalTicks;
1550  _previousIdleTicks = idleTicks;
1551 
1552  if( totalTicksSinceLastTime == 0 ) {
1553  return 1.0;
1554  }
1555  return 1.0 - static_cast<double>( idleTicksSinceLastTime ) / totalTicksSinceLastTime;
1556  };
1557 
1558  // Returns 1.0f for "CPU fully pinned", 0.0f for "CPU idle", or somewhere in between
1559  // You'll need to call this at regular intervals, since it measures the load between
1560  // the previous call and the current one.
1561  host_cpu_load_info_data_t cpuinfo;
1562  mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
1563  if(
1564  host_statistics(
1565  mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpuinfo, &count
1566  ) != KERN_SUCCESS
1567  ) {
1568  return 0.0;
1569  }
1570 
1571  size_t totalTicks = 0;
1572  for( int i = 0; i < CPU_STATE_MAX; i++ ) {
1573  totalTicks += cpuinfo.cpu_ticks[i];
1574  }
1575  auto result = calculate_CPU_load_( cpuinfo.cpu_ticks[CPU_STATE_IDLE], totalTicks );
1576  if( all_cores ) {
1577  result *= num_processors;
1578  }
1579  if( percent ) {
1580  result *= 100.0;
1581  }
1582  return result;
1583  }
1584 
1585 #elif defined( __GNUC__ ) || defined( __clang__ ) || defined(__linux__)
1586 
1587  // -------------------------------------------------------------------------
1588  // Current Mem/CPU - Linux
1589  // -------------------------------------------------------------------------
1590 
1591  size_t parse_proc_line_kb_( char* line )
1592  {
1593  // Helper function to parse "/proc/self/status", see
1594  // https://stackoverflow.com/q/63166/4184258
1595  // Adapted from there to add error checking.
1596 
1597 
1598  // Check if the line is too short to contain " kB" and a value
1599  auto length = strlen(line);
1600  if( length < 5 ) {
1601  return 0;
1602  }
1603 
1604  // Need to remove new line from end if present
1605  if( line[length - 1] == '\n' ) {
1606  line[length - 1] = '\0';
1607  --length;
1608  }
1609 
1610  // Check that the string ends with " kB" (case-insensitive)
1611  if( strncasecmp( &line[length - 3], " kB", 3 ) != 0 ) {
1612  return 0;
1613  }
1614 
1615  // Null-terminate the string to remove the " kB"
1616  line[length - 3] = '\0';
1617 
1618  // Find the first digit in the string
1619  char* p = line;
1620  while( *p && !isdigit(*p) ) {
1621  p++;
1622  }
1623 
1624  // Check if we found a digit, then convert the numeric part of the string to an integer
1625  if( *p == '\0' ) {
1626  return 0;
1627  }
1628  return atoi(p);
1629  }
1630 
1632  {
1633  // https://stackoverflow.com/q/63166/4184258
1634 
1635  //Note: this value is in KB!
1636  FILE* file = fopen("/proc/self/status", "r");
1637  size_t result = 0;
1638  char line[128];
1639  if( !file ) {
1640  return 0;
1641  }
1642 
1643  while( fgets( line, 128, file ) != NULL ) {
1644  if( strncmp( line, "VmRSS:", 6 ) == 0 ) {
1645  result = parse_proc_line_kb_(line);
1646  break;
1647  }
1648  }
1649  fclose(file);
1650  return result * 1024;
1651  }
1652 
1653  std::unordered_map<std::string, size_t> get_proc_meminfo_lines_()
1654  {
1655  std::unordered_map<std::string, size_t> meminfo;
1656  std::ifstream file("/proc/meminfo");
1657  std::string line;
1658 
1659  while (std::getline(file, line)) {
1660  std::istringstream iss(line);
1661  std::string key;
1662  size_t value;
1663  std::string unit;
1664  iss >> key >> value >> unit;
1665  key.pop_back(); // Remove trailing ':'
1666  meminfo[key] = value * 1024; // Convert kB to bytes
1667  }
1668 
1669  return meminfo;
1670  }
1671 
1672  size_t info_system_current_memory_helper_( bool available )
1673  {
1674  // Use a more comprehensive approach based on proc files, that also accounts for
1675  // buffered and cached memory pages.
1676  try {
1677  // We purposefully do not make meminfo const here, so that any failing
1678  // lookups instead simply add the element as 0, which is an okay fallback.
1679  size_t mem_avail = 0;
1680  auto meminfo = get_proc_meminfo_lines_();
1681  if( meminfo.count( "MemAvailable" ) > 0 ) {
1682  mem_avail = meminfo["MemAvailable"];
1683  } else {
1684  // If MemAvailable is not found, fallback to calculating it manually
1685  size_t memFree = meminfo["MemFree"];
1686  size_t buffers = meminfo["Buffers"];
1687  size_t cached = meminfo["Cached"];
1688  mem_avail = memFree + buffers + cached;
1689  }
1690  if( available ) {
1691  return mem_avail;
1692  } else if( meminfo.count( "MemTotal" ) != 0 ) {
1693  // If this is not available, we use the below fallback instead.
1694  return meminfo["MemTotal"] - mem_avail;
1695  }
1696  } catch( ... ) {
1697  // Do nothing here, just follow up with the below fallback.
1698  }
1699 
1700  // If the above does not work, we use this as another fallback, which however
1701  // only reports the completely free memory, disregarind buffers and caches.
1702  // Adapted from https://stackoverflow.com/q/63166/4184258
1703  struct sysinfo memInfo;
1704  if( sysinfo( &memInfo )) {
1705  return 0;
1706  }
1707  auto const mem_unit = static_cast<size_t>( memInfo.mem_unit );
1708  if( available ) {
1709  return static_cast<size_t>( memInfo.freeram ) * mem_unit;
1710  } else {
1711  return static_cast<size_t>( memInfo.totalram - memInfo.freeram ) * mem_unit;
1712  }
1713  return 0;
1714  }
1715 
1717  {
1718  return info_system_current_memory_helper_( false );
1719  }
1720 
1722  {
1723  return info_system_current_memory_helper_( true );
1724  }
1725 
1726  size_t info_process_number_of_processors_()
1727  {
1728  // This is kind of redundant from the other functions...
1729  // Well, but we keep it this way for now for compatibility with the original code.
1730 
1731  size_t num_processors = 0;
1732  FILE* file = fopen("/proc/cpuinfo", "r");
1733  if( ! file ) {
1734  return 0;
1735  }
1736  char line[128];
1737  while( fgets(line, 128, file) != NULL) {
1738  if( strncmp(line, "processor", 9) == 0 ) {
1739  ++num_processors;
1740  }
1741  }
1742  fclose(file);
1743  return num_processors;
1744  }
1745 
1746  double info_process_current_cpu_usage( bool all_cores, bool percent )
1747  {
1748  // https://stackoverflow.com/q/63166/4184258
1749 
1750  static clock_t lastCPU, lastSysCPU, lastUserCPU;
1751  static int num_processors;
1752  static bool initialized = false;
1753 
1754  if( ! initialized ) {
1755  struct tms timeSample;
1756  lastCPU = times(&timeSample);
1757  lastSysCPU = timeSample.tms_stime;
1758  lastUserCPU = timeSample.tms_utime;
1759  num_processors = info_process_number_of_processors_();
1760 
1761  initialized = true;
1762  return 0.0;
1763  }
1764 
1765  struct tms timeSample;
1766  clock_t now;
1767  double result;
1768 
1769  now = times(&timeSample);
1770  if(
1771  now <= lastCPU ||
1772  timeSample.tms_stime < lastSysCPU ||
1773  timeSample.tms_utime < lastUserCPU
1774  ) {
1775  //Overflow detection. Just skip this value.
1776  result = 0.0;
1777  } else {
1778  result = (timeSample.tms_stime - lastSysCPU) + (timeSample.tms_utime - lastUserCPU);
1779  result /= (now - lastCPU);
1780  if( ! all_cores ) {
1781  result /= num_processors;
1782  }
1783  if( percent ) {
1784  result *= 100;
1785  }
1786  }
1787  lastCPU = now;
1788  lastSysCPU = timeSample.tms_stime;
1789  lastUserCPU = timeSample.tms_utime;
1790 
1791  return result;
1792  }
1793 
1794  double info_system_current_cpu_usage( bool all_cores, bool percent )
1795  {
1796  // Adapted from https://stackoverflow.com/q/63166/4184258
1797 
1798  static unsigned long long lastTotalUser, lastTotalUserLow, lastTotalSys, lastTotalIdle;
1799  static int num_processors;
1800  static bool initialized = false;
1801 
1802  if( ! initialized ) {
1803  FILE* file = fopen("/proc/stat", "r");
1804  if( ! file ) {
1805  return 0.0;
1806  }
1807 
1808  auto const scanned = fscanf(
1809  file, "cpu %llu %llu %llu %llu",
1810  &lastTotalUser, &lastTotalUserLow, &lastTotalSys, &lastTotalIdle
1811  );
1812  fclose(file);
1813  num_processors = info_process_number_of_processors_();
1814  if( scanned != 4 ) {
1815  return 0.0;
1816  }
1817 
1818  initialized = true;
1819  return 0.0;
1820  }
1821 
1822  double result;
1823  FILE* file;
1824  unsigned long long totalUser, totalUserLow, totalSys, totalIdle, total;
1825 
1826  file = fopen("/proc/stat", "r");
1827  if( ! file ) {
1828  return 0.0;
1829  }
1830  auto const scanned = fscanf(
1831  file, "cpu %llu %llu %llu %llu",
1832  &totalUser, &totalUserLow, &totalSys, &totalIdle
1833  );
1834  fclose(file);
1835  if( scanned != 4 ) {
1836  return 0.0;
1837  }
1838 
1839  if(
1840  totalUser < lastTotalUser || totalUserLow < lastTotalUserLow ||
1841  totalSys < lastTotalSys || totalIdle < lastTotalIdle
1842  ) {
1843  //Overflow detection. Just skip this value.
1844  result = 0.0;
1845  } else {
1846  total =
1847  (totalUser - lastTotalUser) +
1848  (totalUserLow - lastTotalUserLow) +
1849  (totalSys - lastTotalSys)
1850  ;
1851  result = total;
1852  total += (totalIdle - lastTotalIdle);
1853  result /= total;
1854  if( all_cores ) {
1855  result *= num_processors;
1856  }
1857  if( percent ) {
1858  result *= 100;
1859  }
1860  }
1861 
1862  lastTotalUser = totalUser;
1863  lastTotalUserLow = totalUserLow;
1864  lastTotalSys = totalSys;
1865  lastTotalIdle = totalIdle;
1866 
1867  return result;
1868  }
1869 
1870 #else
1871 
1872  // -------------------------------------------------------------------------
1873  // Current Mem/CPU - Default
1874  // -------------------------------------------------------------------------
1875 
1877  {
1878  return 0;
1879  }
1880 
1882  {
1883  return 0;
1884  }
1885 
1887  {
1888  return 0;
1889  }
1890 
1891  double info_process_current_cpu_usage( bool all_cores, bool percent )
1892  {
1893  (void) all_cores;
1894  (void) percent;
1895  return 0.0;
1896  }
1897 
1898  double info_system_current_cpu_usage( bool all_cores, bool percent )
1899  {
1900  (void) all_cores;
1901  (void) percent;
1902  return 0.0;
1903  }
1904 
1905 #endif
1906 
1907 // =================================================================================================
1908 // Total Resource Usage
1909 // =================================================================================================
1910 
1912 {
1913  // Adapted from https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
1914 
1915  struct rusage r_usage;
1916  getrusage(RUSAGE_SELF, &r_usage);
1917 
1918  #if defined __APPLE__
1919  // Mac: ru_maxrss gives the size in bytes
1920  return static_cast<size_t>( r_usage.ru_maxrss );
1921  #else
1922  // Linux: ru_maxrss gives the size in kilobytes
1923  return static_cast<size_t>( r_usage.ru_maxrss * 1024 );
1924  #endif
1925 }
1926 
1927 std::pair<double, double> info_process_total_cpu_time()
1928 {
1929  // https://www.gnu.org/software/libc/manual/html_node/Resource-Usage.html
1930  struct rusage r_usage;
1931  getrusage(RUSAGE_SELF, &r_usage);
1932 
1933  // Calculate user and system time.
1934  auto const u_tmr = r_usage.ru_utime.tv_sec * 1.0 + (double)r_usage.ru_utime.tv_usec * 1.0e-6;
1935  auto const s_tmr = r_usage.ru_stime.tv_sec * 1.0 + r_usage.ru_stime.tv_usec * 1.0e-6;
1936 
1937  return std::make_pair( u_tmr, s_tmr );
1938 }
1939 
1941 {
1942  // Adapted from https://github.com/amkozlov/raxml-ng/blob/master/src/util/sysutil.cpp
1943 
1944  try {
1945  double energy = 0.0;
1946  auto const basepath = "/sys/class/powercap/intel-rapl/intel-rapl:";
1947 
1948  // Sum up over all energy files
1949  size_t const max_packages = 32;
1950  for( size_t i = 0; i < max_packages; ++i ) {
1951  double pkg_energy;
1952  auto const fname = basepath + std::to_string(i) + "/energy_uj";
1953  if( !file_is_readable(fname) ) {
1954  break;
1955  }
1956  std::ifstream fs(fname);
1957  fs >> pkg_energy;
1958  energy += pkg_energy;
1959  }
1960 
1961  // Prepare output
1962  energy /= 1e6; // convert to Joules
1963  energy /= 3600; // convert to Wh
1964  return energy;
1965  } catch ( ... ) {
1966  return 0.0;
1967  }
1968  return 0.0;
1969 }
1970 
1972 {
1973  // Get data.
1974  auto const time = info_process_total_cpu_time();
1975  auto const memory = info_process_peak_memory_usage();
1976  auto const energy = info_process_total_energy_consumption();
1977 
1978  // Print everything.
1979  std::stringstream ss;
1980  ss << std::setprecision(3) << std::fixed;
1981  ss << "Time: " << time.first << "s (user)\n";
1982  ss << "Time: " << time.second << "s (sys)\n";
1983  ss << "Memory: " << to_string_byte_format( memory ) << "\n";
1984  ss << "Energy: " << energy << "Wh\n";
1985 
1986  return ss.str();
1987 }
1988 
1989 } // namespace utils
1990 } // namespace genesis
genesis::utils::InfoHardware::HW_AVX512_BW
bool HW_AVX512_BW
Definition: info.hpp:219
genesis::utils::InfoHardware::HW_AVX512_F
bool HW_AVX512_F
Definition: info.hpp:210
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::InfoCompiler::with_openmp
bool with_openmp
Compiled with OpenMP.
Definition: info.hpp:102
genesis::utils::InfoHardware::HW_SSE3
bool HW_SSE3
Definition: info.hpp:194
genesis::utils::InfoCompiler::is_release
bool is_release
Binary was compiled with build type RELEASE.
Definition: info.hpp:66
genesis::utils::info_terminal_size
std::pair< int, int > info_terminal_size()
Return the width and height of the terminal that is used to run the program, in number of columns and...
Definition: info.cpp:1172
genesis::utils::info_process_total_cpu_time
std::pair< double, double > info_process_total_cpu_time()
Get the currently used cpu run time, similar to the Unix time command.
Definition: info.cpp:1927
genesis::utils::InfoCompiler::with_avx512
bool with_avx512
Compiled with AVX512.
Definition: info.hpp:126
fs.hpp
Provides functions for accessing the file system.
genesis::utils::detect_OS_AVX512_
bool detect_OS_AVX512_()
Definition: info.cpp:553
genesis::utils::InfoHardware::HW_ADX
bool HW_ADX
Definition: info.hpp:185
genesis::utils::InfoHardware::HW_AVX512_BF16
bool HW_AVX512_BF16
Definition: info.hpp:235
genesis::utils::InfoHardware::HW_AVX512_IFMA
bool HW_AVX512_IFMA
Definition: info.hpp:223
genesis::utils::info_online_cpu_cores
long info_online_cpu_cores()
Definition: info.cpp:954
genesis::utils::InfoHardware::HW_SSE
bool HW_SSE
Definition: info.hpp:192
genesis::utils::InfoCompiler::with_avx
bool with_avx
Compiled with AVX.
Definition: info.hpp:110
genesis::utils::info_preprocessor_definitions
std::unordered_map< std::string, std::string > const & info_preprocessor_definitions()
Return a string map with some relevant preprocessor macros.
Definition: info.cpp:296
genesis::utils::info_process_current_cpu_usage
double info_process_current_cpu_usage(bool all_cores, bool percent)
Return the CPU usage of the current process.
Definition: info.cpp:1891
genesis::utils::get_vendor_string_
std::string get_vendor_string_()
Definition: info.cpp:564
genesis::tree::length
double length(Tree const &tree)
Get the length of the tree, i.e., the sum of all branch lengths.
Definition: tree/common_tree/functions.cpp:160
genesis::utils::get_physical_core_count_
int get_physical_core_count_(size_t n_cpu)
Definition: info.cpp:991
genesis::utils::InfoHardware::HW_AVX512_BITALG
bool HW_AVX512_BITALG
Definition: info.hpp:242
genesis::utils::InfoHardware::HW_AVX
bool HW_AVX
Definition: info.hpp:203
genesis::utils::InfoHardware::is_little_endian
bool is_little_endian
System uses little endian memory. If false, system uses big endian.
Definition: info.hpp:157
version.hpp
Some stuff that is totally not imporatant, but nice.
genesis::utils::info_process_peak_memory_usage
size_t info_process_peak_memory_usage()
Get the peak used memory, in bytes.
Definition: info.cpp:1911
genesis::utils::InfoHardware::HW_SSSE3
bool HW_SSSE3
Definition: info.hpp:195
genesis::utils::get_numa_node_id_
size_t get_numa_node_id_(std::string const &cpu_path)
Definition: info.cpp:971
genesis::utils::InfoHardware::HW_PREFETCHWT1
bool HW_PREFETCHWT1
Definition: info.hpp:188
genesis::utils::InfoHardware::cpu_model
std::string cpu_model
Definition: info.hpp:168
genesis::utils::InfoHardware::OS_AVX
bool OS_AVX
Definition: info.hpp:174
genesis::utils::offset
void offset(Histogram &h, double value)
Definition: operations.cpp:47
genesis::utils::InfoCompiler::platform
std::string platform
Platform under which genesis was compiled.
Definition: info.hpp:78
genesis::utils::InfoHardware::HW_AVX512_VPOPCNTDQ
bool HW_AVX512_VPOPCNTDQ
Definition: info.hpp:227
genesis::utils::info_system_current_memory_usage
size_t info_system_current_memory_usage()
Return the memory currently used across all running processes, in bytes.
Definition: info.cpp:1881
genesis::utils::info_get_hardware
InfoHardware const & info_get_hardware()
Return information about hardware features.
Definition: info.cpp:665
genesis::utils::current_time
std::string current_time()
Returns the current time as a string in the format "13:37:42".
Definition: date_time.cpp:88
genesis::utils::InfoHardware::HW_AVX512_4VNNIW
bool HW_AVX512_4VNNIW
Definition: info.hpp:228
genesis::utils::info_print_compiler
std::string info_print_compiler()
Print information about compiler settings and flags to a string.
Definition: info.cpp:363
genesis::utils::info_process_print_total_usage
std::string info_process_print_total_usage()
Print usage information to a string.
Definition: info.cpp:1971
genesis::utils::info_process_current_memory_usage
size_t info_process_current_memory_usage()
Return the memory currently used by the current process, in bytes.
Definition: info.cpp:1876
genesis::utils::InfoHardware::total_memory
size_t total_memory
Total amount of memory, in bytes.
Definition: info.hpp:162
genesis::utils::InfoHardware::HW_GFNI
bool HW_GFNI
Definition: info.hpp:239
genesis::utils::InfoHardware::HW_XOP
bool HW_XOP
Definition: info.hpp:204
genesis::utils::InfoHardware::HW_FMA4
bool HW_FMA4
Definition: info.hpp:206
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: function/genome_locus.hpp:52
genesis::utils::xgetbv
uint64_t xgetbv(unsigned int index)
Definition: info.cpp:485
genesis::utils::info_process_total_energy_consumption
double info_process_total_energy_consumption()
Get energy consumption of the program so far, in Wh.
Definition: info.cpp:1940
genesis::utils::InfoHardware::HW_x64
bool HW_x64
Definition: info.hpp:179
string.hpp
Provides some commonly used string utility functions.
genesis::utils::info_stdout_is_terminal
bool info_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: info.cpp:1154
genesis::utils::InfoHardware::HW_SSE2
bool HW_SSE2
Definition: info.hpp:193
genesis::utils::info_hyperthreads_enabled
bool info_hyperthreads_enabled()
Try to get whether hyperthreads are enabled in the current system.
Definition: info.cpp:1028
genesis::utils::strncasecmp
int strncasecmp(char const *s1, char const *s2, size_t n)
Compares up to n chars of two strings, ignoring case differences.
Definition: string.cpp:90
genesis::utils::InfoHardware::HW_BMI1
bool HW_BMI1
Definition: info.hpp:183
genesis::utils::info_number_of_threads_slurm
size_t info_number_of_threads_slurm()
Get the number of threads as indicated by the SLURM environment.
Definition: info.cpp:1067
genesis::utils::InfoHardware::HW_SSE4a
bool HW_SSE4a
Definition: info.hpp:198
genesis::utils::InfoHardware::vendor_Intel
bool vendor_Intel
Definition: info.hpp:166
genesis::utils::InfoHardware::with_hyperthreading
bool with_hyperthreading
Definition: info.hpp:170
logging.hpp
Provides easy and fast logging functionality.
genesis::utils::get_cpuid_
void get_cpuid_(int32_t out[4], int32_t eax, int32_t ecx)
Definition: info.cpp:468
genesis::utils::InfoHardware::HW_AVX512_PF
bool HW_AVX512_PF
Definition: info.hpp:214
genesis::utils::info_get_pid
size_t info_get_pid()
Get the process ID of the current process.
Definition: info.cpp:1133
genesis::utils::InfoHardware::HW_SSE41
bool HW_SSE41
Definition: info.hpp:196
genesis::utils::InfoCompiler::compiler_family
std::string compiler_family
Compiler family (name) that was used to compile genesis.
Definition: info.hpp:85
genesis::utils::detect_OS_AVX_
bool detect_OS_AVX_()
Definition: info.cpp:533
genesis::utils::info_number_of_threads_openmp
size_t info_number_of_threads_openmp()
Get the number of threads as indicated by the OpenMP environment.
Definition: info.cpp:1044
genesis::utils::InfoHardware::HW_AVX512_ER
bool HW_AVX512_ER
Definition: info.hpp:215
genesis::utils::InfoHardware::HW_AVX512_CD
bool HW_AVX512_CD
Definition: info.hpp:211
genesis::utils::info_system_current_memory_available
size_t info_system_current_memory_available()
Return the memory currently available in the system, in bytes.
Definition: info.cpp:1886
genesis::utils::info_use_avx
bool info_use_avx()
Assess if it is safe to use AVX features.
Definition: info.cpp:897
genesis::utils::get_cpu_model_
std::string get_cpu_model_()
Definition: info.cpp:578
genesis::utils::InfoHardware::HW_BMI2
bool HW_BMI2
Definition: info.hpp:184
genesis::utils::InfoHardware::HW_AVX512_VNNI
bool HW_AVX512_VNNI
Definition: info.hpp:232
genesis::utils::InfoCompiler::build_type
std::string build_type
Build type that was used to compile the binary, i.e., "debug" or "release".
Definition: info.hpp:71
genesis::utils::is_dir
bool is_dir(std::string const &path)
Return true iff the provided path is a directory.
Definition: fs.cpp:213
genesis::utils::get_memtotal_
size_t get_memtotal_()
Definition: info.cpp:609
genesis::utils::InfoCompiler::compile_date_time
std::string compile_date_time
Date and time when genesis was compiled.
Definition: info.hpp:56
info.hpp
genesis::utils::InfoHardware::HW_FMA3
bool HW_FMA3
Definition: info.hpp:205
genesis::utils::get_core_id_
size_t get_core_id_(std::string const &cpu_path)
Definition: info.cpp:986
genesis::utils::info_system_current_cpu_usage
double info_system_current_cpu_usage(bool all_cores, bool percent)
Return the CPU usage of the system, across all cores.
Definition: info.cpp:1898
genesis::utils::InfoHardware::HW_AVX512_4FMAPS
bool HW_AVX512_4FMAPS
Definition: info.hpp:229
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::info_stdin_is_terminal
bool info_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: info.cpp:1144
genesis::utils::InfoHardware::HW_ABM
bool HW_ABM
Definition: info.hpp:180
genesis::utils::InfoCompiler::cpp_version
std::string cpp_version
C++ version that was used to compile genesis.
Definition: info.hpp:97
genesis::utils::info_get_compiler
InfoCompiler const & info_get_compiler()
Return information about compiler settings and flags.
Definition: info.cpp:171
genesis::utils::file_is_readable
bool file_is_readable(std::string const &filename)
Return whether a file is readable.
Definition: fs.cpp:108
genesis::utils::InfoHardware
Definition: info.hpp:152
genesis::utils::info_physical_core_count
size_t info_physical_core_count()
Get the number of CPU cores.
Definition: info.cpp:1010
genesis::utils::to_string_byte_format
std::string to_string_byte_format(size_t value)
Produce a human readable formatting of a size in bytes, using the appropriate suffix.
Definition: string.cpp:1047
genesis::utils::InfoHardware::HW_MMX
bool HW_MMX
Definition: info.hpp:178
genesis::utils::InfoHardware::vendor_string
std::string vendor_string
Definition: info.hpp:167
genesis::utils::info_process_max_file_count
size_t info_process_max_file_count()
Return the maximum number of files (i.e., file descriptors) that can be opened simultaneously in the ...
Definition: info.cpp:1200
genesis::utils::info_use_avx2
bool info_use_avx2()
Assess if it is safe to use AVX2 features.
Definition: info.cpp:908
genesis::utils::InfoHardware::OS_x64
bool OS_x64
Definition: info.hpp:173
options.hpp
genesis::utils::InfoCompiler::with_avx2
bool with_avx2
Compiled with AVX2.
Definition: info.hpp:118
genesis::utils::info_process_current_file_count
size_t info_process_current_file_count()
Return the number of files (i.e., file descriptors) that the current process (the process calling thi...
Definition: info.cpp:1213
genesis::utils::read_id_from_file_
size_t read_id_from_file_(std::string const &filename)
Definition: info.cpp:959
genesis::utils::InfoHardware::vendor_AMD
bool vendor_AMD
Definition: info.hpp:165
genesis::utils::InfoHardware::HW_AVX512_VPCLMUL
bool HW_AVX512_VPCLMUL
Definition: info.hpp:241
genesis::utils::InfoHardware::HW_AES
bool HW_AES
Definition: info.hpp:199
genesis::utils::InfoHardware::HW_SSE42
bool HW_SSE42
Definition: info.hpp:197
genesis::utils::InfoHardware::HW_RDRAND
bool HW_RDRAND
Definition: info.hpp:181
genesis::utils::InfoHardware::OS_AVX512
bool OS_AVX512
Definition: info.hpp:175
genesis::utils::InfoHardware::HW_AVX512_VBMI
bool HW_AVX512_VBMI
Definition: info.hpp:224
genesis::utils::detect_OS_x64_
bool detect_OS_x64_()
Definition: info.cpp:493
genesis::utils::info_stderr_is_terminal
bool info_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: info.cpp:1163
genesis::utils::InfoHardware::HW_AVX512_VL
bool HW_AVX512_VL
Definition: info.hpp:218
genesis::utils::info_use_avx512
bool info_use_avx512()
Assess if it is safe to use AVX512 features.
Definition: info.cpp:919
genesis::utils::InfoHardware::HW_PREFETCHW
bool HW_PREFETCHW
Definition: info.hpp:187
genesis::utils::InfoHardware::HW_RDPID
bool HW_RDPID
Definition: info.hpp:189
genesis::utils::InfoCompiler
Definition: info.hpp:48
genesis::utils::info_print_hardware
std::string info_print_hardware(bool full)
Print information about hardware features to a string.
Definition: info.cpp:795
genesis::utils::InfoHardware::physical_core_count
size_t physical_core_count
Definition: info.hpp:169
genesis::utils::InfoHardware::HW_AVX2
bool HW_AVX2
Definition: info.hpp:207
genesis::utils::InfoHardware::HW_RDSEED
bool HW_RDSEED
Definition: info.hpp:182
genesis::utils::InfoCompiler::is_debug
bool is_debug
Binary was compiled with build type DEBUG.
Definition: info.hpp:61
genesis::utils::InfoHardware::HW_AVX512_VBMI2
bool HW_AVX512_VBMI2
Definition: info.hpp:238
genesis::utils::InfoHardware::HW_SHA
bool HW_SHA
Definition: info.hpp:200
genesis::utils::info_task_cpu_cores
unsigned int info_task_cpu_cores(bool physical=false)
Definition: info.cpp:934
genesis::utils::InfoCompiler::compiler_version
std::string compiler_version
Compiler version that was used to compile genesis.
Definition: info.hpp:92
genesis::utils::InfoHardware::HW_MPX
bool HW_MPX
Definition: info.hpp:186
genesis::utils::InfoHardware::HW_AVX512_DQ
bool HW_AVX512_DQ
Definition: info.hpp:220
genesis::utils::InfoHardware::HW_VAES
bool HW_VAES
Definition: info.hpp:240