diff --git a/engine/services/hardware_service.cc b/engine/services/hardware_service.cc index 88a5df6b0..5cb235422 100644 --- a/engine/services/hardware_service.cc +++ b/engine/services/hardware_service.cc @@ -52,7 +52,7 @@ HardwareInfo HardwareService::GetHardwareInfo() { }; } - return HardwareInfo{.cpu = cortex::hw::GetCPUInfo(), + return HardwareInfo{.cpu = cpu_info_.GetCPUInfo(), .os = cortex::hw::GetOSInfo(), .ram = cortex::hw::GetMemoryInfo(), .storage = cortex::hw::GetStorageInfo(), @@ -207,9 +207,6 @@ bool HardwareService::Restart(const std::string& host, int port) { if (!TryConnectToServer(host, port)) { return false; } - std::cout << "Server started" << std::endl; - std::cout << "API Documentation available at: http://" << host << ":" - << port << std::endl; } #endif diff --git a/engine/services/hardware_service.h b/engine/services/hardware_service.h index a8a619d4f..680cd0961 100644 --- a/engine/services/hardware_service.h +++ b/engine/services/hardware_service.h @@ -1,8 +1,8 @@ #pragma once #include +#include #include #include -#include #include "common/hardware_config.h" #include "database_service.h" @@ -41,4 +41,5 @@ class HardwareService { std::shared_ptr db_service_ = nullptr; std::optional ahc_; std::mutex mtx_; + cortex::hw::CpuInfo cpu_info_; }; \ No newline at end of file diff --git a/engine/utils/hardware/cpu_info.h b/engine/utils/hardware/cpu_info.h index 20ae30bc3..af7a85a4b 100644 --- a/engine/utils/hardware/cpu_info.h +++ b/engine/utils/hardware/cpu_info.h @@ -1,37 +1,198 @@ #pragma once #include +#include +#include +#include #include #include +#include #include + +#ifdef _WIN32 +#include +#include +#pragma comment(lib, "pdh.lib") +#elif defined(__APPLE__) || defined(__MACH__) +#include +#include +#else +#include +#include +#include +#include +#endif #include "common/hardware_common.h" -#include "cpu_usage.h" #include "hwinfo/hwinfo.h" #include "utils/cpuid/cpu_info.h" namespace cortex::hw { -inline CPU GetCPUInfo() { - auto res = hwinfo::getAllCPUs(); - if (res.empty()) - return CPU{}; - auto cpu = res[0]; - cortex::cpuid::CpuInfo inst; +struct Jiffies { + Jiffies() { + working = -1; + all = -1; + } -#if defined(__linux__) - float usage = 0; - for (auto const& c : res) { - usage += c.currentUtilisation(); + Jiffies(int64_t _all, int64_t _working) { + all = _all; + working = _working; } - usage = usage / res.size() * 100; + + int64_t working; + int64_t all; +}; + +struct CpuInfo { + private: + cortex::cpuid::CpuInfo inst; + bool jiffies_initialized = false; + + public: + double GetCPUUsage() { +#if defined(_WIN32) + unsigned long long previous_total_ticks = 0; + unsigned long long previous_idle_ticks = 0; + + auto calculate_cpu_load = [&](unsigned long long idle_ticks, + unsigned long long total_ticks) { + unsigned long long total_ticks_since_last_time = + total_ticks - previous_total_ticks; + unsigned long long idle_ticks_since_last_time = + idle_ticks - previous_idle_ticks; + + float ret = 1.0f - ((total_ticks_since_last_time > 0) + ? ((float)idle_ticks_since_last_time) / + total_ticks_since_last_time + : 0); + + previous_total_ticks = total_ticks; + previous_idle_ticks = idle_ticks; + return ret * 100; + }; + + auto file_time_to_int64 = [](const FILETIME& ft) { + return (((unsigned long long)(ft.dwHighDateTime)) << 32) | + ((unsigned long long)ft.dwLowDateTime); + }; + + FILETIME idle_time, kernel_time, user_time; + float res = 0; + constexpr const int kCount = 100; + for (int i = 0; i < kCount; i++) { + res += GetSystemTimes(&idle_time, &kernel_time, &user_time) + ? calculate_cpu_load(file_time_to_int64(idle_time), + file_time_to_int64(kernel_time) + + file_time_to_int64(user_time)) + : -1.0f; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + return res < 0 ? -1.0f : res / kCount; + +#elif defined(__APPLE__) || defined(__MACH__) + // macOS implementation + host_cpu_load_info_data_t cpu_info; + mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; + + static unsigned long long previous_total_ticks = 0; + static unsigned long long previous_idle_ticks = 0; + + if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, + (host_info_t)&cpu_info, &count) == KERN_SUCCESS) { + unsigned long long total_ticks = 0; + for (int i = 0; i < CPU_STATE_MAX; i++) { + total_ticks += cpu_info.cpu_ticks[i]; + } + + unsigned long long idle_ticks = cpu_info.cpu_ticks[CPU_STATE_IDLE]; + + unsigned long long total_ticks_since_last_time = + total_ticks - previous_total_ticks; + unsigned long long idle_ticks_since_last_time = + idle_ticks - previous_idle_ticks; + + double cpu_usage = 1.0f - ((double)idle_ticks_since_last_time / + total_ticks_since_last_time); + + previous_total_ticks = total_ticks; + previous_idle_ticks = idle_ticks; + + return cpu_usage * 100.0; + } + return -1.0; + #else - float usage = GetCPUUsage(); + if (!jiffies_initialized) { + // Sleep 1 sec just for the start cause the usage needs to have a delta value which is depending on the unix file + // read it's just for the init, you don't need to wait if the delta is already created ... + std::this_thread::sleep_for(std::chrono::duration(1)); + jiffies_initialized = true; + } + + auto get_jiffies = [](int index) -> Jiffies { + std::ifstream filestat("/proc/stat"); + if (!filestat.is_open()) { + return {}; + } + + for (int i = 0; i < index; ++i) { + if (!filestat.ignore(std::numeric_limits::max(), + '\n')) { + break; + } + } + std::string line; + std::getline(filestat, line); + + std::istringstream iss(line); + std::vector results(std::istream_iterator{iss}, + std::istream_iterator()); + + const int64_t jiffies_0 = std::stol(results[1]); + const int64_t jiffies_1 = std::stol(results[2]); + const int64_t jiffies_2 = std::stol(results[3]); + const int64_t jiffies_3 = std::stol(results[4]); + const int64_t jiffies_4 = std::stol(results[5]); + const int64_t jiffies_5 = std::stol(results[6]); + const int64_t jiffies_6 = std::stol(results[7]); + const int64_t jiffies_7 = std::stol(results[8]); + const int64_t jiffies_8 = std::stol(results[9]); + const int64_t jiffies_9 = std::stol(results[10]); + + int64_t all = jiffies_0 + jiffies_1 + jiffies_2 + jiffies_3 + jiffies_4 + + jiffies_5 + jiffies_6 + jiffies_7 + jiffies_8 + jiffies_9; + int64_t working = jiffies_0 + jiffies_1 + jiffies_2; + + return {all, working}; + }; + static Jiffies last = Jiffies(); + + Jiffies current = get_jiffies(0); + + auto total_over_period = static_cast(current.all - last.all); + auto work_over_period = static_cast(current.working - last.working); + + last = current; + + const double utilization = work_over_period / total_over_period; + if (utilization < 0 || utilization > 1 || std::isnan(utilization)) { + return -1.0; + } + return utilization * 100; #endif + } - // float usage = 0; - return CPU{.cores = cpu.numPhysicalCores(), - .arch = std::string(GetArch()), - .model = cpu.modelName(), - .usage = usage, - .instructions = inst.instructions()}; -} + CPU GetCPUInfo() { + auto res = hwinfo::getAllCPUs(); + if (res.empty()) + return CPU{}; + auto cpu = res[0]; + cortex::cpuid::CpuInfo inst; + float usage = GetCPUUsage(); + return CPU{.cores = cpu.numPhysicalCores(), + .arch = std::string(GetArch()), + .model = cpu.modelName(), + .usage = usage, + .instructions = inst.instructions()}; + } +}; } // namespace cortex::hw \ No newline at end of file diff --git a/engine/utils/hardware/cpu_usage.h b/engine/utils/hardware/cpu_usage.h deleted file mode 100644 index 2bba32f09..000000000 --- a/engine/utils/hardware/cpu_usage.h +++ /dev/null @@ -1,162 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#pragma comment(lib, "pdh.lib") -#elif defined(__APPLE__) || defined(__MACH__) -#include -#include -#else -#include -#include -#endif -#include "utils/logging_utils.h" - -namespace cortex::hw { -inline double GetCPUUsage() { -#if defined(_WIN32) - unsigned long long previous_total_ticks = 0; - unsigned long long previous_idle_ticks = 0; - - auto calculate_cpu_load = [&](unsigned long long idle_ticks, - unsigned long long total_ticks) { - unsigned long long total_ticks_since_last_time = - total_ticks - previous_total_ticks; - unsigned long long idle_ticks_since_last_time = - idle_ticks - previous_idle_ticks; - - float ret = 1.0f - ((total_ticks_since_last_time > 0) - ? ((float)idle_ticks_since_last_time) / - total_ticks_since_last_time - : 0); - - previous_total_ticks = total_ticks; - previous_idle_ticks = idle_ticks; - return ret * 100; - }; - - auto file_time_to_int64 = [](const FILETIME& ft) { - return (((unsigned long long)(ft.dwHighDateTime)) << 32) | - ((unsigned long long)ft.dwLowDateTime); - }; - - FILETIME idle_time, kernel_time, user_time; - float res = 0; - constexpr const int kCount = 100; - for (int i = 0; i < kCount; i++) { - res += GetSystemTimes(&idle_time, &kernel_time, &user_time) - ? calculate_cpu_load(file_time_to_int64(idle_time), - file_time_to_int64(kernel_time) + - file_time_to_int64(user_time)) - : -1.0f; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - return res < 0 ? -1.0f : res / kCount; - -#elif defined(__APPLE__) || defined(__MACH__) - // macOS implementation - host_cpu_load_info_data_t cpu_info; - mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; - - static unsigned long long previous_total_ticks = 0; - static unsigned long long previous_idle_ticks = 0; - - if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, - (host_info_t)&cpu_info, &count) == KERN_SUCCESS) { - unsigned long long total_ticks = 0; - for (int i = 0; i < CPU_STATE_MAX; i++) { - total_ticks += cpu_info.cpu_ticks[i]; - } - - unsigned long long idle_ticks = cpu_info.cpu_ticks[CPU_STATE_IDLE]; - - unsigned long long total_ticks_since_last_time = - total_ticks - previous_total_ticks; - unsigned long long idle_ticks_since_last_time = - idle_ticks - previous_idle_ticks; - - double cpu_usage = 1.0f - ((double)idle_ticks_since_last_time / - total_ticks_since_last_time); - - previous_total_ticks = total_ticks; - previous_idle_ticks = idle_ticks; - - return cpu_usage * 100.0; - } - return -1.0; - -#else - // Linux implementation - std::vector last_total_user, last_total_user_low, - last_total_sys, last_total_idle; - - std::vector total_user, total_user_low, total_sys, - total_idle; - - std::ifstream stat_file("/proc/stat"); - if (stat_file.is_open()) { - std::string line; - int cpu_count = 0; - double total_cpu_percentage = 0.0; - - while (std::getline(stat_file, line)) { - if (line.substr(0, 3) != "cpu") - break; // We only want lines that start with "cpu" - - cpu_count++; - std::vector values; - std::istringstream iss(line); - std::string cpu; - iss >> cpu; - unsigned long long value; - while (iss >> value) { - values.push_back(value); - } - - if (values.size() < 4) - continue; - - total_user.push_back(values[0]); - total_user_low.push_back(values[1]); - total_sys.push_back(values[2]); - total_idle.push_back(values[3]); - - if (last_total_user.size() < cpu_count) { - last_total_user.push_back(0); - last_total_user_low.push_back(0); - last_total_sys.push_back(0); - last_total_idle.push_back(0); - } - - unsigned long long total = - (total_user[cpu_count - 1] - last_total_user[cpu_count - 1]) + - (total_user_low[cpu_count - 1] - last_total_user_low[cpu_count - 1]) + - (total_sys[cpu_count - 1] - last_total_sys[cpu_count - 1]); - double percent = total; - total += (total_idle[cpu_count - 1] - last_total_idle[cpu_count - 1]); - percent /= total; - percent *= 100; - - total_cpu_percentage += percent; - - last_total_user[cpu_count - 1] = total_user[cpu_count - 1]; - last_total_user_low[cpu_count - 1] = total_user_low[cpu_count - 1]; - last_total_sys[cpu_count - 1] = total_sys[cpu_count - 1]; - last_total_idle[cpu_count - 1] = total_idle[cpu_count - 1]; - } - stat_file.close(); - - if (cpu_count > 0) { - return total_cpu_percentage / cpu_count; // Return average CPU usage - } - } - return -1.0; -#endif -} -} // namespace cortex::hw \ No newline at end of file