Merge branch 'cpu'

pull/20/head
FlightlessMango 4 years ago
commit 3d711005d4

@ -0,0 +1,220 @@
#include "cpu.h"
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <string.h>
#include <algorithm>
#include <regex>
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif
#ifndef PROCSTATFILE
#define PROCSTATFILE PROCDIR "/stat"
#endif
#ifndef PROCMEMINFOFILE
#define PROCMEMINFOFILE PROCDIR "/meminfo"
#endif
#ifndef PROCCPUINFOFILE
#define PROCCPUINFOFILE PROCDIR "/cpuinfo"
#endif
static bool starts_with(const std::string& s, const char *t){
return s.rfind(t, 0) == 0;
}
void calculateCPUData(CPUData& cpuData,
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)
{
// 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);
}
CPUStats::CPUStats()
{
m_inited = Init();
}
bool CPUStats::Init()
{
std::string line;
std::ifstream file (PROCSTATFILE);
bool first = true;
m_cpuData.clear();
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
return false;
}
do {
if (!std::getline(file, line)) {
std::cerr << "Failed to read all of " << PROCSTATFILE << std::endl;
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);
UpdateCPUData();
return true;
}
//TODO take sampling interval into account?
bool CPUStats::UpdateCPUData()
{
CPUStats::UpdateCoreMhz();
unsigned long long int usertime, nicetime, systemtime, idletime;
unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
int cpuid = -1;
if (!m_inited)
return false;
std::string line;
std::ifstream file (PROCSTATFILE);
bool ret = false;
if (!file.is_open()) {
std::cerr << "Failed to opening " << PROCSTATFILE << std::endl;
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) {
//std::cerr << "Parsing 'cpu" << cpuid << "' line:" << line << std::endl;
if (!ret) {
//std::cerr << "Failed to parse 'cpu' line" << std::endl;
std::cerr << "Failed to parse 'cpu' line:" << line << std::endl;
return false;
}
if (cpuid < 0 /* can it? */ || (size_t)cpuid > m_cpuData.size()) {
std::cerr << "Cpu id '" << cpuid << "' is out of bounds" << std::endl;
return false;
}
CPUData& cpuData = m_cpuData[cpuid];
calculateCPUData(cpuData, usertime, nicetime, systemtime, idletime, ioWait, irq, softIrq, steal, guest, guestnice);
cpuid = -1;
} else {
break;
}
} while(true);
m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size();
m_updatedCPUs = true;
return ret;
}
bool CPUStats::UpdateCoreMhz() {
m_coreMhz.clear();
std::ifstream cpuInfo(PROCCPUINFOFILE);
std::string row;
int i = 0;
while (std::getline(cpuInfo, row)) {
CPUData& cpuData = m_cpuData[i];
if (row.find("MHz") != std::string::npos){
row = std::regex_replace(row, std::regex(R"([^0-9.])"), "");
cpuData.mhz = stoi(row);
i++;
}
}
return true;
}
CPUStats cpuStats;

@ -0,0 +1,64 @@
#include <vector>
#include <cstdint>
typedef struct CPUData_ {
unsigned long long int totalTime;
unsigned long long int userTime;
unsigned long long int systemTime;
unsigned long long int systemAllTime;
unsigned long long int idleAllTime;
unsigned long long int idleTime;
unsigned long long int niceTime;
unsigned long long int ioWaitTime;
unsigned long long int irqTime;
unsigned long long int softIrqTime;
unsigned long long int stealTime;
unsigned long long int guestTime;
unsigned long long int totalPeriod;
unsigned long long int userPeriod;
unsigned long long int systemPeriod;
unsigned long long int systemAllPeriod;
unsigned long long int idleAllPeriod;
unsigned long long int idlePeriod;
unsigned long long int nicePeriod;
unsigned long long int ioWaitPeriod;
unsigned long long int irqPeriod;
unsigned long long int softIrqPeriod;
unsigned long long int stealPeriod;
unsigned long long int guestPeriod;
float percent;
int mhz;
} CPUData;
class CPUStats
{
public:
CPUStats();
bool Init();
bool Updated()
{
return m_updatedCPUs;
}
bool UpdateCPUData();
bool UpdateCoreMhz();
double GetCPUPeriod() { return m_cpuPeriod; }
const std::vector<CPUData>& GetCPUData() const {
return m_cpuData;
}
const CPUData& GetCPUDataTotal() const {
return m_cpuDataTotal;
}
private:
unsigned long long int m_boottime = 0;
std::vector<CPUData> m_cpuData;
CPUData m_cpuDataTotal {};
std::vector<int> m_coreMhz;
double m_cpuPeriod = 0;
bool m_updatedCPUs = false; // TODO use caching or just update?
bool m_inited = false;
};
extern CPUStats cpuStats;

@ -23,19 +23,10 @@ int gpuLoad, gpuTemp, cpuTemp;
string gpuLoadDisplay, cpuTempLocation;
FILE *amdGpuFile, *amdTempFile, *cpuTempFile;
const int NUM_CPU_STATES = 10;
struct Cpus{
size_t num;
string name;
int value;
string output;
int freq;
};
int numCpuCores = std::thread::hardware_concurrency();
size_t arraySize = numCpuCores + 1;
std::vector<Cpus> cpuArray;
// std::vector<Cpus> cpuArray;
pthread_t cpuThread, gpuThread, cpuInfoThread, nvidiaSmiThread;
string exec(string command) {
@ -60,126 +51,8 @@ string exec(string command) {
return result;
}
void coreCounting(){
cpuArray.push_back({0, "CPU:"});
for (size_t i = 0; i < arraySize; i++) {
size_t offset = i;
stringstream ss;
ss << "CPU " << offset << ":";
string cpuNameString = ss.str();
cpuArray.push_back({i+1 , cpuNameString});
}
}
std::string m_cpuUtilizationString;
enum CPUStates
{
S_USER = 0,
S_NICE,
S_SYSTEM,
S_IDLE,
S_IOWAIT,
S_IRQ,
S_SOFTIRQ,
S_STEAL,
S_GUEST,
S_GUEST_NICE
};
typedef struct CPUData
{
std::string cpu;
size_t times[NUM_CPU_STATES];
} CPUData;
void ReadStatsCPU(std::vector<CPUData> & entries)
{
std::ifstream fileStat("/proc/stat");
std::string line;
const std::string STR_CPU("cpu");
const std::size_t LEN_STR_CPU = STR_CPU.size();
const std::string STR_TOT("tot");
while(std::getline(fileStat, line))
{
// cpu stats line found
if(!line.compare(0, LEN_STR_CPU, STR_CPU))
{
std::istringstream ss(line);
// store entry
entries.emplace_back(CPUData());
CPUData & entry = entries.back();
// read cpu label
ss >> entry.cpu;
if(entry.cpu.size() > LEN_STR_CPU)
entry.cpu.erase(0, LEN_STR_CPU);
else
entry.cpu = STR_TOT;
// read times
for(int i = 0; i < NUM_CPU_STATES; ++i)
ss >> entry.times[i];
}
}
}
size_t GetIdleTime(const CPUData & e)
{
return e.times[S_IDLE] +
e.times[S_IOWAIT];
}
size_t GetActiveTime(const CPUData & e)
{
return e.times[S_USER] +
e.times[S_NICE] +
e.times[S_SYSTEM] +
e.times[S_IRQ] +
e.times[S_SOFTIRQ] +
e.times[S_STEAL] +
e.times[S_GUEST] +
e.times[S_GUEST_NICE];
}
void PrintStats(const std::vector<CPUData> & entries1, const std::vector<CPUData> & entries2)
{
const size_t NUM_ENTRIES = entries1.size();
for(size_t i = 0; i < NUM_ENTRIES; ++i)
{
const CPUData & e1 = entries1[i];
const CPUData & e2 = entries2[i];
const float ACTIVE_TIME = static_cast<float>(GetActiveTime(e2) - GetActiveTime(e1));
const float IDLE_TIME = static_cast<float>(GetIdleTime(e2) - GetIdleTime(e1));
const float TOTAL_TIME = ACTIVE_TIME + IDLE_TIME;
cpuArray[i].value = (truncf(100.f * ACTIVE_TIME / TOTAL_TIME) * 10 / 10);
}
}
void *cpuInfo(void *){
FILE *cpuInfo = fopen("/proc/cpuinfo", "r");
char line[256];
int i = 0;
while (fgets(line, sizeof(line), cpuInfo)) {
std::string row;
row = line;
if (row.find("MHz") != std::string::npos){
row = std::regex_replace(row, std::regex(R"([^0-9.])"), "");
cpuArray[i + 1].freq = stoi(row);
i++;
}
}
fclose(cpuInfo);
char buff[6];
rewind(cpuTempFile);
fflush(cpuTempFile);
@ -223,48 +96,3 @@ void *getAmdGpuUsage(void *){
pthread_detach(gpuThread);
return NULL;
}
void *getCpuUsage(void *)
{
std::vector<CPUData> entries1;
std::vector<CPUData> entries2;
// snapshot 1
ReadStatsCPU(entries1);
// 100ms pause
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// snapshot 2
ReadStatsCPU(entries2);
// print output
PrintStats(entries1, entries2);
pthread_detach(cpuThread);
return NULL;
}
void updateCpuStrings(){
for (size_t i = 0; i < arraySize; i++) {
size_t spacing = 10;
string value = to_string(cpuArray[i].value);
value.erase( value.find_last_not_of('0') + 1, std::string::npos );
size_t correctionValue = (spacing - cpuArray[i].name.length()) - value.length();
string correction = "";
for (size_t i = 0; i < correctionValue; i++) {
correction.append(" ");
}
stringstream ss;
if (i < 11) {
if (i == 0) {
ss << cpuArray[i].name << " " << cpuArray[i].value << "%";
} else {
ss << cpuArray[i].name << correction << cpuArray[i].value << "%";
}
} else {
ss << cpuArray[i].name << correction << cpuArray[i].value << "%";
}
cpuArray[i].output = ss.str();
}
}

@ -35,6 +35,7 @@ vklayer_files = files(
'overlay.cpp',
'overlay_params.c',
'font_unispace.c',
'cpu.cpp',
)
dep_nvml = cc.find_library('nvidia-ml', required: false)

@ -47,6 +47,7 @@
#include "cpu_gpu.h"
#include "logging.h"
#include "keybinds.h"
#include "cpu.h"
bool open = false, displayHud = true;
string gpuString;
@ -846,7 +847,7 @@ static void snapshot_swapchain_frame(struct swapchain_data *data)
if(log_duration_env)
duration = std::stoi(log_duration_env);
coreCounting();
// coreCounting();
if (deviceName.find("Radeon") != std::string::npos || deviceName.find("AMD") != std::string::npos) {
amdGpuFile = fopen("/sys/class/drm/card0/device/gpu_busy_percent", "r");
string tempFolder = exec("ls /sys/class/drm/card0/device/hwmon/");
@ -907,9 +908,8 @@ static void snapshot_swapchain_frame(struct swapchain_data *data)
if (data->last_fps_update) {
if (capture_begin ||
elapsed >= instance_data->params.fps_sampling_period) {
updateCpuStrings();
pthread_create(&cpuThread, NULL, &getCpuUsage, NULL);
data->cpuString = cpuArray[0].output.c_str();
cpuStats.UpdateCPUData();
cpuLoadLog = cpuStats.GetCPUDataTotal().percent;
pthread_create(&cpuInfoThread, NULL, &cpuInfo, NULL);
// get gpu usage
@ -920,7 +920,7 @@ static void snapshot_swapchain_frame(struct swapchain_data *data)
pthread_create(&gpuThread, NULL, &getAmdGpuUsage, NULL);
// update variables for logging
cpuLoadLog = cpuArray[0].value;
// cpuLoadLog = cpuArray[0].value;
gpuLoadLog = gpuLoad;
data->frametimeDisplay = data->frametime;
@ -1090,7 +1090,8 @@ static void compute_swapchain_display(struct swapchain_data *data)
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_core_load]){
for (int i = 0; i < numCpuCores; i++)
int i = 0;
for (const CPUData &cpuData : cpuStats.GetCPUData())
{
ImGui::TextColored(ImVec4(0.0, 0.502, 0.753, 1.00f), "CPU");
ImGui::SameLine(0, 1.0f);
@ -1098,13 +1099,14 @@ static void compute_swapchain_display(struct swapchain_data *data)
ImGui::TextColored(ImVec4(0.0, 0.502, 0.753, 1.00f),"%i", i);
ImGui::PopFont();
ImGui::SameLine(hudFirstRow);
ImGui::Text("%i%%", cpuArray[i + 1].value);
ImGui::Text("%i%%", int(cpuData.percent));
ImGui::SameLine(hudSecondRow);
ImGui::Text("%i", cpuArray[i + 1].freq);
ImGui::Text("%i", cpuData.mhz);
ImGui::SameLine(0, 1.0f);
ImGui::PushFont(font1);
ImGui::Text("MHz");
ImGui::PopFont();
i++;
}
}
if (instance_data->params.enabled[OVERLAY_PARAM_ENABLED_fps]){

Loading…
Cancel
Save