11#pragma once
22
33#include < json/json.h>
4+ #include < chrono>
5+ #include < iostream>
6+ #include < sstream>
47#include < string>
58#include < string_view>
9+ #include < thread>
610#include < vector>
11+
12+ #ifdef _WIN32
13+ #include < pdh.h>
14+ #include < windows.h>
15+ #pragma comment(lib, "pdh.lib")
16+ #elif defined(__APPLE__) || defined(__MACH__)
17+ #include < mach/mach_host.h>
18+ #include < mach/mach_init.h>
19+ #else
20+ #include < unistd.h>
21+ #include < cmath>
22+ #include < fstream>
23+ #include < iterator>
24+ #endif
725#include " common/hardware_common.h"
8- #include " cpu_usage.h"
926#include " hwinfo/hwinfo.h"
1027#include " utils/cpuid/cpu_info.h"
1128
1229namespace cortex ::hw {
13- inline CPU GetCPUInfo () {
14- auto res = hwinfo::getAllCPUs ();
15- if (res.empty ())
16- return CPU{};
17- auto cpu = res[0 ];
18- cortex::cpuid::CpuInfo inst;
30+ struct Jiffies {
31+ Jiffies () {
32+ working = -1 ;
33+ all = -1 ;
34+ }
1935
20- #if defined(__linux__)
21- float usage = 0 ;
22- for (auto const & c : res) {
23- usage += c.currentUtilisation ();
36+ Jiffies (int64_t _all, int64_t _working) {
37+ all = _all;
38+ working = _working;
2439 }
25- usage = usage / res.size () * 100 ;
40+
41+ int64_t working;
42+ int64_t all;
43+ };
44+
45+ struct CpuInfo {
46+ private:
47+ cortex::cpuid::CpuInfo inst;
48+ bool jiffies_initialized = false ;
49+
50+ public:
51+ double GetCPUUsage () {
52+ #if defined(_WIN32)
53+ unsigned long long previous_total_ticks = 0 ;
54+ unsigned long long previous_idle_ticks = 0 ;
55+
56+ auto calculate_cpu_load = [&](unsigned long long idle_ticks,
57+ unsigned long long total_ticks) {
58+ unsigned long long total_ticks_since_last_time =
59+ total_ticks - previous_total_ticks;
60+ unsigned long long idle_ticks_since_last_time =
61+ idle_ticks - previous_idle_ticks;
62+
63+ float ret = 1 .0f - ((total_ticks_since_last_time > 0 )
64+ ? ((float )idle_ticks_since_last_time) /
65+ total_ticks_since_last_time
66+ : 0 );
67+
68+ previous_total_ticks = total_ticks;
69+ previous_idle_ticks = idle_ticks;
70+ return ret * 100 ;
71+ };
72+
73+ auto file_time_to_int64 = [](const FILETIME& ft) {
74+ return (((unsigned long long )(ft.dwHighDateTime )) << 32 ) |
75+ ((unsigned long long )ft.dwLowDateTime );
76+ };
77+
78+ FILETIME idle_time, kernel_time, user_time;
79+ float res = 0 ;
80+ constexpr const int kCount = 100 ;
81+ for (int i = 0 ; i < kCount ; i++) {
82+ res += GetSystemTimes (&idle_time, &kernel_time, &user_time)
83+ ? calculate_cpu_load (file_time_to_int64 (idle_time),
84+ file_time_to_int64 (kernel_time) +
85+ file_time_to_int64 (user_time))
86+ : -1 .0f ;
87+ std::this_thread::sleep_for (std::chrono::milliseconds (1 ));
88+ }
89+ return res < 0 ? -1 .0f : res / kCount ;
90+
91+ #elif defined(__APPLE__) || defined(__MACH__)
92+ // macOS implementation
93+ host_cpu_load_info_data_t cpu_info;
94+ mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
95+
96+ static unsigned long long previous_total_ticks = 0 ;
97+ static unsigned long long previous_idle_ticks = 0 ;
98+
99+ if (host_statistics (mach_host_self (), HOST_CPU_LOAD_INFO,
100+ (host_info_t )&cpu_info, &count) == KERN_SUCCESS) {
101+ unsigned long long total_ticks = 0 ;
102+ for (int i = 0 ; i < CPU_STATE_MAX; i++) {
103+ total_ticks += cpu_info.cpu_ticks [i];
104+ }
105+
106+ unsigned long long idle_ticks = cpu_info.cpu_ticks [CPU_STATE_IDLE];
107+
108+ unsigned long long total_ticks_since_last_time =
109+ total_ticks - previous_total_ticks;
110+ unsigned long long idle_ticks_since_last_time =
111+ idle_ticks - previous_idle_ticks;
112+
113+ double cpu_usage = 1 .0f - ((double )idle_ticks_since_last_time /
114+ total_ticks_since_last_time);
115+
116+ previous_total_ticks = total_ticks;
117+ previous_idle_ticks = idle_ticks;
118+
119+ return cpu_usage * 100.0 ;
120+ }
121+ return -1.0 ;
122+
26123#else
27- float usage = GetCPUUsage ();
124+ if (!jiffies_initialized) {
125+ // Sleep 1 sec just for the start cause the usage needs to have a delta value which is depending on the unix file
126+ // read it's just for the init, you don't need to wait if the delta is already created ...
127+ std::this_thread::sleep_for (std::chrono::duration<double >(1 ));
128+ jiffies_initialized = true ;
129+ }
130+
131+ auto get_jiffies = [](int index) -> Jiffies {
132+ std::ifstream filestat (" /proc/stat" );
133+ if (!filestat.is_open ()) {
134+ return {};
135+ }
136+
137+ for (int i = 0 ; i < index; ++i) {
138+ if (!filestat.ignore (std::numeric_limits<std::streamsize>::max (),
139+ ' \n ' )) {
140+ break ;
141+ }
142+ }
143+ std::string line;
144+ std::getline (filestat, line);
145+
146+ std::istringstream iss (line);
147+ std::vector<std::string> results (std::istream_iterator<std::string>{iss},
148+ std::istream_iterator<std::string>());
149+
150+ const int64_t jiffies_0 = std::stol (results[1 ]);
151+ const int64_t jiffies_1 = std::stol (results[2 ]);
152+ const int64_t jiffies_2 = std::stol (results[3 ]);
153+ const int64_t jiffies_3 = std::stol (results[4 ]);
154+ const int64_t jiffies_4 = std::stol (results[5 ]);
155+ const int64_t jiffies_5 = std::stol (results[6 ]);
156+ const int64_t jiffies_6 = std::stol (results[7 ]);
157+ const int64_t jiffies_7 = std::stol (results[8 ]);
158+ const int64_t jiffies_8 = std::stol (results[9 ]);
159+ const int64_t jiffies_9 = std::stol (results[10 ]);
160+
161+ int64_t all = jiffies_0 + jiffies_1 + jiffies_2 + jiffies_3 + jiffies_4 +
162+ jiffies_5 + jiffies_6 + jiffies_7 + jiffies_8 + jiffies_9;
163+ int64_t working = jiffies_0 + jiffies_1 + jiffies_2;
164+
165+ return {all, working};
166+ };
167+ static Jiffies last = Jiffies ();
168+
169+ Jiffies current = get_jiffies (0 );
170+
171+ auto total_over_period = static_cast <double >(current.all - last.all );
172+ auto work_over_period = static_cast <double >(current.working - last.working );
173+
174+ last = current;
175+
176+ const double utilization = work_over_period / total_over_period;
177+ if (utilization < 0 || utilization > 1 || std::isnan (utilization)) {
178+ return -1.0 ;
179+ }
180+ return utilization * 100 ;
28181#endif
182+ }
29183
30- // float usage = 0;
31- return CPU{.cores = cpu.numPhysicalCores (),
32- .arch = std::string (GetArch ()),
33- .model = cpu.modelName (),
34- .usage = usage,
35- .instructions = inst.instructions ()};
36- }
184+ CPU GetCPUInfo () {
185+ auto res = hwinfo::getAllCPUs ();
186+ if (res.empty ())
187+ return CPU{};
188+ auto cpu = res[0 ];
189+ cortex::cpuid::CpuInfo inst;
190+ float usage = GetCPUUsage ();
191+ return CPU{.cores = cpu.numPhysicalCores (),
192+ .arch = std::string (GetArch ()),
193+ .model = cpu.modelName (),
194+ .usage = usage,
195+ .instructions = inst.instructions ()};
196+ }
197+ };
37198} // namespace cortex::hw
0 commit comments