Processor Counter Monitor
utils.h
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 // Copyright (c) 2009-2020, Intel Corporation
3 // written by Roman Dementiev
4 
5 
10 #pragma once
11 
12 #include <cstdio>
13 #include <cstring>
14 #include <fstream>
15 #include <time.h>
16 #include "types.h"
17 #include <vector>
18 #include <chrono>
19 #include <math.h>
20 #include <assert.h>
21 
22 #ifndef _MSC_VER
23 #include <csignal>
24 #include <ctime>
25 #include <cmath>
26 #else
27 #include <intrin.h>
28 #endif
29 
30 namespace pcm {
31 
32 #ifdef _MSC_VER
33  using tstring = std::basic_string<TCHAR>;
34 #ifdef UNICODE
35  static auto& tcerr = std::wcerr;
36 #else
37  static auto& tcerr = std::cerr;
38 #endif
39 #endif // _MSC_VER
40 
41 typedef void (* print_usage_func)(const std::string & progname);
42 double parse_delay(const char * arg, const std::string & progname, print_usage_func print_usage_func);
43 bool extract_argument_value(const char * arg, std::initializer_list<const char*> arg_names, std::string & value);
44 bool check_argument_equals(const char * arg, std::initializer_list<const char*> arg_names);
45 
46 void exit_cleanup(void);
47 void set_signal_handlers(void);
48 void set_real_time_priority(const bool & silent);
49 void restore_signal_handlers(void);
50 #ifndef _MSC_VER
51 void sigINT_handler(int signum);
52 void sigHUP_handler(int signum);
53 void sigUSR_handler(int signum);
54 void sigSTOP_handler(int signum);
55 void sigCONT_handler(int signum);
56 #endif
57 
58 void set_post_cleanup_callback(void(*cb)(void));
59 
60 inline void MySleep(int delay)
61 {
62 #ifdef _MSC_VER
63  if (delay) Sleep(delay * 1000);
64 #else
65  ::sleep(delay);
66 #endif
67 }
68 
69 inline void MySleepMs(int delay_ms)
70 {
71 #ifdef _MSC_VER
72  if (delay_ms) Sleep((DWORD)delay_ms);
73 #else
74  struct timespec sleep_intrval;
75  double complete_seconds;
76  sleep_intrval.tv_nsec = static_cast<long>(1000000000.0 * (::modf(delay_ms / 1000.0, &complete_seconds)));
77  sleep_intrval.tv_sec = static_cast<time_t>(complete_seconds);
78  ::nanosleep(&sleep_intrval, NULL);
79 #endif
80 }
81 
82 void MySystem(char * sysCmd, char ** argc);
83 
84 #ifdef _MSC_VER
85 #pragma warning (disable : 4068 ) // disable unknown pragma warning
86 #endif
87 
88 #ifdef __GCC__
89 #pragma GCC diagnostic push
90 #pragma GCC diagnostic ignored "-Woverloaded-virtual"
91 #elif defined __clang__
92 #pragma clang diagnostic push
93 #pragma clang diagnostic ignored "-Woverloaded-virtual"
94 #endif
95 struct null_stream : public std::streambuf
96 {
97  int_type overflow(int_type) override { return {}; }
98 };
99 #ifdef __GCC__
100 #pragma GCC diagnostic pop
101 #elif defined __clang__
102 #pragma clang diagnostic pop
103 #endif
104 
105 template <class IntType>
106 inline std::string unit_format(IntType n)
107 {
108  char buffer[1024];
109  if (n <= 9999ULL)
110  {
111  snprintf(buffer, 1024, "%4d ", int32(n));
112  return std::string{buffer};
113  }
114  if (n <= 9999999ULL)
115  {
116  snprintf(buffer, 1024, "%4d K", int32(n / 1000ULL));
117  return std::string{buffer};
118  }
119  if (n <= 9999999999ULL)
120  {
121  snprintf(buffer, 1024, "%4d M", int32(n / 1000000ULL));
122  return std::string{buffer};
123  }
124  if (n <= 9999999999999ULL)
125  {
126  snprintf(buffer, 1024, "%4d G", int32(n / 1000000000ULL));
127  return std::string{buffer};
128  }
129 
130  snprintf(buffer, 1024, "%4d T", int32(n / (1000000000ULL * 1000ULL)));
131  return std::string{buffer};
132 }
133 
134 void print_cpu_details();
135 
136 #define PCM_UNUSED(x) (void)(x)
137 
138 #define PCM_COMPILE_ASSERT(condition) \
139  typedef char pcm_compile_assert_failed[(condition) ? 1 : -1]; \
140  pcm_compile_assert_failed pcm_compile_assert_failed_; \
141  PCM_UNUSED(pcm_compile_assert_failed_);
142 
143 #ifdef _MSC_VER
144 class ThreadGroupTempAffinity
145 {
146  GROUP_AFFINITY PreviousGroupAffinity;
147  bool restore;
148 
149  ThreadGroupTempAffinity(); // forbidden
150  ThreadGroupTempAffinity(const ThreadGroupTempAffinity &); // forbidden
151  ThreadGroupTempAffinity & operator = (const ThreadGroupTempAffinity &); // forbidden
152 
153 public:
154  ThreadGroupTempAffinity(uint32 core_id, bool checkStatus = true, const bool restore_ = false);
155  ~ThreadGroupTempAffinity();
156 };
157 #endif
158 
159 class checked_uint64 // uint64 with checking for overflows when computing differences
160 {
161  uint64 data;
162  uint64 overflows;
163 public:
164  checked_uint64() : data(0), overflows(0) {}
165  checked_uint64(const uint64 d, const uint64 o) : data(d), overflows(o) {}
166  const checked_uint64& operator += (const checked_uint64& o)
167  {
168  data += o.data;
169  overflows += o.overflows;
170  return *this;
171  }
172 
173  uint64 operator - (const checked_uint64& o) const
174  {
175  // computing data - o.data
176  constexpr uint64 counter_width = 48;
177  return data + overflows * (1ULL << counter_width) - o.data;
178  }
179 
180  uint64 getRawData_NoOverflowProtection() const { return data; }
181 };
182 
183 // a secure (but partial) alternative for sscanf
184 // see example usage in pcm-core.cpp
185 typedef std::istringstream pcm_sscanf;
186 
187 class s_expect : public std::string
188 {
189 public:
190  explicit s_expect(const char * s) : std::string(s) {}
191  explicit s_expect(const std::string & s) : std::string(s) {}
192  friend std::istream & operator >> (std::istream & istr, s_expect && s);
193  friend std::istream & operator >> (std::istream && istr, s_expect && s);
194 private:
195 
196  void match(std::istream & istr) const
197  {
198  istr >> std::noskipws;
199  const auto len = length();
200  char * buffer = new char[len + 2];
201  buffer[0] = 0;
202  istr.get(buffer, len+1);
203  if (*this != std::string(buffer))
204  {
205  istr.setstate(std::ios_base::failbit);
206  }
207  delete [] buffer;
208  }
209 };
210 
211 inline std::istream & operator >> (std::istream & istr, s_expect && s)
212 {
213  s.match(istr);
214  return istr;
215 }
216 
217 inline std::istream & operator >> (std::istream && istr, s_expect && s)
218 {
219  s.match(istr);
220  return istr;
221 }
222 
223 inline std::pair<tm, uint64> pcm_localtime() // returns <tm, milliseconds>
224 {
225  const auto durationSinceEpoch = std::chrono::system_clock::now().time_since_epoch();
226  const auto durationSinceEpochInSeconds = std::chrono::duration_cast<std::chrono::seconds>(durationSinceEpoch);
227  time_t now = durationSinceEpochInSeconds.count();
228  tm result;
229 #ifdef _MSC_VER
230  localtime_s(&result, &now);
231 #else
232  localtime_r(&now, &result);
233 #endif
234  return std::make_pair(result, std::chrono::duration_cast<std::chrono::milliseconds>(durationSinceEpoch- durationSinceEpochInSeconds).count());
235 }
236 
237 enum CsvOutputType
238 {
239  Header1,
240  Header2,
241  Data,
242  Header21, // merged headers 2 and 1
243  Json
244 };
245 
246 template <class H1, class H2, class D>
247 inline void choose(const CsvOutputType outputType, H1 h1Func, H2 h2Func, D dataFunc)
248 {
249  switch (outputType)
250  {
251  case Header1:
252  case Header21:
253  h1Func();
254  break;
255  case Header2:
256  h2Func();
257  break;
258  case Data:
259  case Json:
260  dataFunc();
261  break;
262  default:
263  std::cerr << "PCM internal error: wrong CSvOutputType\n";
264  }
265 }
266 
267 inline void printDateForCSV(const CsvOutputType outputType, std::string separator = std::string(","))
268 {
269  choose(outputType,
270  [&separator]() {
271  std::cout << separator << separator; // Time
272  },
273  [&separator]() {
274  std::cout << "Date" << separator << "Time" << separator;
275  },
276  [&separator]() {
277  std::pair<tm, uint64> tt{ pcm_localtime() };
278  std::cout.precision(3);
279  char old_fill = std::cout.fill('0');
280  std::cout <<
281  std::setw(4) << 1900 + tt.first.tm_year << '-' <<
282  std::setw(2) << 1 + tt.first.tm_mon << '-' <<
283  std::setw(2) << tt.first.tm_mday << separator <<
284  std::setw(2) << tt.first.tm_hour << ':' <<
285  std::setw(2) << tt.first.tm_min << ':' <<
286  std::setw(2) << tt.first.tm_sec << '.' <<
287  std::setw(3) << tt.second << separator; // milliseconds
288  std::cout.fill(old_fill);
289  std::cout.setf(std::ios::fixed);
290  std::cout.precision(2);
291  });
292 }
293 
294 inline void printDateForJson(const std::string& separator, const std::string &jsonSeparator)
295 {
296  std::pair<tm, uint64> tt{ pcm_localtime() };
297  std::cout.precision(3);
298  char old_fill = std::cout.fill('0');
299  std::cout <<
300  "Date" << jsonSeparator << "\"" <<
301  std::setw(4) << 1900 + tt.first.tm_year << '-' <<
302  std::setw(2) << 1 + tt.first.tm_mon << '-' <<
303  std::setw(2) << tt.first.tm_mday << "\"" << separator <<
304  "Time" << jsonSeparator << "\"" <<
305  std::setw(2) << tt.first.tm_hour << ':' <<
306  std::setw(2) << tt.first.tm_min << ':' <<
307  std::setw(2) << tt.first.tm_sec << '.' <<
308  std::setw(3) << tt.second << "\"" << separator; // milliseconds
309  std::cout.fill(old_fill);
310  std::cout.setf(std::ios::fixed);
311  std::cout.precision(2);
312 }
313 
314 std::vector<std::string> split(const std::string & str, const char delim);
315 
316 class PCM;
317 bool CheckAndForceRTMAbortMode(const char * argv, PCM * m);
318 
319 void print_help_force_rtm_abort_mode(const int alignment);
320 
321 template <class F>
322 void parseParam(int argc, char* argv[], const char* param, F f)
323 {
324  if (argc > 1) do
325  {
326  argv++;
327  argc--;
328  if ((std::string("-") + param == *argv) || (std::string("/") + param == *argv))
329  {
330  argv++;
331  argc--;
332  if (argc == 0)
333  {
334  std::cerr << "ERROR: no parameter provided for option " << param << "\n";
335  exit(EXIT_FAILURE);
336  }
337  f(*argv);
338  continue;
339  }
340  } while (argc > 1); // end of command line parsing loop
341 }
342 
343 class MainLoop
344 {
345  unsigned numberOfIterations = 0;
346 public:
347  MainLoop() {}
348  bool parseArg(const char * arg)
349  {
350  std::string arg_value;
351  if (extract_argument_value(arg, {"-i", "/i"}, arg_value))
352  {
353  numberOfIterations = (unsigned int)atoi(arg_value.c_str());
354  return true;
355  }
356 
357  return false;
358  }
359  unsigned getNumberOfIterations() const
360  {
361  return numberOfIterations;
362  }
363  template <class Body>
364  void operator ()(const Body & body)
365  {
366  unsigned int i = 1;
367  // std::cerr << "DEBUG: numberOfIterations: " << numberOfIterations << "\n";
368  while ((i <= numberOfIterations) || (numberOfIterations == 0))
369  {
370  if (body() == false)
371  {
372  break;
373  }
374  ++i;
375  }
376  }
377 };
378 
379 #ifdef __linux__
380 FILE * tryOpen(const char * path, const char * mode);
381 std::string readSysFS(const char * path, bool silent);
382 bool writeSysFS(const char * path, const std::string & value, bool silent);
383 #endif
384 
385 int calibratedSleep(const double delay, const char* sysCmd, const MainLoop& mainLoop, PCM* m);
386 
388  double fraction{0.0};
389  std::string label{""}; // not used currently
390  char fill{'0'};
391  StackedBarItem() {}
392  StackedBarItem(double fraction_,
393  const std::string & label_,
394  char fill_) : fraction(fraction_), label(label_), fill(fill_) {}
395 };
396 
397 void drawStackedBar(const std::string & label, std::vector<StackedBarItem> & h, const int width = 80);
398 
399 // emulates scanf %i for hex 0x prefix otherwise assumes dec (no oct support)
400 bool match(const std::string& subtoken, const std::string& sname, uint64* result);
401 
402 uint64 read_number(const char* str);
403 
405 {
406  int array[4];
407  struct { unsigned int eax, ebx, ecx, edx; } reg;
408 };
409 
410 inline void pcm_cpuid(int leaf, PCM_CPUID_INFO& info)
411 {
412 #ifdef _MSC_VER
413  // version for Windows
414  __cpuid(info.array, leaf);
415 #else
416  __asm__ __volatile__("cpuid" : \
417  "=a" (info.reg.eax), "=b" (info.reg.ebx), "=c" (info.reg.ecx), "=d" (info.reg.edx) : "a" (leaf));
418 #endif
419 }
420 
421 inline void clear_screen() {
422 #ifdef _MSC_VER
423  system("cls");
424 #else
425  std::cout << "\033[2J\033[0;0H";
426 #endif
427 }
428 
429 inline uint32 build_bit_ui(uint32 beg, uint32 end)
430 {
431  assert(end <= 31);
432  uint32 myll = 0;
433  if (end == 31)
434  {
435  myll = (uint32)(-1);
436  }
437  else
438  {
439  myll = (1 << (end + 1)) - 1;
440  }
441  myll = myll >> beg;
442  return myll;
443 }
444 
445 inline uint32 extract_bits_ui(uint32 myin, uint32 beg, uint32 end)
446 {
447  uint32 myll = 0;
448  uint32 beg1, end1;
449 
450  // Let the user reverse the order of beg & end.
451  if (beg <= end)
452  {
453  beg1 = beg;
454  end1 = end;
455  }
456  else
457  {
458  beg1 = end;
459  end1 = beg;
460  }
461  myll = myin >> beg1;
462  myll = myll & build_bit_ui(beg1, end1);
463  return myll;
464 }
465 
466 inline uint64 build_bit(uint32 beg, uint32 end)
467 {
468  uint64 myll = 0;
469  if (end == 63)
470  {
471  myll = static_cast<uint64>(-1);
472  }
473  else
474  {
475  myll = (1LL << (end + 1)) - 1;
476  }
477  myll = myll >> beg;
478  return myll;
479 }
480 
481 inline uint64 extract_bits(uint64 myin, uint32 beg, uint32 end)
482 {
483  uint64 myll = 0;
484  uint32 beg1, end1;
485 
486  // Let the user reverse the order of beg & end.
487  if (beg <= end)
488  {
489  beg1 = beg;
490  end1 = end;
491  }
492  else
493  {
494  beg1 = end;
495  end1 = beg;
496  }
497  myll = myin >> beg1;
498  myll = myll & build_bit(beg1, end1);
499  return myll;
500 }
501 
502 std::string safe_getenv(const char* env);
503 
504 #ifdef _MSC_VER
505 inline HANDLE openMSRDriver()
506 {
507  return CreateFile(TEXT("\\\\.\\RDMSR"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
508 }
509 #endif
510 
511 // called before everything else to read '-s' arg and
512 // silence all following err output
513 void check_and_set_silent(int argc, char * argv[], null_stream &nullStream2);
514 
515 void print_pid_collection_message(int pid);
516 
517 inline bool isPIDOption(char * argv [])
518 {
519  return check_argument_equals(*argv, {"-pid", "/pid"});
520 }
521 
522 inline void parsePID(int argc, char* argv[], int& pid)
523 {
524  parseParam(argc, argv, "pid", [&pid](const char* p) { if (p) pid = atoi(p); });
525 }
526 } // namespace pcm
Internal type and constant definitions.
Definition: utils.h:95
CPU Performance Monitor.
Definition: cpucounters.h:543
Definition: bw.cpp:12
Definition: utils.h:387
Definition: utils.h:187
Definition: utils.h:404
Definition: utils.h:159
Definition: pcm-iio.cpp:146
Definition: utils.h:343