GooFit  v2.1.3
Application.cpp
Go to the documentation of this file.
1 #include <goofit/Application.h>
3 #include <goofit/Version.h>
4 
5 #include <thrust/detail/config/device_system.h>
6 
7 #ifndef _MSC_VER
8 #include <x86/cpu_x86.h>
9 #endif
10 
11 #ifdef GOOFIT_MPI
12 #include <mpi.h>
13 #endif
14 
15 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
16 #include <cuda_runtime.h>
17 #endif
18 
19 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_OMP || THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_TBB
20 #include <omp.h>
21 #endif
22 
23 namespace GooFit {
24 
25 void signal_handler(int s) {
26  std::cout << std::endl << reset << red << bold;
27  std::cout << "GooFit: Control-C detected, exiting..." << reset << std::endl;
28  std::exit(1);
29 }
30 
31 void print_splash() {
32  std::cout << reset << green << " Welcome to";
33 #if GOOFIT_SPLASH
34  // Just in case, for clang format:
35  // clang-format off
36  std::string splash = R"raw(
37  ██████╗ ████████╗
38  ██╔════╝ █████╗ █████╗ ██╔═════╝ ██╗
39  ██║ ███╗██╔══██╗██╔══██╗█████╗██╗██████╗
40  ██║ ██║██║ ██║██║ ██║██╔══╝██║╚═██╔═╝
41  ╚██████╔╝╚█████╔╝╚█████╔╝██║ ██║ ██║
42  ╚═════╝ ╚════╝ ╚════╝ ╚═╝ ╚═╝ ██║
43  ███████║
44  ╚══════╝
45  )raw";
46  // clang-format on
47 
48  std::cout << reset << dim;
49  bool cur_green = false;
50  for(int i = 0; i < splash.size(); i++) {
51  std::string letter = splash.substr(i, 3);
52  bool is_edge
53  = letter == "╚" || letter == "╝" || letter == "╗" || letter == "╔" || letter == "║" || letter == "═";
54  bool is_block = letter == "█";
55 
56  if(is_block && !cur_green) {
57  std::cout << reset << green;
58  cur_green = true;
59  } else if(is_edge && cur_green) {
60  std::cout << reset << dim;
61  cur_green = false;
62  }
63  std::cout << splash[i];
64  if(splash[i] == '\n')
65  std::cout << std::flush;
66  }
67 #else
68  std::cout << " GooFit\n";
69 #endif
70 
71  std::cout << reset << std::flush;
72 }
73 
74 void print_goofit_info(int gpuDev_) {
75  GOOFIT_INFO("GooFit: Version {} ({}) Commit: {}", GOOFIT_VERSION, GOOFIT_TAG, GOOFIT_GIT_VERSION);
76 
77 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
78  cudaDeviceProp devProp;
79  cudaGetDeviceProperties(&devProp, gpuDev_);
80 
81  GOOFIT_INFO("CUDA: Device {}: {}", gpuDev_, devProp.name);
82 
83  GOOFIT_INFO("CUDA: Compute {}.{}", devProp.major, devProp.minor);
84  GOOFIT_INFO("CUDA: Total global memory: {} GB", devProp.totalGlobalMem / 1.0e9);
85  GOOFIT_INFO("CUDA: Multiprocessors: {}", devProp.multiProcessorCount);
86 
87  GOOFIT_DEBUG("CUDA: Total amount of shared memory per block: {}", devProp.sharedMemPerBlock);
88  GOOFIT_DEBUG("CUDA: Total registers per block: {}", devProp.regsPerBlock);
89  GOOFIT_DEBUG("CUDA: Warp size: {}", devProp.warpSize);
90  GOOFIT_DEBUG("CUDA: Maximum memory pitch: {}", devProp.memPitch);
91  GOOFIT_DEBUG("CUDA: Total amount of constant memory: {}", devProp.totalConstMem);
92 
93 #elif THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_OMP
94  GOOFIT_INFO("OMP: Number of threads: {}", omp_get_max_threads());
95 #elif THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_TBB
96  GOOFIT_INFO("TBB: Backend selected");
97 #elif THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CPP
98  GOOFIT_INFO("CPP: Single threaded mode");
99 #endif
100 
101 #if GOOFIT_ROOT_FOUND
102  GOOFIT_INFO("ROOT: Found");
103 #else
104  GOOFIT_INFO("ROOT: Not found");
105 #endif
106 
107  // Print out warnings if not fully optimized
108  std::cout << red;
109  FeatureDetector::cpu_x86::print_warnings();
110  std::cout << GooFit::reset << std::flush;
111 
112 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
113  int deviceCount;
114  cudaGetDeviceCount(&deviceCount);
115 
116  for(int i = 0; i < deviceCount; i++) {
117  cudaDeviceProp deviceProp;
118  cudaGetDeviceProperties(&deviceProp, i);
119  GOOFIT_INFO("CUDA: Device {} has compute capability {}.{}", i, deviceProp.major, deviceProp.minor);
120  }
121 #endif
122 }
123 
124 Application::Application(std::string discription, int argc, char **argv)
125  : App(discription)
126  , argc_(argc)
127  , argv_(argv) {
128 #ifdef GOOFIT_MPI
129  MPI_Init(&argc_, &argv_);
130 
131  int myId, numProcs;
132  MPI_Comm_size(MPI_COMM_WORLD, &numProcs);
133  MPI_Comm_rank(MPI_COMM_WORLD, &myId);
134 
135 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
136  int deviceCount;
137  cudaGetDeviceCount(&deviceCount);
138 
139  // Get Batch system number of nodes if possible
140  auto PBS_NUM_NODES = getenv("PBS_NUM_NODES");
141 
142  int nodes = PBS_NUM_NODES == nullptr ? 1 : atoi(PBS_NUM_NODES);
143 
144  if(nodes == 0)
145  nodes = 1;
146 
147  int procsPerNode = numProcs / nodes;
148  int localRank = myId % procsPerNode;
149 
150  // Note, this will (probably) be overwritten by gpu-set-device calls...
151  if(deviceCount == 1 && localRank > 1) {
152  // Multi-process to one GPU!
153  gpuDev_ = 0;
154  } else if(procsPerNode > 1 && deviceCount > 1) {
155  if(localRank <= deviceCount) {
156  // setting multiple processes to multiple GPU's
157  gpuDev_ = localRank;
158  } else {
159  // More multiple processes than GPU's, distribute sort of evenly!
160  gpuDev_ = localRank % deviceCount;
161  }
162  } else {
163  // multiple GPU's, using one process
164  gpuDev_ = 0;
165  }
166 
167  std::cout << "MPI using CUDA device: " << gpuDev_ << std::endl;
168  cudaSetDevice(gpuDev_);
169 #endif
170 #endif
171 
172  // Fallthrough is useful for most models of GooFit subcommands
173  fallthrough();
174 
175 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
176 #ifndef GOOFIT_MPI
177  add_option("--gpu-dev", gpuDev_, "GPU device to use", true)->group("GooFit");
178 #endif
179  add_flag("--show-gpus", show_gpus_, "Show the available GPU devices and exit")->group("GooFit");
180 #endif
181  auto quiet = add_flag("-q,--quiet", quiet_, "Reduce the verbosity of the Application")->group("GooFit");
182 
183  add_flag("--nosplash", splash_, "Do not print a splash")->group("GooFit")->excludes(quiet);
184 
185  set_config("--config", "config.ini", "An ini file with command line options in it")->group("GooFit");
186 
187  // Reset color on exit (but not control-c)
188  std::atexit([]() { std::cout << GooFit::reset; });
189 
190 #ifndef _MSC_VER
191  sigIntHandler.sa_handler = signal_handler;
192  sigemptyset(&sigIntHandler.sa_mask);
193  sigIntHandler.sa_flags = 0;
194  sigaction(SIGINT, &sigIntHandler, nullptr);
195 #endif
196 }
197 
199  set_device();
200 
201  if(!quiet_) {
202  if(!splash_)
203  print_splash();
205  }
206 }
207 
209 #if THRUST_DEVICE_SYSTEM == THRUST_DEVICE_SYSTEM_CUDA
210  if(gpuDev_ != 0) {
211  cudaSetDevice(gpuDev_);
212  }
213 #endif
214 }
215 
216 int Application::exit(const CLI::Error &e) {
217 #ifdef GOOFIT_MPI
218  int myId;
219  MPI_Comm_rank(MPI_COMM_WORLD, &myId);
220 
221  if(myId > 0)
222  return e.get_exit_code();
223 
224 #endif
225  std::cout << (e.get_exit_code() == 0 ? blue : red);
226  int rval = CLI::App::exit(e);
227  std::cout << GooFit::reset;
228  return rval;
229 }
230 
231 #ifdef GOOFIT_MPI
233  // Only specialized finalize if MPI is present
234  MPI_Finalize();
235 }
236 #else
237 Application::~Application() = default;
238 #endif
239 
240 std::string Application::get_filename(const std::string &input_str, std::string base) const {
241  // Run from current directory
242  if(CLI::ExistingFile(input_str).empty())
243  return input_str;
244 
245  // Run from a different directory
246  std::string prog_name{argv_[0]};
247  size_t loc = prog_name.rfind("/");
248  if(loc != std::string::npos) {
249  std::string cdir = prog_name.substr(0, loc);
250  std::string new_input{cdir + "/" + input_str};
251  if(CLI::ExistingFile(new_input).empty()) {
252  std::cout << "Found file at " << new_input << std::endl;
253  return new_input;
254  }
255  }
256 
257  // If all else fails, try to get file from source directory (if base is specified)
258  if(base.size() > 0) {
259  std::string new_input = std::string(GOOFIT_SOURCE_DIR) + "/" + base + "/" + input_str;
260  if(CLI::ExistingFile(new_input).empty()) {
261  std::cout << "Found file at " << new_input << std::endl;
262  return new_input;
263  }
264  }
265 
266  // Could not find file
267  throw GooFit::FileError(input_str);
268 }
269 
270 } // namespace GooFit
void set_device() const
void signal_handler(int s)
will call the correct exit func, no unwinding of the stack though
Definition: Application.cpp:25
~Application() override
Cleanup MPI if needed.
#define GOOFIT_INFO(...)
Definition: Log.h:10
void print_splash()
Definition: Application.cpp:31
void print_goofit_info(int gpuDev_=0)
Print out information about GooFit.
Definition: Application.cpp:74
struct sigaction sigIntHandler
Handle control-c codes.
Definition: Application.h:52
constexpr rang::style const bold
Definition: Color.h:17
constexpr rang::fg const blue
Definition: Color.h:12
constexpr rang::fg const red
Definition: Color.h:9
int exit(const CLI::Error &e)
Exit.
void pre_callback() override
Gets called in parse.
#define GOOFIT_DEBUG(...)
Definition: Log.h:96
Application(std::string discription, int argc, char **argv)
Make a new Application.
constexpr rang::style const dim
Definition: Color.h:18
constexpr rang::style const reset
Definition: Color.h:16
constexpr rang::fg const green
Definition: Color.h:10
std::string get_filename(const std::string &input_str, std::string base="") const