1+ #pragma once
2+ #include < chrono>
3+ #include < iostream>
4+ #include < sstream>
5+ #include < thread>
6+ #include < vector>
7+
8+ #ifdef _WIN32
9+ #include < pdh.h>
10+ #include < windows.h>
11+ #pragma comment(lib, "pdh.lib")
12+ #elif defined(__APPLE__) || defined(__MACH__)
13+ #include < mach/mach_host.h>
14+ #include < mach/mach_init.h>
15+ #else
16+ #include < unistd.h>
17+ #include < fstream>
18+ #endif
19+ #include " utils/logging_utils.h"
20+
21+ namespace cortex ::hw {
22+ inline double GetCPUUsage () {
23+ #if defined(_WIN32)
24+ unsigned long long previous_total_ticks = 0 ;
25+ unsigned long long previous_idle_ticks = 0 ;
26+
27+ auto calculate_cpu_load = [&](unsigned long long idle_ticks,
28+ unsigned long long total_ticks) {
29+ unsigned long long total_ticks_since_last_time =
30+ total_ticks - previous_total_ticks;
31+ unsigned long long idle_ticks_since_last_time =
32+ idle_ticks - previous_idle_ticks;
33+
34+ float ret = 1 .0f - ((total_ticks_since_last_time > 0 )
35+ ? ((float )idle_ticks_since_last_time) /
36+ total_ticks_since_last_time
37+ : 0 );
38+
39+ previous_total_ticks = total_ticks;
40+ previous_idle_ticks = idle_ticks;
41+ return ret * 100 ;
42+ };
43+
44+ auto file_time_to_int64 = [](const FILETIME& ft) {
45+ return (((unsigned long long )(ft.dwHighDateTime )) << 32 ) |
46+ ((unsigned long long )ft.dwLowDateTime );
47+ };
48+
49+ FILETIME idle_time, kernel_time, user_time;
50+ float res = 0 ;
51+ constexpr const int kCount = 100 ;
52+ for (int i = 0 ; i < kCount ; i++) {
53+ res += GetSystemTimes (&idle_time, &kernel_time, &user_time)
54+ ? calculate_cpu_load (file_time_to_int64 (idle_time),
55+ file_time_to_int64 (kernel_time) +
56+ file_time_to_int64 (user_time))
57+ : -1 .0f ;
58+ std::this_thread::sleep_for (std::chrono::milliseconds (1 ));
59+ }
60+ return res < 0 ? -1 .0f : res / kCount ;
61+
62+ #elif defined(__APPLE__) || defined(__MACH__)
63+ // macOS implementation
64+ host_cpu_load_info_data_t cpu_info;
65+ mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
66+
67+ static unsigned long long previous_total_ticks = 0 ;
68+ static unsigned long long previous_idle_ticks = 0 ;
69+
70+ if (host_statistics (mach_host_self (), HOST_CPU_LOAD_INFO,
71+ (host_info_t )&cpu_info, &count) == KERN_SUCCESS) {
72+ unsigned long long total_ticks = 0 ;
73+ for (int i = 0 ; i < CPU_STATE_MAX; i++) {
74+ total_ticks += cpu_info.cpu_ticks [i];
75+ }
76+
77+ unsigned long long idle_ticks = cpu_info.cpu_ticks [CPU_STATE_IDLE];
78+
79+ unsigned long long total_ticks_since_last_time =
80+ total_ticks - previous_total_ticks;
81+ unsigned long long idle_ticks_since_last_time =
82+ idle_ticks - previous_idle_ticks;
83+
84+ double cpu_usage = 1 .0f - ((double )idle_ticks_since_last_time /
85+ total_ticks_since_last_time);
86+
87+ previous_total_ticks = total_ticks;
88+ previous_idle_ticks = idle_ticks;
89+
90+ return cpu_usage * 100.0 ;
91+ }
92+ return -1.0 ;
93+
94+ #else
95+ // Linux implementation
96+ std::vector<unsigned long long > last_total_user, last_total_user_low,
97+ last_total_sys, last_total_idle;
98+
99+ std::vector<unsigned long long > total_user, total_user_low, total_sys,
100+ total_idle;
101+
102+ std::ifstream stat_file (" /proc/stat" );
103+ if (stat_file.is_open ()) {
104+ std::string line;
105+ int cpu_count = 0 ;
106+ double total_cpu_percentage = 0.0 ;
107+
108+ while (std::getline (stat_file, line)) {
109+ if (line.substr (0 , 3 ) != " cpu" )
110+ break ; // We only want lines that start with "cpu"
111+
112+ cpu_count++;
113+ std::vector<unsigned long long > values;
114+ std::istringstream iss (line);
115+ std::string cpu;
116+ iss >> cpu;
117+ unsigned long long value;
118+ while (iss >> value) {
119+ values.push_back (value);
120+ }
121+
122+ if (values.size () < 4 )
123+ continue ;
124+
125+ total_user.push_back (values[0 ]);
126+ total_user_low.push_back (values[1 ]);
127+ total_sys.push_back (values[2 ]);
128+ total_idle.push_back (values[3 ]);
129+
130+ if (last_total_user.size () < cpu_count) {
131+ last_total_user.push_back (0 );
132+ last_total_user_low.push_back (0 );
133+ last_total_sys.push_back (0 );
134+ last_total_idle.push_back (0 );
135+ }
136+
137+ unsigned long long total =
138+ (total_user[cpu_count - 1 ] - last_total_user[cpu_count - 1 ]) +
139+ (total_user_low[cpu_count - 1 ] - last_total_user_low[cpu_count - 1 ]) +
140+ (total_sys[cpu_count - 1 ] - last_total_sys[cpu_count - 1 ]);
141+ double percent = total;
142+ total += (total_idle[cpu_count - 1 ] - last_total_idle[cpu_count - 1 ]);
143+ percent /= total;
144+ percent *= 100 ;
145+
146+ total_cpu_percentage += percent;
147+
148+ last_total_user[cpu_count - 1 ] = total_user[cpu_count - 1 ];
149+ last_total_user_low[cpu_count - 1 ] = total_user_low[cpu_count - 1 ];
150+ last_total_sys[cpu_count - 1 ] = total_sys[cpu_count - 1 ];
151+ last_total_idle[cpu_count - 1 ] = total_idle[cpu_count - 1 ];
152+ }
153+ stat_file.close ();
154+
155+ if (cpu_count > 0 ) {
156+ return total_cpu_percentage / cpu_count; // Return average CPU usage
157+ }
158+ }
159+ return -1.0 ;
160+ #endif
161+ }
162+ } // namespace cortex::hw
0 commit comments