Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add cpu usage #1868

Merged
merged 3 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions engine/cli/commands/hardware_list_cmd.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ bool HardwareListCmd::Exec(const std::string& host, int port,
if (!ho.has_value() || ho.value().show_cpu) {
std::cout << "CPU Information:" << std::endl;
Table table;
std::vector<std::string> column_headers{"#", "Arch", "Cores", "Model",
"Instructions"};
std::vector<std::string> column_headers{"#", "Arch", "Cores",
"Model", "Usage", "Instructions"};

Row_t header{column_headers.begin(), column_headers.end()};
table.add_row(header);
Expand All @@ -52,6 +52,7 @@ bool HardwareListCmd::Exec(const std::string& host, int port,
row.emplace_back(cpu.arch);
row.emplace_back(std::to_string(cpu.cores));
row.emplace_back(cpu.model);
row.emplace_back(std::to_string(cpu.usage));
std::string insts;
for (auto const& i : cpu.instructions) {
insts += i + " ";
Expand Down
15 changes: 10 additions & 5 deletions engine/common/hardware_common.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#pragma once
#include <assert.h>
#include <json/json.h>
#include <string>
#include <variant>
#include <vector>
#include <assert.h>

namespace cortex::hw {

Expand All @@ -26,6 +26,7 @@ struct CPU {
int cores;
std::string arch;
std::string model;
float usage;
std::vector<std::string> instructions;
};

Expand All @@ -34,6 +35,7 @@ inline Json::Value ToJson(const CPU& cpu) {
res["arch"] = cpu.arch;
res["cores"] = cpu.cores;
res["model"] = cpu.model;
res["usage"] = cpu.usage;
Json::Value insts(Json::arrayValue);
for (auto const& i : cpu.instructions) {
insts.append(i);
Expand All @@ -47,11 +49,16 @@ inline CPU FromJson(const Json::Value& root) {
int cores = root["cores"].asInt();
std::string arch = root["arch"].asString();
std::string model = root["model"].asString();
float usage = root["usage"].asFloat();
std::vector<std::string> insts;
for (auto const& i : root["instructions"]) {
insts.emplace_back(i.asString());
}
return {.cores = cores, .arch = arch, .model = model, .instructions = insts};
return {.cores = cores,
.arch = arch,
.model = model,
.usage = usage,
.instructions = insts};
}
} // namespace cpu

Expand Down Expand Up @@ -143,7 +150,6 @@ inline OS FromJson(const Json::Value& root) {
}
} // namespace os


struct PowerInfo {
std::string charging_status;
int battery_life;
Expand All @@ -166,7 +172,6 @@ inline PowerInfo FromJson(const Json::Value& root) {
}
} // namespace power


namespace {
int64_t ByteToMiB(int64_t b) {
return b / 1024 / 1024;
Expand Down Expand Up @@ -215,4 +220,4 @@ inline StorageInfo FromJson(const Json::Value& root) {
.available = root["available"].asInt64()};
}
} // namespace storage
}
} // namespace cortex::hw
4 changes: 4 additions & 0 deletions engine/utils/hardware/cpu_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string_view>
#include <vector>
#include "common/hardware_common.h"
#include "cpu_usage.h"
#include "hwinfo/hwinfo.h"
#include "utils/cpuid/cpu_info.h"

Expand All @@ -15,9 +16,12 @@ inline CPU GetCPUInfo() {
return CPU{};
auto cpu = res[0];
cortex::cpuid::CpuInfo inst;
float usage = GetCPUUsage();
// float usage = 0;
return CPU{.cores = cpu.numPhysicalCores(),
.arch = std::string(GetArch()),
.model = cpu.modelName(),
.usage = usage,
.instructions = inst.instructions()};
}
} // namespace cortex::hw
162 changes: 162 additions & 0 deletions engine/utils/hardware/cpu_usage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#pragma once
#include <chrono>
#include <iostream>
#include <sstream>
#include <thread>
#include <vector>

#ifdef _WIN32
#include <pdh.h>
#include <windows.h>
#pragma comment(lib, "pdh.lib")
#elif defined(__APPLE__) || defined(__MACH__)
#include <mach/mach_host.h>
#include <mach/mach_init.h>
#else
#include <unistd.h>
#include <fstream>
#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<unsigned long long> last_total_user, last_total_user_low,
last_total_sys, last_total_idle;

std::vector<unsigned long long> 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<unsigned long long> 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
Loading