Enigma  3.2.0
A Simple, Reliable and Efficient Encryption Tool
CPUInfo.hpp
Go to the documentation of this file.
1 #pragma once
2 #ifndef ENIGMA_CPU_INFO_H
3 #define ENIGMA_CPU_INFO_H
4 
5 
6 #include <Core/Core.hpp>
7 #include <Logger/Logger.hpp>
8 
9 #if defined(ENIGMA_PLATFORM_WINDOWS)
10 // Windows Includes
11 #include <Windows.h>
12 #elif defined(ENIGMA_PLATFORM_LINUX)
13 // Linux Includes
14 #include <cstdio>
15 #include <cstdlib>
16 #include <cstring>
17 #include <sys/times.h>
18 #elif defined(ENIGMA_PLATFORM_MACOS)
19 // MacOS Includes
20 #include <mach/mach_error.h>
21 #include <mach/mach_host.h>
22 #include <mach/mach_init.h>
23 #include <mach/vm_map.h>
24 #endif
25 
30 class CPUInfo {
31  public:
32  CPUInfo() noexcept;
33  ~CPUInfo() noexcept = default;
34 
37 
38 
39  public:
43  float GetCPUUsage() noexcept;
44 
48  float GetProcessCPUUsage() noexcept;
49 
50  private:
51 #if defined(ENIGMA_PLATFORM_WINDOWS) || defined(ENIGMA_PLATFORM_MACOS)
55  float CalculateCPULoad(const std::uint64_t idle_ticks, const std::uint64_t total_ticks) {
56  const std::uint64_t total_ticks_since_last_time = total_ticks - m_cpu_previous_total_ticks;
57  const std::uint64_t idle_ticks_since_last_time = idle_ticks - m_cpu_previous_idle_ticks;
58 
59  const float rate = 1.0f - ((total_ticks_since_last_time > 0) ? static_cast<float>(idle_ticks_since_last_time) / total_ticks_since_last_time : 0.0f);
60 
61  m_cpu_previous_total_ticks = total_ticks;
62  m_cpu_previous_idle_ticks = idle_ticks;
63 
64  return (rate * 100.0f);
65  }
66 #endif
67 
68 
69  private:
70 #if defined(ENIGMA_PLATFORM_WINDOWS)
71 
72  FILETIME m_idle_time{}, m_kernel_time{}, m_user_time{};
73  std::uint64_t m_cpu_previous_total_ticks{0};
74  std::uint64_t m_cpu_previous_idle_ticks{0};
75 
76  std::uint64_t FileTimeToUInt64(const FILETIME& file_time) {
77  return (static_cast<std::uint64_t>(file_time.dwHighDateTime) << 32) | static_cast<std::uint64_t>(file_time.dwLowDateTime);
78  }
79 
80 #elif defined(ENIGMA_PLATFORM_LINUX)
81 
82  std::uint64_t m_last_total_user{0};
83  std::uint64_t m_last_total_user_low{0};
84  std::uint64_t m_last_total_sys{0};
85  std::uint64_t m_last_total_idle{0};
86 
87 #elif defined(ENIGMA_PLATFORM_MACOS)
88 
89  std::uint64_t m_cpu_previous_total_ticks{0};
90  std::uint64_t m_cpu_previous_idle_ticks{0};
91  host_cpu_load_info_data_t m_cpu_info{};
92  mach_msg_type_number_t m_count = HOST_CPU_LOAD_INFO_COUNT;
93 
94 #endif
95 };
96 
97 
99 
100 
101 #endif // !ENIGMA_CPU_INFO_H
102 
103 
104 #if 0
105 #pragma once
106 #ifndef ENIGMA_CPU_INFO_H
107 #define ENIGMA_CPU_INFO_H
108 
109 #undef ENIGMA_PLATFORM_WINDOWS
110 #define ENIGMA_PLATFORM_LINUX 1
111 
112 #include <Core/Core.hpp>
113 #include <Logger/Logger.hpp>
114 
115 #if defined(ENIGMA_PLATFORM_WINDOWS)
116 // Windows Includes
117 #include <Windows.h>
118 #elif defined(ENIGMA_PLATFORM_LINUX)
119 // Linux Includes
120 #include <cstring>
121 #include <sys/times.h>
122 #include <sys/vtimes.h>
123 #elif defined(ENIGMA_PLATFORM_MACOS)
124 // MacOS Includes
125 #include <mach/mach_error.h>
126 #include <mach/mach_host.h>
127 #include <mach/mach_init.h>
128 #include <mach/vm_map.h>
129 #endif
130 
132 /*
133 * CPUInfo class will gather informations about the CPU at runtime
134 */
135 class CPUInfo
136 {
137 public: /* Constructors / Destructor */
138  CPUInfo() noexcept
139  {
140 #if defined(ENIGMA_PLATFORM_WINDOWS)
141  ::SYSTEM_INFO sys_info{};
142  ::FILETIME ftime{}, fsys{}, fuser{};
143 
144  ::GetSystemInfo(&sys_info);
145  m_num_processors = sys_info.dwNumberOfProcessors;
146 
147  ::GetSystemTimeAsFileTime(&ftime);
148  std::memcpy(&m_last_cpu, &ftime, sizeof(FILETIME));
149 
150  ::GetProcessTimes(::GetCurrentProcess(), &ftime, &ftime, &fsys, &fuser);
151  std::memcpy(&m_last_sys_cpu, &fsys, sizeof(FILETIME));
152  std::memcpy(&m_last_user_cpu, &fuser, sizeof(FILETIME));
153 #elif defined(ENIGMA_PLATFORM_LINUX)
154  std::FILE* file{};
155  struct tms timeSample {};
156  char line[128];
157 
158  lastCPU = times(&timeSample);
159  lastSysCPU = timeSample.tms_stime;
160  lastUserCPU = timeSample.tms_utime;
161 
162  file = fopen("/proc/cpuinfo", "r");
163  numProcessors = 0;
164  while (fgets(line, 128, file) != NULL) {
165  if (strncmp(line, "processor", 9) == 0) numProcessors++;
166  }
167  fclose(file);
168 #endif
169 
170  }
171  ~CPUInfo() noexcept = default;
172 
175 
176 
177 public:
178  /*
179  * Returns cpu usage (in percentage [0% -> 100%])
180  */
181  float CPUInfo::GetCPUUsage() noexcept
182  {
183  float percentage{ 0.0f };
184 
185 #if defined(ENIGMA_PLATFORM_WINDOWS)
186 
187  if (::GetSystemTimes(&m_idle_time, &m_kernel_time, &m_user_time))
188  {
189  const std::uint64_t idle_ticks = this->FileTimeToUInt64(m_idle_time);
190  const std::uint64_t total_ticks = this->FileTimeToUInt64(m_kernel_time) + this->FileTimeToUInt64(m_user_time);
191  percentage = this->CalculateCPULoad(idle_ticks, total_ticks);
192  }
193  else
194  percentage = -100.0f;
195 
196 #elif defined(ENIGMA_PLATFORM_LINUX)
197 
198  std::uint64_t total_user{}, total_user_low{}, total_sys{}, total_idle{}, total{};
199 
200  std::FILE* file = std::fopen("/proc/stat", "r");
201  std::fscanf(file, "cpu %llu %llu %llu %llu",
202  &total_user, &total_user_low,
203  &total_sys, &total_idle);
204  std::fclose(file);
205 
206  if (total_user < m_last_total_user || total_user_low < m_last_total_user_low ||
207  total_sys < m_last_total_sys || total_idle < m_last_total_idle)
208  {
209  //Overflow detection. Just skip this value.
210  percentage = -100.0f;
211  }
212  else
213  {
214  total = (total_user - m_last_total_user) + (total_user_low - m_last_total_user_low) + (total_sys - m_last_total_sys);
215  percentage = static_cast<float>(total);
216  total += (total_idle - m_last_total_idle);
217  percentage /= total;
218  percentage *= 100.0f;
219  }
220 
221  m_last_total_user = total_user;
222  m_last_total_user_low = total_user_low;
223  m_last_total_sys = total_sys;
224  m_last_total_idle = total_idle;
225 
226 #elif defined(ENIGMA_PLATFORM_MACOS)
227  if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&m_cpu_info, &m_count) == KERN_SUCCESS)
228  {
229  std::uint64_t total_ticks{ 0 };
230  for (auto i = 0; i < CPU_STATE_MAX; ++i)
231  total_ticks += m_cpu_info.cpu_ticks[i];
232  const std::uint64_t idle_ticks = m_cpu_info.cpu_ticks[CPU_STATE_IDLE];
233  percentage = this->CalculateCPULoad(idle_ticks, total_ticks);
234  }
235  else
236  percentage = -100.0f;
237 #endif
238 
239  return percentage;
240  }
241 
242 
243  /*
244  * Returns cpu usage by current process (in percentage [0% -> 100%])
245  */
246  float GetProcessCPUUsage() noexcept
247  {
248 #if defined(ENIGMA_PLATFORM_WINDOWS)
249 
250  ULARGE_INTEGER now{}, sys{}, user{};
251 
252  ::GetSystemTimeAsFileTime(&m_idle_time);
253  std::memcpy(&now, &m_idle_time, sizeof(FILETIME));
254 
255  ::GetProcessTimes(::GetCurrentProcess(), &m_idle_time, &m_idle_time, &m_kernel_time, &m_user_time);
256  std::memcpy(&sys, &m_kernel_time, sizeof(FILETIME));
257  std::memcpy(&user, &m_user_time, sizeof(FILETIME));
258 
259  float percent = static_cast<float>(sys.QuadPart - m_last_sys_cpu.QuadPart) + static_cast<float>(user.QuadPart - m_last_user_cpu.QuadPart);
260  percent /= static_cast<float>(now.QuadPart - m_last_cpu.QuadPart);
261  percent /= static_cast<float>(m_num_processors);
262 
263  m_last_cpu = now;
264  m_last_user_cpu = user;
265  m_last_sys_cpu = sys;
266 
267  return percent * 100.0f;
268 
269 #elif defined(ENIGMA_PLATFORM_LINUX)
270 #elif defined(ENIGMA_PLATFORM_MACOS)
271 #else
272  return 0.0f;
273 #endif
274  }
275 
276 
277 private: /* Platform Functions */
278 #if defined(ENIGMA_PLATFORM_WINDOWS) || defined(ENIGMA_PLATFORM_MACOS)
279  /*
280  * Calculates CPU Load percentage by idle and total ticks for (used for Windows & MacOS)
281  */
282  float CalculateCPULoad(const std::uint64_t idle_ticks, const std::uint64_t total_ticks)
283  {
284  const std::uint64_t total_ticks_since_last_time = total_ticks - m_cpu_previous_total_ticks;
285  const std::uint64_t idle_ticks_since_last_time = idle_ticks - m_cpu_previous_idle_ticks;
286 
287  const float rate = 1.0f - ((total_ticks_since_last_time > 0) ? static_cast<float>(idle_ticks_since_last_time) / total_ticks_since_last_time : 0.0f);
288 
289  m_cpu_previous_total_ticks = total_ticks;
290  m_cpu_previous_idle_ticks = idle_ticks;
291 
292  return (rate * 100.0f);
293  }
294 #endif
295 
296 
297 private: /* Platform Variables */
298 #if defined(ENIGMA_PLATFORM_WINDOWS)
299 
300  FILETIME m_idle_time{}, m_kernel_time{}, m_user_time{};
301  ULARGE_INTEGER m_last_cpu{}, m_last_user_cpu{}, m_last_sys_cpu{};
302  std::int32_t m_num_processors{};
303 
304  std::uint64_t m_cpu_previous_total_ticks{ 0 };
305  std::uint64_t m_cpu_previous_idle_ticks{ 0 };
306 
307  std::uint64_t FileTimeToUInt64(const FILETIME& file_time)
308  {
309  return (static_cast<std::uint64_t>(file_time.dwHighDateTime) << 32) | static_cast<std::uint64_t>(file_time.dwLowDateTime);
310  }
311 
312 #elif defined(ENIGMA_PLATFORM_LINUX)
313 
314  std::uint64_t m_last_total_user{ 0 };
315  std::uint64_t m_last_total_user_low{ 0 };
316  std::uint64_t m_last_total_sys{ 0 };
317  std::uint64_t m_last_total_idle{ 0 };
318 
319  std::int32_t m_num_processors{};
320 
321 #elif defined(ENIGMA_PLATFORM_MACOS)
322 
323  std::uint64_t m_cpu_previous_total_ticks{ 0 };
324  std::uint64_t m_cpu_previous_idle_ticks{ 0 };
325  host_cpu_load_info_data_t m_cpu_info{};
326  mach_msg_type_number_t m_count = HOST_CPU_LOAD_INFO_COUNT;
327 
328 #endif
329 };
330 
331 
333 
334 
335 #endif // !ENIGMA_CPU_INFO_H
336 #endif
#define NS_ENIGMA_BEGIN
Enable/Disable Assertions.
Definition: Macros.hpp:13
#define NS_ENIGMA_END
Definition: Macros.hpp:14
CPUInfo() noexcept
float GetProcessCPUUsage() noexcept
ENIGMA_NON_MOVEABLE(CPUInfo)
~CPUInfo() noexcept=default
ENIGMA_NON_COPYABLE(CPUInfo)
float GetCPUUsage() noexcept
static std::string now(const std::string_view &format="%Y-%m-%d %H:%M:%S")
returns current date and time as a string with a specific format