|
|
|
@ -240,6 +240,113 @@ bool CPUStats::UpdateCpuTemp() {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool get_cpu_power_k10temp(CPUPowerData* cpuPowerData, int& power) {
|
|
|
|
|
CPUPowerData_k10temp* powerData_k10temp = (CPUPowerData_k10temp*)cpuPowerData;
|
|
|
|
|
|
|
|
|
|
if (!powerData_k10temp->coreVoltageFile || !powerData_k10temp->coreCurrentFile || !powerData_k10temp->socVoltageFile || !powerData_k10temp->socCurrentFile)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
rewind(powerData_k10temp->coreVoltageFile);
|
|
|
|
|
rewind(powerData_k10temp->coreCurrentFile);
|
|
|
|
|
rewind(powerData_k10temp->socVoltageFile);
|
|
|
|
|
rewind(powerData_k10temp->socCurrentFile);
|
|
|
|
|
|
|
|
|
|
fflush(powerData_k10temp->coreVoltageFile);
|
|
|
|
|
fflush(powerData_k10temp->coreCurrentFile);
|
|
|
|
|
fflush(powerData_k10temp->socVoltageFile);
|
|
|
|
|
fflush(powerData_k10temp->socCurrentFile);
|
|
|
|
|
|
|
|
|
|
int coreVoltage, coreCurrent;
|
|
|
|
|
int socVoltage, socCurrent;
|
|
|
|
|
|
|
|
|
|
if (fscanf(powerData_k10temp->coreVoltageFile, "%d", &coreVoltage) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
if (fscanf(powerData_k10temp->coreCurrentFile, "%d", &coreCurrent) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
if (fscanf(powerData_k10temp->socVoltageFile, "%d", &socVoltage) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
if (fscanf(powerData_k10temp->socCurrentFile, "%d", &socCurrent) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
power = (coreVoltage * coreCurrent + socVoltage * socCurrent) / 1000000;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool get_cpu_power_zenpower(CPUPowerData* cpuPowerData, int& power) {
|
|
|
|
|
CPUPowerData_zenpower* powerData_zenpower = (CPUPowerData_zenpower*)cpuPowerData;
|
|
|
|
|
|
|
|
|
|
if (!powerData_zenpower->corePowerFile || !powerData_zenpower->socPowerFile)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
rewind(powerData_zenpower->corePowerFile);
|
|
|
|
|
rewind(powerData_zenpower->socPowerFile);
|
|
|
|
|
|
|
|
|
|
fflush(powerData_zenpower->corePowerFile);
|
|
|
|
|
fflush(powerData_zenpower->socPowerFile);
|
|
|
|
|
|
|
|
|
|
int corePower, socPower;
|
|
|
|
|
|
|
|
|
|
if (fscanf(powerData_zenpower->corePowerFile, "%d", &corePower) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
if (fscanf(powerData_zenpower->socPowerFile, "%d", &socPower) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
power = (corePower + socPower) / 1000000;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool get_cpu_power_rapl(CPUPowerData* cpuPowerData, int& power) {
|
|
|
|
|
CPUPowerData_rapl* powerData_rapl = (CPUPowerData_rapl*)cpuPowerData;
|
|
|
|
|
|
|
|
|
|
if (!powerData_rapl->energyCounterFile)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
rewind(powerData_rapl->energyCounterFile);
|
|
|
|
|
fflush(powerData_rapl->energyCounterFile);
|
|
|
|
|
|
|
|
|
|
int energyCounterValue = 0;
|
|
|
|
|
if (fscanf(powerData_rapl->energyCounterFile, "%d", &energyCounterValue) != 1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
Clock::time_point now = Clock::now();
|
|
|
|
|
Clock::duration timeDiff = now - powerData_rapl->lastCounterValueTime;
|
|
|
|
|
int energyCounterDiff = energyCounterValue - powerData_rapl->lastCounterValue;
|
|
|
|
|
|
|
|
|
|
power = (int)((float)energyCounterDiff / (float)timeDiff.count() * 1000);
|
|
|
|
|
|
|
|
|
|
powerData_rapl->lastCounterValue = energyCounterValue;
|
|
|
|
|
powerData_rapl->lastCounterValueTime = now;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CPUStats::UpdateCpuPower() {
|
|
|
|
|
if(!m_cpuPowerData)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
int power = 0;
|
|
|
|
|
|
|
|
|
|
switch(m_cpuPowerData->source) {
|
|
|
|
|
case CPU_POWER_K10TEMP:
|
|
|
|
|
if (!get_cpu_power_k10temp(m_cpuPowerData.get(), power)) return false;
|
|
|
|
|
break;
|
|
|
|
|
case CPU_POWER_ZENPOWER:
|
|
|
|
|
if (!get_cpu_power_zenpower(m_cpuPowerData.get(), power)) return false;
|
|
|
|
|
break;
|
|
|
|
|
case CPU_POWER_RAPL:
|
|
|
|
|
if (!get_cpu_power_rapl(m_cpuPowerData.get(), power)) return false;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_cpuDataTotal.power = power;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool find_temp_input(const std::string path, std::string& input, const std::string& name)
|
|
|
|
|
{
|
|
|
|
|
auto files = ls(path.c_str(), "temp", LS_FILES);
|
|
|
|
@ -321,4 +428,191 @@ bool CPUStats::GetCpuFile() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool find_voltage_input(const std::string path, std::string& input, const std::string& name)
|
|
|
|
|
{
|
|
|
|
|
auto files = ls(path.c_str(), "in", LS_FILES);
|
|
|
|
|
for (auto& file : files) {
|
|
|
|
|
if (!ends_with(file, "_label"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto label = read_line(path + "/" + file);
|
|
|
|
|
if (label != name)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto uscore = file.find_first_of("_");
|
|
|
|
|
if (uscore != std::string::npos) {
|
|
|
|
|
file.erase(uscore, std::string::npos);
|
|
|
|
|
input = path + "/" + file + "_input";
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool find_current_input(const std::string path, std::string& input, const std::string& name)
|
|
|
|
|
{
|
|
|
|
|
auto files = ls(path.c_str(), "curr", LS_FILES);
|
|
|
|
|
for (auto& file : files) {
|
|
|
|
|
if (!ends_with(file, "_label"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto label = read_line(path + "/" + file);
|
|
|
|
|
if (label != name)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto uscore = file.find_first_of("_");
|
|
|
|
|
if (uscore != std::string::npos) {
|
|
|
|
|
file.erase(uscore, std::string::npos);
|
|
|
|
|
input = path + "/" + file + "_input";
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool find_power_input(const std::string path, std::string& input, const std::string& name)
|
|
|
|
|
{
|
|
|
|
|
auto files = ls(path.c_str(), "power", LS_FILES);
|
|
|
|
|
for (auto& file : files) {
|
|
|
|
|
if (!ends_with(file, "_label"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto label = read_line(path + "/" + file);
|
|
|
|
|
if (label != name)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
auto uscore = file.find_first_of("_");
|
|
|
|
|
if (uscore != std::string::npos) {
|
|
|
|
|
file.erase(uscore, std::string::npos);
|
|
|
|
|
input = path + "/" + file + "_input";
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPUPowerData_k10temp* init_cpu_power_data_k10temp(const std::string path) {
|
|
|
|
|
CPUPowerData_k10temp* powerData = new CPUPowerData_k10temp();
|
|
|
|
|
|
|
|
|
|
std::string coreVoltageInput, coreCurrentInput;
|
|
|
|
|
std::string socVoltageInput, socCurrentInput;
|
|
|
|
|
|
|
|
|
|
if(!find_voltage_input(path, coreVoltageInput, "Vcore")) goto error;
|
|
|
|
|
if(!find_current_input(path, coreCurrentInput, "Icore")) goto error;
|
|
|
|
|
if(!find_voltage_input(path, socVoltageInput, "Vsoc")) goto error;
|
|
|
|
|
if(!find_current_input(path, socCurrentInput, "Isoc")) goto error;
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
std::cerr << "hwmon: using input: " << coreVoltageInput << std::endl;
|
|
|
|
|
std::cerr << "hwmon: using input: " << coreCurrentInput << std::endl;
|
|
|
|
|
std::cerr << "hwmon: using input: " << socVoltageInput << std::endl;
|
|
|
|
|
std::cerr << "hwmon: using input: " << socCurrentInput << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
powerData->coreVoltageFile = fopen(coreVoltageInput.c_str(), "r");
|
|
|
|
|
powerData->coreCurrentFile = fopen(coreCurrentInput.c_str(), "r");
|
|
|
|
|
powerData->socVoltageFile = fopen(socVoltageInput.c_str(), "r");
|
|
|
|
|
powerData->socCurrentFile = fopen(socCurrentInput.c_str(), "r");
|
|
|
|
|
goto success;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
delete powerData;
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
return powerData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPUPowerData_zenpower* init_cpu_power_data_zenpower(const std::string path) {
|
|
|
|
|
CPUPowerData_zenpower* powerData = new CPUPowerData_zenpower();
|
|
|
|
|
|
|
|
|
|
std::string corePowerInput, socPowerInput;
|
|
|
|
|
|
|
|
|
|
if(!find_power_input(path, corePowerInput, "SVI2_P_Core")) goto error;
|
|
|
|
|
if(!find_power_input(path, socPowerInput, "SVI2_P_SoC")) goto error;
|
|
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
std::cerr << "hwmon: using input: " << corePowerInput << std::endl;
|
|
|
|
|
std::cerr << "hwmon: using input: " << socPowerInput << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
powerData->corePowerFile = fopen(corePowerInput.c_str(), "r");
|
|
|
|
|
powerData->socPowerFile = fopen(socPowerInput.c_str(), "r");
|
|
|
|
|
goto success;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
delete powerData;
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
return powerData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPUPowerData_rapl* init_cpu_power_data_rapl(const std::string path) {
|
|
|
|
|
CPUPowerData_rapl* powerData = new CPUPowerData_rapl();
|
|
|
|
|
|
|
|
|
|
std::string energyCounterPath = path + "/energy_uj";
|
|
|
|
|
if (!file_exists(energyCounterPath)) goto error;
|
|
|
|
|
|
|
|
|
|
powerData->energyCounterFile = fopen(energyCounterPath.c_str(), "r");
|
|
|
|
|
goto success;
|
|
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
delete powerData;
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
success:
|
|
|
|
|
return powerData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CPUStats::InitCpuPowerData() {
|
|
|
|
|
if(m_cpuPowerData != nullptr)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
std::string name, path;
|
|
|
|
|
std::string hwmon = "/sys/class/hwmon/";
|
|
|
|
|
|
|
|
|
|
CPUPowerData* cpuPowerData = nullptr;
|
|
|
|
|
|
|
|
|
|
auto dirs = ls(hwmon.c_str());
|
|
|
|
|
for (auto& dir : dirs) {
|
|
|
|
|
path = hwmon + dir;
|
|
|
|
|
name = read_line(path + "/name");
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
std::cerr << "hwmon: sensor name: " << name << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
if (name == "k10temp") {
|
|
|
|
|
cpuPowerData = (CPUPowerData*)init_cpu_power_data_k10temp(path);
|
|
|
|
|
break;
|
|
|
|
|
} else if (name == "zenpower") {
|
|
|
|
|
cpuPowerData = (CPUPowerData*)init_cpu_power_data_zenpower(path);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!cpuPowerData) {
|
|
|
|
|
std::string powercap = "/sys/class/powercap/";
|
|
|
|
|
auto powercap_dirs = ls(powercap.c_str());
|
|
|
|
|
for (auto& dir : powercap_dirs) {
|
|
|
|
|
path = powercap + dir;
|
|
|
|
|
name = read_line(path + "/name");
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
std::cerr << "powercap: name: " << name << std::endl;
|
|
|
|
|
#endif
|
|
|
|
|
if (name == "package-0") {
|
|
|
|
|
cpuPowerData = (CPUPowerData*)init_cpu_power_data_rapl(path);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(cpuPowerData == nullptr) {
|
|
|
|
|
std::cerr << "MANGOHUD: Failed to initialize CPU power data" << std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_cpuPowerData.reset(cpuPowerData);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CPUStats cpuStats;
|
|
|
|
|