Merge pull request #388 from flgx16/cpu_power

Add cpu_power
pull/400/head
flightlessmango 4 years ago committed by GitHub
commit ce6a87823b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -171,7 +171,7 @@ Parameters that are enabled by default have to be explicitly disabled. These (cu
| `log_interval` | Change the default log interval, `100` is default |
| `vulkan_driver` | Displays used vulkan driver, radv/amdgpu-pro/amdvlk |
| `gpu_name` | Displays GPU name from pci.ids |
| `gpu_power` | Display GPU draw in watts |
| `cpu_power`<br>`gpu_power` | Display CPU/GPU draw in watts |
| `engine_version` | Display OpenGL or vulkan and vulkan-based render engine's version |
| `permit_upload` | Allow uploading of logs to Flightlessmango.com |
| `upload_log` | Change keybind for uploading log |

@ -19,6 +19,7 @@
### Display the current CPU information
cpu_stats
# cpu_temp
# cpu_power
# cpu_text = "CPU"
# cpu_mhz
# cpu_load_change

@ -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;

@ -5,6 +5,9 @@
#include <vector>
#include <cstdint>
#include <cstdio>
#include <memory>
#include "timing.hpp"
typedef struct CPUData_ {
unsigned long long int totalTime;
@ -36,8 +39,73 @@ typedef struct CPUData_ {
int mhz;
int temp;
int cpu_mhz;
int power;
} CPUData;
enum {
CPU_POWER_K10TEMP,
CPU_POWER_ZENPOWER,
CPU_POWER_RAPL
};
struct CPUPowerData {
int source;
};
struct CPUPowerData_k10temp : public CPUPowerData {
CPUPowerData_k10temp() {
this->source = CPU_POWER_K10TEMP;
};
~CPUPowerData_k10temp() {
if(this->coreVoltageFile)
fclose(this->coreVoltageFile);
if(this->coreCurrentFile)
fclose(this->coreCurrentFile);
if(this->socVoltageFile)
fclose(this->socVoltageFile);
if(this->socCurrentFile)
fclose(this->socCurrentFile);
};
FILE* coreVoltageFile;
FILE* coreCurrentFile;
FILE* socVoltageFile;
FILE* socCurrentFile;
};
struct CPUPowerData_zenpower : public CPUPowerData {
CPUPowerData_zenpower() {
this->source = CPU_POWER_ZENPOWER;
};
~CPUPowerData_zenpower() {
if(this->corePowerFile)
fclose(this->corePowerFile);
if(this->socPowerFile)
fclose(this->socPowerFile);
};
FILE* corePowerFile;
FILE* socPowerFile;
};
struct CPUPowerData_rapl : public CPUPowerData {
CPUPowerData_rapl() {
this->source = CPU_POWER_RAPL;
this->lastCounterValueTime = Clock::now();
};
~CPUPowerData_rapl() {
if(this->energyCounterFile)
fclose(this->energyCounterFile);
};
FILE* energyCounterFile;
int lastCounterValue;
Clock::time_point lastCounterValueTime;
};
class CPUStats
{
public:
@ -52,7 +120,9 @@ public:
bool UpdateCPUData();
bool UpdateCoreMhz();
bool UpdateCpuTemp();
bool UpdateCpuPower();
bool GetCpuFile();
bool InitCpuPowerData();
double GetCPUPeriod() { return m_cpuPeriod; }
const std::vector<CPUData>& GetCPUData() const {
@ -70,6 +140,7 @@ private:
bool m_updatedCPUs = false; // TODO use caching or just update?
bool m_inited = false;
FILE *m_cpuTempFile = nullptr;
std::unique_ptr<CPUPowerData> m_cpuPowerData;
};
extern CPUStats cpuStats;

@ -115,7 +115,7 @@ void HudElements::cpu_stats(){
ImGui::SameLine(0, 1.0f);
ImGui::Text("°C");
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz])
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz] || HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_power])
ImGui::TableNextRow();
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_mhz]){
ImGui::TableNextCell();
@ -125,6 +125,14 @@ void HudElements::cpu_stats(){
ImGui::Text("MHz");
ImGui::PopFont();
}
if (HUDElements.params->enabled[OVERLAY_PARAM_ENABLED_cpu_power]){
ImGui::TableNextCell();
right_aligned_text(HUDElements.sw_stats->colors.text, HUDElements.ralign_width, "%i", cpuStats.GetCPUDataTotal().power);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(HUDElements.sw_stats->font1);
ImGui::Text("W");
ImGui::PopFont();
}
}
}

@ -26,6 +26,8 @@ void update_hw_info(struct swapchain_stats& sw_stats, struct overlay_params& par
cpuStats.UpdateCoreMhz();
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_temp] || logger->is_active())
cpuStats.UpdateCpuTemp();
if (params.enabled[OVERLAY_PARAM_ENABLED_cpu_power])
cpuStats.UpdateCpuPower();
#endif
}
if (params.enabled[OVERLAY_PARAM_ENABLED_gpu_stats] || logger->is_active()) {

@ -487,6 +487,7 @@ parse_overlay_config(struct overlay_params *params,
params->enabled[OVERLAY_PARAM_ENABLED_frame_timing] = true;
params->enabled[OVERLAY_PARAM_ENABLED_core_load] = false;
params->enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = false;
params->enabled[OVERLAY_PARAM_ENABLED_cpu_power] = false;
params->enabled[OVERLAY_PARAM_ENABLED_gpu_temp] = false;
params->enabled[OVERLAY_PARAM_ENABLED_cpu_stats] = true;
params->enabled[OVERLAY_PARAM_ENABLED_gpu_stats] = true;

@ -29,6 +29,7 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_BOOL(frame_timing) \
OVERLAY_PARAM_BOOL(core_load) \
OVERLAY_PARAM_BOOL(cpu_temp) \
OVERLAY_PARAM_BOOL(cpu_power) \
OVERLAY_PARAM_BOOL(gpu_temp) \
OVERLAY_PARAM_BOOL(cpu_stats) \
OVERLAY_PARAM_BOOL(gpu_stats) \

@ -466,6 +466,8 @@ void init_cpu_stats(overlay_params& params)
&& enabled[OVERLAY_PARAM_ENABLED_cpu_stats];
enabled[OVERLAY_PARAM_ENABLED_cpu_temp] = cpuStats.GetCpuFile()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_temp];
enabled[OVERLAY_PARAM_ENABLED_cpu_power] = cpuStats.InitCpuPowerData()
&& enabled[OVERLAY_PARAM_ENABLED_cpu_power];
#endif
}

Loading…
Cancel
Save