1
1
#pragma once
2
2
3
3
#include < json/json.h>
4
+ #include < chrono>
5
+ #include < iostream>
6
+ #include < sstream>
4
7
#include < string>
5
8
#include < string_view>
9
+ #include < thread>
6
10
#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
7
25
#include " common/hardware_common.h"
8
- #include " cpu_usage.h"
9
26
#include " hwinfo/hwinfo.h"
10
27
#include " utils/cpuid/cpu_info.h"
11
28
12
29
namespace 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
+ }
19
35
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;
24
39
}
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
+
26
123
#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 ;
28
181
#endif
182
+ }
29
183
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
+ };
37
198
} // namespace cortex::hw
0 commit comments