2020-02-01 23:55:24 +00:00
|
|
|
#include "cpu.h"
|
2020-11-28 23:41:14 +00:00
|
|
|
#include <memory>
|
2020-02-01 23:55:24 +00:00
|
|
|
#include <string>
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <regex>
|
2021-04-05 10:36:34 +00:00
|
|
|
#include <inttypes.h>
|
2021-07-16 00:28:46 +00:00
|
|
|
#include <spdlog/spdlog.h>
|
2020-02-04 08:11:51 +00:00
|
|
|
#include "string_utils.h"
|
2022-01-14 21:41:38 +00:00
|
|
|
#include "hud_elements.h"
|
|
|
|
#include "overlay.h"
|
|
|
|
#include "amdgpu.h"
|
2020-02-01 23:55:24 +00:00
|
|
|
|
|
|
|
#ifndef PROCDIR
|
|
|
|
#define PROCDIR "/proc"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PROCSTATFILE
|
|
|
|
#define PROCSTATFILE PROCDIR "/stat"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PROCMEMINFOFILE
|
|
|
|
#define PROCMEMINFOFILE PROCDIR "/meminfo"
|
|
|
|
#endif
|
|
|
|
|
2020-03-10 05:19:18 +00:00
|
|
|
#include "file_utils.h"
|
|
|
|
|
2020-02-02 00:12:01 +00:00
|
|
|
void calculateCPUData(CPUData& cpuData,
|
2020-03-13 14:35:11 +00:00
|
|
|
unsigned long long int usertime,
|
|
|
|
unsigned long long int nicetime,
|
|
|
|
unsigned long long int systemtime,
|
|
|
|
unsigned long long int idletime,
|
|
|
|
unsigned long long int ioWait,
|
|
|
|
unsigned long long int irq,
|
|
|
|
unsigned long long int softIrq,
|
|
|
|
unsigned long long int steal,
|
|
|
|
unsigned long long int guest,
|
|
|
|
unsigned long long int guestnice)
|
2020-02-02 00:12:01 +00:00
|
|
|
{
|
2020-03-13 14:35:11 +00:00
|
|
|
// Guest time is already accounted in usertime
|
|
|
|
usertime = usertime - guest;
|
|
|
|
nicetime = nicetime - guestnice;
|
|
|
|
// Fields existing on kernels >= 2.6
|
|
|
|
// (and RHEL's patched kernel 2.4...)
|
|
|
|
unsigned long long int idlealltime = idletime + ioWait;
|
|
|
|
unsigned long long int systemalltime = systemtime + irq + softIrq;
|
|
|
|
unsigned long long int virtalltime = guest + guestnice;
|
|
|
|
unsigned long long int totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
|
|
|
|
|
|
|
|
// Since we do a subtraction (usertime - guest) and cputime64_to_clock_t()
|
|
|
|
// used in /proc/stat rounds down numbers, it can lead to a case where the
|
|
|
|
// integer overflow.
|
|
|
|
#define WRAP_SUBTRACT(a,b) (a > b) ? a - b : 0
|
|
|
|
cpuData.userPeriod = WRAP_SUBTRACT(usertime, cpuData.userTime);
|
|
|
|
cpuData.nicePeriod = WRAP_SUBTRACT(nicetime, cpuData.niceTime);
|
|
|
|
cpuData.systemPeriod = WRAP_SUBTRACT(systemtime, cpuData.systemTime);
|
|
|
|
cpuData.systemAllPeriod = WRAP_SUBTRACT(systemalltime, cpuData.systemAllTime);
|
|
|
|
cpuData.idleAllPeriod = WRAP_SUBTRACT(idlealltime, cpuData.idleAllTime);
|
|
|
|
cpuData.idlePeriod = WRAP_SUBTRACT(idletime, cpuData.idleTime);
|
|
|
|
cpuData.ioWaitPeriod = WRAP_SUBTRACT(ioWait, cpuData.ioWaitTime);
|
|
|
|
cpuData.irqPeriod = WRAP_SUBTRACT(irq, cpuData.irqTime);
|
|
|
|
cpuData.softIrqPeriod = WRAP_SUBTRACT(softIrq, cpuData.softIrqTime);
|
|
|
|
cpuData.stealPeriod = WRAP_SUBTRACT(steal, cpuData.stealTime);
|
|
|
|
cpuData.guestPeriod = WRAP_SUBTRACT(virtalltime, cpuData.guestTime);
|
|
|
|
cpuData.totalPeriod = WRAP_SUBTRACT(totaltime, cpuData.totalTime);
|
|
|
|
#undef WRAP_SUBTRACT
|
|
|
|
cpuData.userTime = usertime;
|
|
|
|
cpuData.niceTime = nicetime;
|
|
|
|
cpuData.systemTime = systemtime;
|
|
|
|
cpuData.systemAllTime = systemalltime;
|
|
|
|
cpuData.idleAllTime = idlealltime;
|
|
|
|
cpuData.idleTime = idletime;
|
|
|
|
cpuData.ioWaitTime = ioWait;
|
|
|
|
cpuData.irqTime = irq;
|
|
|
|
cpuData.softIrqTime = softIrq;
|
|
|
|
cpuData.stealTime = steal;
|
|
|
|
cpuData.guestTime = virtalltime;
|
|
|
|
cpuData.totalTime = totaltime;
|
|
|
|
|
|
|
|
if (cpuData.totalPeriod == 0)
|
|
|
|
return;
|
|
|
|
float total = (float)cpuData.totalPeriod;
|
|
|
|
float v[4];
|
|
|
|
v[0] = cpuData.nicePeriod * 100.0f / total;
|
|
|
|
v[1] = cpuData.userPeriod * 100.0f / total;
|
|
|
|
|
|
|
|
/* if not detailed */
|
|
|
|
v[2] = cpuData.systemAllPeriod * 100.0f / total;
|
|
|
|
v[3] = (cpuData.stealPeriod + cpuData.guestPeriod) * 100.0f / total;
|
|
|
|
//cpuData.percent = std::clamp(v[0]+v[1]+v[2]+v[3], 0.0f, 100.0f);
|
|
|
|
cpuData.percent = std::min(std::max(v[0]+v[1]+v[2]+v[3], 0.0f), 100.0f);
|
2020-02-02 00:12:01 +00:00
|
|
|
}
|
2020-02-01 23:55:24 +00:00
|
|
|
|
|
|
|
CPUStats::CPUStats()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-14 20:59:43 +00:00
|
|
|
CPUStats::~CPUStats()
|
|
|
|
{
|
|
|
|
if (m_cpuTempFile)
|
|
|
|
fclose(m_cpuTempFile);
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:55:24 +00:00
|
|
|
bool CPUStats::Init()
|
|
|
|
{
|
2020-03-13 13:57:04 +00:00
|
|
|
if (m_inited)
|
|
|
|
return true;
|
2020-03-14 20:59:43 +00:00
|
|
|
|
2020-03-13 14:35:11 +00:00
|
|
|
std::string line;
|
|
|
|
std::ifstream file (PROCSTATFILE);
|
|
|
|
bool first = true;
|
|
|
|
m_cpuData.clear();
|
|
|
|
|
|
|
|
if (!file.is_open()) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_ERROR("Failed to opening " PROCSTATFILE);
|
2020-03-13 14:35:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (!std::getline(file, line)) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("Failed to read all of " PROCSTATFILE);
|
2020-03-13 14:35:11 +00:00
|
|
|
return false;
|
|
|
|
} else if (starts_with(line, "cpu")) {
|
|
|
|
if (first) {
|
|
|
|
first =false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
CPUData cpu = {};
|
|
|
|
cpu.totalTime = 1;
|
|
|
|
cpu.totalPeriod = 1;
|
|
|
|
m_cpuData.push_back(cpu);
|
|
|
|
|
|
|
|
} else if (starts_with(line, "btime ")) {
|
|
|
|
|
|
|
|
// C++ way, kind of noisy
|
|
|
|
//std::istringstream token( line );
|
|
|
|
//std::string s;
|
|
|
|
//token >> s;
|
|
|
|
//token >> m_boottime;
|
|
|
|
|
|
|
|
// assume that if btime got read, that everything else is OK too
|
|
|
|
sscanf(line.c_str(), "btime %lld\n", &m_boottime);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(true);
|
|
|
|
|
|
|
|
m_inited = true;
|
|
|
|
return UpdateCPUData();
|
2020-02-01 23:55:24 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 13:50:02 +00:00
|
|
|
bool CPUStats::Reinit()
|
|
|
|
{
|
|
|
|
m_inited = false;
|
|
|
|
return Init();
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:55:24 +00:00
|
|
|
//TODO take sampling interval into account?
|
|
|
|
bool CPUStats::UpdateCPUData()
|
|
|
|
{
|
2020-03-13 14:35:11 +00:00
|
|
|
unsigned long long int usertime, nicetime, systemtime, idletime;
|
|
|
|
unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
|
|
|
|
int cpuid = -1;
|
2021-01-30 13:50:02 +00:00
|
|
|
size_t cpu_count = 0;
|
2020-03-13 14:35:11 +00:00
|
|
|
|
|
|
|
if (!m_inited)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
std::ifstream file (PROCSTATFILE);
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
if (!file.is_open()) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_ERROR("Failed to opening " PROCSTATFILE);
|
2020-03-13 14:35:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
do {
|
|
|
|
if (!std::getline(file, line)) {
|
|
|
|
break;
|
|
|
|
} else if (!ret && sscanf(line.c_str(), "cpu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
|
|
|
|
&usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 10) {
|
|
|
|
ret = true;
|
|
|
|
calculateCPUData(m_cpuDataTotal, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
|
|
|
|
} else if (sscanf(line.c_str(), "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu",
|
|
|
|
&cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice) == 11) {
|
|
|
|
|
2021-07-21 16:48:45 +00:00
|
|
|
//SPDLOG_DEBUG("Parsing 'cpu{}' line:{}", cpuid, line);
|
2020-03-13 14:35:11 +00:00
|
|
|
|
|
|
|
if (!ret) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("Failed to parse 'cpu' line:{}", line);
|
2020-03-13 14:35:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-30 13:50:02 +00:00
|
|
|
if (cpuid < 0 /* can it? */) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("Cpu id '{}' is out of bounds", cpuid);
|
2020-03-13 14:35:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-30 13:50:02 +00:00
|
|
|
if ((size_t)cpuid >= m_cpuData.size()) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("Cpu id '{}' is out of bounds, reiniting", cpuid);
|
2021-01-30 13:50:02 +00:00
|
|
|
return Reinit();
|
|
|
|
}
|
|
|
|
|
2020-03-13 14:35:11 +00:00
|
|
|
CPUData& cpuData = m_cpuData[cpuid];
|
|
|
|
calculateCPUData(cpuData, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
|
|
|
|
cpuid = -1;
|
2021-01-30 13:50:02 +00:00
|
|
|
cpu_count++;
|
2020-03-13 14:35:11 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while(true);
|
|
|
|
|
2021-01-30 13:50:02 +00:00
|
|
|
if (cpu_count < m_cpuData.size())
|
|
|
|
m_cpuData.resize(cpu_count);
|
|
|
|
|
2020-03-13 14:35:11 +00:00
|
|
|
m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size();
|
|
|
|
m_updatedCPUs = true;
|
|
|
|
return ret;
|
2020-02-01 23:55:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CPUStats::UpdateCoreMhz() {
|
2020-02-02 00:12:01 +00:00
|
|
|
m_coreMhz.clear();
|
2021-12-30 22:59:04 +00:00
|
|
|
FILE *fp;
|
2021-12-14 17:49:23 +00:00
|
|
|
for (size_t i = 0; i < m_cpuData.size(); i++)
|
|
|
|
{
|
2021-12-30 22:59:04 +00:00
|
|
|
std::string path = "/sys/devices/system/cpu/cpu" + std::to_string(i) + "/cpufreq/scaling_cur_freq";
|
2022-01-19 15:06:40 +00:00
|
|
|
if ((fp = fopen(path.c_str(), "r"))){
|
2022-03-06 15:45:17 +00:00
|
|
|
int64_t temp;
|
|
|
|
if (fscanf(fp, "%" PRId64, &temp) != 1)
|
|
|
|
temp = 0;
|
|
|
|
m_cpuData[i].mhz = temp / 1000;
|
2021-12-30 22:59:04 +00:00
|
|
|
fclose(fp);
|
|
|
|
}
|
2020-02-01 23:55:24 +00:00
|
|
|
}
|
2022-02-17 03:52:15 +00:00
|
|
|
|
2020-11-11 22:11:21 +00:00
|
|
|
m_cpuDataTotal.cpu_mhz = 0;
|
|
|
|
for (auto data : m_cpuData)
|
2021-12-14 17:49:23 +00:00
|
|
|
if (data.mhz > m_cpuDataTotal.cpu_mhz)
|
|
|
|
m_cpuDataTotal.cpu_mhz = data.mhz;
|
2021-11-03 00:06:15 +00:00
|
|
|
|
2020-02-01 23:55:24 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-13 14:35:11 +00:00
|
|
|
bool CPUStats::UpdateCpuTemp() {
|
2022-01-14 21:41:38 +00:00
|
|
|
#ifdef MANGOAPP
|
2022-02-06 20:56:33 +00:00
|
|
|
m_cpuDataTotal.temp = gpu_info.apu_cpu_temp;
|
2022-01-14 21:41:38 +00:00
|
|
|
#else
|
2020-03-14 20:59:43 +00:00
|
|
|
if (!m_cpuTempFile)
|
|
|
|
return false;
|
|
|
|
|
2020-08-11 18:45:42 +00:00
|
|
|
int temp = 0;
|
2020-03-14 20:59:43 +00:00
|
|
|
rewind(m_cpuTempFile);
|
|
|
|
fflush(m_cpuTempFile);
|
2020-08-11 18:45:42 +00:00
|
|
|
bool ret = (fscanf(m_cpuTempFile, "%d", &temp) == 1);
|
|
|
|
m_cpuDataTotal.temp = temp / 1000;
|
2020-03-10 05:19:18 +00:00
|
|
|
|
2020-08-11 18:45:42 +00:00
|
|
|
return ret;
|
2022-01-14 21:41:38 +00:00
|
|
|
#endif
|
|
|
|
return true;
|
2020-03-10 05:19:18 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 03:34:17 +00:00
|
|
|
static bool get_cpu_power_k10temp(CPUPowerData* cpuPowerData, float& power) {
|
2020-11-12 21:27:35 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-02-07 03:34:17 +00:00
|
|
|
static bool get_cpu_power_zenpower(CPUPowerData* cpuPowerData, float& power) {
|
2020-11-12 21:27:35 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-02-07 03:34:17 +00:00
|
|
|
static bool get_cpu_power_rapl(CPUPowerData* cpuPowerData, float& power) {
|
2020-11-12 21:27:35 +00:00
|
|
|
CPUPowerData_rapl* powerData_rapl = (CPUPowerData_rapl*)cpuPowerData;
|
|
|
|
|
|
|
|
if (!powerData_rapl->energyCounterFile)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rewind(powerData_rapl->energyCounterFile);
|
|
|
|
fflush(powerData_rapl->energyCounterFile);
|
|
|
|
|
2021-04-05 10:36:34 +00:00
|
|
|
uint64_t energyCounterValue = 0;
|
|
|
|
if (fscanf(powerData_rapl->energyCounterFile, "%" SCNu64, &energyCounterValue) != 1)
|
2020-11-12 21:27:35 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
Clock::time_point now = Clock::now();
|
|
|
|
Clock::duration timeDiff = now - powerData_rapl->lastCounterValueTime;
|
2021-04-05 10:36:34 +00:00
|
|
|
int64_t timeDiffMicro = std::chrono::duration_cast<std::chrono::microseconds>(timeDiff).count();
|
|
|
|
uint64_t energyCounterDiff = energyCounterValue - powerData_rapl->lastCounterValue;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
2021-04-05 10:36:34 +00:00
|
|
|
if (powerData_rapl->lastCounterValue > 0 && energyCounterValue > powerData_rapl->lastCounterValue)
|
|
|
|
power = energyCounterDiff / timeDiffMicro;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
powerData_rapl->lastCounterValue = energyCounterValue;
|
|
|
|
powerData_rapl->lastCounterValueTime = now;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-02-07 03:34:17 +00:00
|
|
|
static bool get_cpu_power_amdgpu(float& power) {
|
|
|
|
power = gpu_info.apu_cpu_power;
|
2022-01-14 21:41:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-11-12 21:27:35 +00:00
|
|
|
bool CPUStats::UpdateCpuPower() {
|
|
|
|
if(!m_cpuPowerData)
|
|
|
|
return false;
|
|
|
|
|
2022-02-07 03:34:17 +00:00
|
|
|
float power = 0;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
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;
|
2022-01-14 21:41:38 +00:00
|
|
|
case CPU_POWER_AMDGPU:
|
|
|
|
if (!get_cpu_power_amdgpu(power)) return false;
|
|
|
|
break;
|
2020-11-12 21:27:35 +00:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cpuDataTotal.power = power;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-14 10:49:56 +00:00
|
|
|
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);
|
|
|
|
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_fallback_temp_input(const std::string path, std::string& input)
|
|
|
|
{
|
|
|
|
auto files = ls(path.c_str(), "temp", LS_FILES);
|
|
|
|
if (!files.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::sort(files.begin(), files.end());
|
|
|
|
for (auto& file : files) {
|
|
|
|
if (!ends_with(file, "_input"))
|
|
|
|
continue;
|
|
|
|
input = path + "/" + file;
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("fallback cpu temp input: {}", input);
|
2020-05-14 10:49:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-13 14:35:11 +00:00
|
|
|
bool CPUStats::GetCpuFile() {
|
2020-03-14 20:59:43 +00:00
|
|
|
if (m_cpuTempFile)
|
|
|
|
return true;
|
|
|
|
|
2020-05-14 10:49:56 +00:00
|
|
|
std::string name, path, input;
|
2020-03-13 14:35:11 +00:00
|
|
|
std::string hwmon = "/sys/class/hwmon/";
|
|
|
|
|
|
|
|
auto dirs = ls(hwmon.c_str());
|
|
|
|
for (auto& dir : dirs) {
|
|
|
|
path = hwmon + dir;
|
|
|
|
name = read_line(path + "/name");
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("hwmon: sensor name: {}", name);
|
2021-07-16 00:28:46 +00:00
|
|
|
|
2020-06-25 14:29:26 +00:00
|
|
|
if (name == "coretemp") {
|
|
|
|
find_temp_input(path, input, "Package id 0");
|
2020-05-14 10:49:56 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-06-25 14:29:26 +00:00
|
|
|
else if ((name == "zenpower" || name == "k10temp")) {
|
|
|
|
find_temp_input(path, input, "Tdie");
|
2020-03-13 14:35:11 +00:00
|
|
|
break;
|
2020-06-25 14:29:26 +00:00
|
|
|
} else if (name == "atk0110") {
|
|
|
|
find_temp_input(path, input, "CPU Temperature");
|
2022-02-17 03:52:15 +00:00
|
|
|
break;
|
2020-08-03 17:34:40 +00:00
|
|
|
} else {
|
|
|
|
path.clear();
|
2020-03-13 14:35:11 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-14 21:41:38 +00:00
|
|
|
#ifndef MANGOAPP
|
2020-08-03 17:34:40 +00:00
|
|
|
if (path.empty() || (!file_exists(input) && !find_fallback_temp_input(path, input))) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_ERROR("Could not find cpu temp sensor location");
|
2020-03-14 20:59:43 +00:00
|
|
|
return false;
|
2020-03-13 14:35:11 +00:00
|
|
|
} else {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", input);
|
2020-05-14 10:49:56 +00:00
|
|
|
m_cpuTempFile = fopen(input.c_str(), "r");
|
2020-03-13 14:35:11 +00:00
|
|
|
}
|
2022-01-14 21:41:38 +00:00
|
|
|
#endif
|
2020-03-13 14:35:11 +00:00
|
|
|
return true;
|
2020-03-10 05:19:18 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 12:51:01 +00:00
|
|
|
static bool find_input(const std::string& path, const char* input_prefix, std::string& input, const std::string& name)
|
2020-11-12 21:27:35 +00:00
|
|
|
{
|
2021-01-30 12:51:01 +00:00
|
|
|
auto files = ls(path.c_str(), input_prefix, LS_FILES);
|
2020-11-12 21:27:35 +00:00
|
|
|
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) {
|
2020-11-28 23:41:14 +00:00
|
|
|
auto powerData = std::make_unique<CPUPowerData_k10temp>();
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
std::string coreVoltageInput, coreCurrentInput;
|
|
|
|
std::string socVoltageInput, socCurrentInput;
|
|
|
|
|
2021-01-30 12:51:01 +00:00
|
|
|
if(!find_input(path, "in", coreVoltageInput, "Vcore")) return nullptr;
|
|
|
|
if(!find_input(path, "curr", coreCurrentInput, "Icore")) return nullptr;
|
|
|
|
if(!find_input(path, "in", socVoltageInput, "Vsoc")) return nullptr;
|
|
|
|
if(!find_input(path, "curr", socCurrentInput, "Isoc")) return nullptr;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", coreVoltageInput);
|
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", coreCurrentInput);
|
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", socVoltageInput);
|
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", socCurrentInput);
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2020-11-28 23:41:14 +00:00
|
|
|
return powerData.release();
|
2020-11-12 21:27:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CPUPowerData_zenpower* init_cpu_power_data_zenpower(const std::string path) {
|
2020-11-28 23:41:14 +00:00
|
|
|
auto powerData = std::make_unique<CPUPowerData_zenpower>();
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
std::string corePowerInput, socPowerInput;
|
|
|
|
|
2021-01-30 12:51:01 +00:00
|
|
|
if(!find_input(path, "power", corePowerInput, "SVI2_P_Core")) return nullptr;
|
|
|
|
if(!find_input(path, "power", socPowerInput, "SVI2_P_SoC")) return nullptr;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", corePowerInput);
|
|
|
|
SPDLOG_DEBUG("hwmon: using input: {}", socPowerInput);
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
powerData->corePowerFile = fopen(corePowerInput.c_str(), "r");
|
|
|
|
powerData->socPowerFile = fopen(socPowerInput.c_str(), "r");
|
|
|
|
|
2020-11-28 23:41:14 +00:00
|
|
|
return powerData.release();
|
2020-11-12 21:27:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CPUPowerData_rapl* init_cpu_power_data_rapl(const std::string path) {
|
2020-11-28 23:41:14 +00:00
|
|
|
auto powerData = std::make_unique<CPUPowerData_rapl>();
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
std::string energyCounterPath = path + "/energy_uj";
|
2020-11-28 23:41:14 +00:00
|
|
|
if (!file_exists(energyCounterPath)) return nullptr;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
powerData->energyCounterFile = fopen(energyCounterPath.c_str(), "r");
|
|
|
|
|
2020-11-28 23:41:14 +00:00
|
|
|
return powerData.release();
|
2020-11-12 21:27:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CPUStats::InitCpuPowerData() {
|
|
|
|
if(m_cpuPowerData != nullptr)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
std::string name, path;
|
|
|
|
std::string hwmon = "/sys/class/hwmon/";
|
2022-01-14 21:41:38 +00:00
|
|
|
bool intel = false;
|
2020-11-12 21:27:35 +00:00
|
|
|
|
|
|
|
CPUPowerData* cpuPowerData = nullptr;
|
|
|
|
|
|
|
|
auto dirs = ls(hwmon.c_str());
|
|
|
|
for (auto& dir : dirs) {
|
|
|
|
path = hwmon + dir;
|
|
|
|
name = read_line(path + "/name");
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("hwmon: sensor name: {}", name);
|
2021-07-16 00:28:46 +00:00
|
|
|
|
2020-11-12 21:27:35 +00:00
|
|
|
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;
|
2022-01-14 21:41:38 +00:00
|
|
|
} else if (name == "coretemp") {
|
|
|
|
intel = true;
|
2020-11-12 21:27:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-14 21:41:38 +00:00
|
|
|
if (!cpuPowerData && intel) {
|
2020-11-12 21:27:35 +00:00
|
|
|
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");
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("powercap: name: {}", name);
|
2020-11-12 21:27:35 +00:00
|
|
|
if (name == "package-0") {
|
|
|
|
cpuPowerData = (CPUPowerData*)init_cpu_power_data_rapl(path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-02-17 03:52:15 +00:00
|
|
|
}
|
|
|
|
if (!cpuPowerData && !intel) {
|
2022-01-14 21:41:38 +00:00
|
|
|
auto powerData = std::make_unique<CPUPowerData_amdgpu>();
|
|
|
|
cpuPowerData = (CPUPowerData*)powerData.release();
|
2020-11-12 21:27:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(cpuPowerData == nullptr) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_ERROR("Failed to initialize CPU power data");
|
2020-11-12 21:27:35 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cpuPowerData.reset(cpuPowerData);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-10 12:11:56 +00:00
|
|
|
CPUStats cpuStats;
|