MaCh3  2.2.3
Reference Guide
Monitor.cpp
Go to the documentation of this file.
1 #include "Manager/Monitor.h"
2 #include <unistd.h>
3 
4 //Only if GPU is enabled
5 #ifdef MaCh3_CUDA
6 #include "Manager/gpuUtils.cuh"
7 #endif
8 
9 namespace MaCh3Utils {
10 
11 // *************************
12 void MaCh3Welcome() {
13 // *************************
14  // KS: Just make sure we only call it once
15  static bool MaCh3WelcomeInitialised = false;
16 
17  if(MaCh3WelcomeInitialised) return;
18 
19  std::string MaCh3_VERSION = GetMaCh3Version();
20 
21  MACH3LOG_INFO("##################################");
22  MACH3LOG_INFO("Welcome to: ");
23  MACH3LOG_INFO(" __ __ _____ _ ____ ");
24  MACH3LOG_INFO(" | \\/ | / ____| | |___ \\ ");
25  MACH3LOG_INFO(" | \\ / | __ _| | | |__ __) |");
26  MACH3LOG_INFO(" | |\\/| |/ _` | | | '_ \\ |__ < ");
27  MACH3LOG_INFO(" | | | | (_| | |____| | | |___) |");
28  MACH3LOG_INFO(" |_| |_|\\__,_|\\_____|_| |_|____/ ");
29  MACH3LOG_INFO("Version: {}", MaCh3_VERSION);
30  MACH3LOG_INFO("##################################");
31 
32  GetCPUInfo();
33 
34  GetGPUInfo();
35 
36  #ifdef DEBUG
37  GetOSInfo();
38  GetDiskUsage();
39  #endif
40 
41  MaCh3WelcomeInitialised = true;
42 }
43 
44 // ************************
45 // KS: Get version of MaCh3
46 std::string GetMaCh3Version() {
47 // ************************
48  //KS: Find MaCh3 version based on header file. There could be better way to just include version.h but as long as we don't have to hardcode version I am content
49  std::string MaCh3_VERSION = "";
50 
51  if(std::getenv("MaCh3_ROOT") == nullptr){
52  throw MaCh3Exception(__FILE__, __LINE__, "Error: you haven't sourced setup.MaCh3.sh in core!");
53  }
54 
55  std::string file = std::string(std::getenv("MaCh3_ROOT")) + "/version.h";
56  // Open the version.h file
57  std::ifstream versionFile(file);
58 
59  // Check if the file is opened successfully
60  if (!versionFile.is_open()) {
61  MACH3LOG_ERROR("Error: Couldn't open version.h {}", file);
62  throw MaCh3Exception(__FILE__, __LINE__);
63  }
64 
65  std::string line;
66  const std::string searchKey = "MaCh3_VERSION=";
67 
68  // Read each line from the file
69  while (std::getline(versionFile, line)) {
70  // Search for the line containing MaCh3_VERSION
71  auto pos = line.find(searchKey);
72  if (pos != std::string::npos) {
73  // Extract the version string
74  MaCh3_VERSION = line.substr(pos + searchKey.length());
75  MaCh3_VERSION.erase(0, MaCh3_VERSION.find_first_not_of("\"")); // Remove leading quote
76  MaCh3_VERSION.erase(MaCh3_VERSION.find_last_not_of("\";") + 1); // Remove trailing quote and semicolon
77  break; // Stop searching once found
78  }
79  }
80  // Close the file
81  versionFile.close();
82 
83  return MaCh3_VERSION;
84 }
85 
86 // ************************
87 // KS: Find out more about operational system
88 void GetOSInfo() {
89 // ************************
90  MACH3LOG_INFO("Operating System Information:");
91 
92  // Distribution and version
93  MACH3LOG_INFO("Distribution: {}", TerminalToString("lsb_release -d | awk -F':' '{print $2}'"));
94  MACH3LOG_INFO("Kernel Version: {}", TerminalToString("uname -r"));
95 }
96 
97 // ************************
98 //KS: Simple function retrieving CPU info
99 void GetCPUInfo() {
100 // ************************
101  //KS: Use -m 1 to limit to only one grep because in one computing node there is a lot of CPU which are the same
102  MACH3LOG_INFO("Using following CPU:");
103 
104  MACH3LOG_INFO("{}", TerminalToString("cat /proc/cpuinfo | grep -m 1 name"));
105  MACH3LOG_INFO("{}", TerminalToString("cat /proc/cpuinfo | grep -m 1 MHz"));
106  //KS: Below code is convoluted because I mostly work on English based Linux but sometimes on Polish based Linux, this ensures it works on both. We can add support for other languages if needed
107  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -i Archit"));
108  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -m 1 -E 'L1d |L1d:'"));
109  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -m 1 -E 'L1i |L1i:'"));
110  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -m 1 -E 'L2 |L2:'"));
111  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -m 1 -E 'L3 |L3:'"));
112  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -m 1 -E 'Thread.* per core:|Wątków na rdzeń:'"));
113  MACH3LOG_INFO("{}", TerminalToString("lscpu | grep -m 1 -E '^CPU(:|\\(s\\)):?\\s+[0-9]+'"));
114  MACH3LOG_INFO("With available threads {}", M3::GetNThreads());
115 
116  NThreadsSanity();
117  //KS: /proc/cpuinfo and lscpu holds much more info I have limited it but one can expand it if needed
118 }
119 
120 
121 // ************************
123 // ************************
124  //KS: If OMP_NUM_THREADS is exported, assume user did this on purpose
125  if (std::getenv("OMP_NUM_THREADS") != nullptr) return;
126 
127  const int nThreads = M3::GetNThreads();
128  constexpr int MaxAllowedThreads = 16;
129  constexpr int RecommendedThreads = 8;
130 
131  if (nThreads > MaxAllowedThreads) {
132  MACH3LOG_CRITICAL("You specified more than {} threads ({})", MaxAllowedThreads, nThreads);
133  MACH3LOG_CRITICAL("With so many threads code will be slower, please use:");
134  MACH3LOG_CRITICAL("export OMP_NUM_THREADS={}", RecommendedThreads);
135  MACH3LOG_CRITICAL("To use different number of threads");
136  throw MaCh3Exception(__FILE__, __LINE__, "Too many threads");
137  }
138 }
139 
140 
141 // ************************
142 //KS: Simple function retrieving GPU info
143 void GetGPUInfo(){
144 // ************************
145 #ifdef MaCh3_CUDA
146  MACH3LOG_INFO("Using following GPU:");
147  // Print GPU name
148  MACH3LOG_INFO("GPU Name: {}", TerminalToString("nvidia-smi --query-gpu=name --format=csv,noheader"));
149  // Print number of GPUs
150  MACH3LOG_INFO("Number of GPUs: {}", TerminalToString("nvidia-smi --query-gpu=count --format=csv,noheader"));
151  // Print total VRAM
152  MACH3LOG_INFO("Total VRAM: {} MB", TerminalToString("nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits"));
153  // Print Driver Version
154  MACH3LOG_INFO("Driver Version: {}", TerminalToString("nvidia-smi --query-gpu=driver_version --format=csv,noheader"));
155  // Print N GPU thread
156  MACH3LOG_INFO("Currently used GPU has: {} threads", GetNumGPUThreads());
157  // Print L2 cache
158  MACH3LOG_INFO("Currently used GPU has: {} KB L2 cache", GetL2CacheSize() / 1024);
159  // Shared memory info
160  MACH3LOG_INFO("Max shared memory per block: {} KB", GetSharedMemoryPerBlock() / 1024);
161  // Print 1D texture size
162  MACH3LOG_INFO("Max 1D texture size: {}", GetMaxTexture1DSize());
163 #endif
164 }
165 
166 // ************************
167 // KS: Find out about Disk usage
168 void GetDiskUsage() {
169 // ************************
170  MACH3LOG_INFO("Disk Usage:");
171 
172  // Get disk usage
173  MACH3LOG_INFO("{}", TerminalToString("df -h --total | grep total"));
174 }
175 
176 // ************************
177 // KS: Convoluted code to grab output from terminal to string
178 std::string TerminalToString(std::string cmd) {
179 // ************************
180  std::array<char, 128> buffer;
181  std::string result;
182  std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
183  if (!pipe) {
184  throw MaCh3Exception(__FILE__, __LINE__, "popen() failed!");
185  }
186  while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
187  result += buffer.data();
188  }
189  // Remove trailing newline characters
190  result.erase(std::remove(result.begin(), result.end(), '\n'), result.end());
191  return result;
192 }
193 
194 // ************************
195 //KS: Simple to retrieve speed of get entry inspired by
196 void EstimateDataTransferRate(TChain* chain, const Long64_t entry){
197 // ************************
198  TStopwatch timer;
199 
200  timer.Start();
201  Int_t bytesProcessed{ chain->GetEntry(entry) };
202 
203  timer.Stop();
204 
205  Double_t timeInSeconds = timer.RealTime();
206  Double_t dataRateMBps = (double(bytesProcessed) / (1024.0 * 1024.0)) / timeInSeconds;
207 
208  MACH3LOG_INFO("Data transfer: {} B, rate: {:.2f} MB/s", bytesProcessed, dataRateMBps);
209 }
210 
211 // ************************
212 //KS: Simply print progress bar
213 void PrintProgressBar(const Long64_t Done, const Long64_t All) {
214 // ************************
215  double progress = double(Done)/double(All);
216  const int barWidth = 20;
217  std::ostringstream progressBar;
218 
219  progressBar << "[";
220  int pos = int(barWidth * progress);
221  for (int i = 0; i < barWidth; ++i) {
222  if (i < pos)
223  progressBar << "=";
224  else if (i == pos)
225  progressBar << ">";
226  else
227  progressBar << " ";
228  }
229 
230  progressBar << "] " << std::setw(3) << Done <<"/"<< All<<" ("<<static_cast<int>(progress * 100.0)<<"%)\r";
231  MACH3LOG_INFO("{}", progressBar.str());
232 }
233 
234 // ***************************************************************************
235 //CW: Get memory, which is probably silly
236 int getValue(const std::string& Type) { //Note: this value is in KB!
237 // ***************************************************************************
238  std::ifstream file("/proc/self/status");
239  int result = -1;
240  std::string line;
241 
242  if (Type == "VmSize")
243  {
244  while (std::getline(file, line))
245  {
246  if (line.compare(0, 7, "VmSize:") == 0)
247  {
248  result = parseLine(line.substr(7));
249  break;
250  }
251  }
252  }
253  else if (Type == "VmRSS")
254  {
255  while (std::getline(file, line))
256  {
257  if (line.compare(0, 6, "VmRSS:") == 0)
258  {
259  result = parseLine(line.substr(6));
260  break;
261  }
262  }
263  }
264  else if (Type == "MemTotal")
265  {
266  std::ifstream meminfo("/proc/meminfo");
267  while (std::getline(meminfo, line))
268  {
269  if (line.find("MemTotal:") != std::string::npos) {
270  result = parseLine(line.substr(9));
271  break;
272  }
273  }
274  }
275  else
276  {
277  MACH3LOG_ERROR("Not supported getValue: {}", Type);
278  throw MaCh3Exception(__FILE__, __LINE__);
279  }
280  return result;
281 }
282 
283 // ***************************************************************************
284 //CW: Get memory, which is probably silly
285 int parseLine(const std::string& line){
286 // ***************************************************************************
287  std::istringstream iss(line);
288  int value;
289  iss >> value;
290  return value;
291 }
292 
293 // ***************************************************************************
294 //KS: Print Yaml config using logger
295 void PrintConfig(const YAML::Node& node){
296 // ***************************************************************************
297  std::stringstream ss;
298  ss << node;
299  std::string yamlString = ss.str();
300 
301  std::istringstream iss(yamlString);
302  std::string line;
303  while (std::getline(iss, line)) {
304  MACH3LOG_INFO("{}", line);
305  }
306 }
307 
308 // ***************************************************************************
309 //KS: Print content of TFile using logger
310 void Print(const TTree* tree) {
311 // ***************************************************************************
312  if (!tree) return;
313 
314  // Create a temporary file to capture stdout
315  FILE* tmpFile = tmpfile();
316  if (!tmpFile) return;
317 
318  // Save old stdout
319  int oldStdout = dup(fileno(stdout));
320  // Redirect stdout to tmpFile
321  dup2(fileno(tmpFile), fileno(stdout));
322 
323  tree->Print(); // ROOT writes to stdout
324 
325  fflush(stdout);
326  // Restore old stdout
327  dup2(oldStdout, fileno(stdout));
328  close(oldStdout);
329 
330  // Read tmpFile content
331  fseek(tmpFile, 0, SEEK_SET);
332  char buffer[1024];
333  while (fgets(buffer, sizeof(buffer), tmpFile)) {
334  std::string line(buffer);
335  if (!line.empty() && line.back() == '\n') line.pop_back();
336  MACH3LOG_INFO("{}", line);
337  }
338 
339  fclose(tmpFile);
340 }
341 
342 // ***************************************************************************
343 //KS: Almost all MaCh3 executables have the same usage, prepare simple printer
344 void MaCh3Usage(int argc, char **argv) {
345 // ***************************************************************************
346  if (argc != 2) {
347  MACH3LOG_ERROR("Wrong usage of MaCh3 executable!");
348  MACH3LOG_ERROR("Syntax is $: {} config.yaml", argv[0]);
349  MACH3LOG_ERROR("Where config.yaml is a valid config file, compatible with the manager class (manager/manager.cpp/h)");
350  throw MaCh3Exception(__FILE__, __LINE__);
351  }
352 }
353 } //end namespace
354 
355 namespace M3 {
356 // ***************************************************************************
357 int GetNThreads() {
358 // ***************************************************************************
359  #ifdef MULTITHREAD
360  return omp_get_max_threads();
361  #else
362  return 1;
363  #endif
364 }
365 
366 // ***************************************************************************
367 void AddPath(std::string& FilePath) {
368 // ***************************************************************************
369  //KS:Most inputs are in ${MACH3}/inputs/blarb.root
370  if (std::getenv("MACH3") == nullptr) {
371  MACH3LOG_ERROR("MACH3 is not defined");
372  MACH3LOG_ERROR("Please source your setup script");
373  MACH3LOG_ERROR("Read more: https://github.com/mach3-software/MaCh3/wiki/0.-FAQ#error-need-mach3-environment-variable");
374  throw MaCh3Exception(__FILE__, __LINE__);
375  }
376 
377  std::string MaCh3Path = std::string(std::getenv("MACH3")) + "/";
378  // Check if FilePath does NOT start with MaCh3Path
379  if (FilePath.find(MaCh3Path) != 0) {
380  FilePath.insert(0, MaCh3Path);
381  }
382 }
383 } //end namespace
384 
#define MACH3LOG_CRITICAL
Definition: MaCh3Logger.h:28
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:27
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:25
System and monitoring utilities for printing system information and status updates.
Custom exception class for MaCh3 errors.
size_t GetMaxTexture1DSize(const int device)
KS: Get the maximum size for 1D textures on the specified GPU device.
Definition: gpuUtils.cu:134
int GetNumGPUThreads(const int Device)
KS: Get number of GPU threads for currently used GPU.
Definition: gpuUtils.cu:102
size_t GetL2CacheSize(const int device)
KS: Get L2 cache size (in bytes) for the specified GPU device.
Definition: gpuUtils.cu:122
size_t GetSharedMemoryPerBlock(const int device)
KS: Returns the maximum shared memory per block for a given GPU device.
Definition: gpuUtils.cu:146
Common CUDA utilities and definitions for shared GPU functionality.
Definition: Core.h:19
int GetNThreads()
number of threads which we need for example for TRandom3
Definition: Monitor.cpp:357
void AddPath(std::string &FilePath)
Prepends the MACH3 environment path to FilePath if it is not already present.
Definition: Monitor.cpp:367
void GetOSInfo()
KS: Find out more about operational system.
Definition: Monitor.cpp:88
std::string TerminalToString(std::string cmd)
KS: Convoluted code to grab output from terminal to string.
Definition: Monitor.cpp:178
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:213
std::string GetMaCh3Version()
KS: Get version of MaCh3.
Definition: Monitor.cpp:46
void Print(const TTree *tree)
Definition: Monitor.cpp:310
void GetDiskUsage()
KS: Find out about Disk usage.
Definition: Monitor.cpp:168
void NThreadsSanity()
KS: Check if user is not using huge number of threads and throw error.
Definition: Monitor.cpp:122
void GetCPUInfo()
KS: Check what CPU you are using.
Definition: Monitor.cpp:99
void GetGPUInfo()
KS: Check what GPU you are using.
Definition: Monitor.cpp:143
int getValue(const std::string &Type)
CW: Get info like RAM.
Definition: Monitor.cpp:236
void PrintConfig(const YAML::Node &node)
KS: Print Yaml config using logger.
Definition: Monitor.cpp:295
void MaCh3Usage(int argc, char **argv)
KS: Almost all MaCh3 executables have the same usage, prepare simple printer.
Definition: Monitor.cpp:344
void MaCh3Welcome()
KS: Prints welcome message with MaCh3 logo.
Definition: Monitor.cpp:12
int parseLine(const std::string &line)
CW: Get memory, which is probably silly.
Definition: Monitor.cpp:285
void EstimateDataTransferRate(TChain *chain, const Long64_t entry)
KS: Check what CPU you are using.
Definition: Monitor.cpp:196