New cpu implementation

pull/20/head
FlightlessMango 4 years ago
parent 58384b0602
commit 1a60999243

@ -0,0 +1,208 @@
#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;
}
std::vector<int> coreMhz;
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;
} 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];
// 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;
cpuid = -1;
float total = (float)(cpuData.totalPeriod == 0 ? 1 : 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::min(std::max(v[0]+v[1]+v[2]+v[3], 0.0f), 100.0f);
} else {
break;
}
} while(true);
m_cpuPeriod = (double)m_cpuData[0].totalPeriod / m_cpuData.size();
m_updatedCPUs = true;
return ret;
}
bool CPUStats::UpdateCoreMhz() {
coreMhz.clear();
FILE *cpuInfo = fopen(PROCCPUINFOFILE, "r");
char line[256];
int i = 0;
while (fgets(line, sizeof(line), cpuInfo)) {
CPUData& cpuData = m_cpuData[i];
std::string row;
row = line;
if (row.find("MHz") != std::string::npos){
row = std::regex_replace(row, std::regex(R"([^0-9.])"), "");
cpuData.mhz = stoi(row);
i++;
}
}
fclose(cpuInfo);
return true;
}
CPUStats cpuStats;

@ -0,0 +1,59 @@
#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;
}
private:
unsigned long long int m_boottime = 0;
std::vector<CPUData> m_cpuData;
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,109 +51,6 @@ 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");
@ -173,7 +61,7 @@ void *cpuInfo(void *){
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);
// cpuArray[i + 1].freq = stoi(row);
i++;
}
}
@ -223,48 +111,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,10 +908,13 @@ 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();
pthread_create(&cpuInfoThread, NULL, &cpuInfo, NULL);
cpuStats.UpdateCPUData();
int i = 0;
cpuLoadLog = 0;
for (const CPUData &cpuData : cpuStats.GetCPUData())
cpuLoadLog += cpuData.percent;
cpuLoadLog = cpuLoadLog / cpuStats.GetCPUData().size();
// get gpu usage
if (deviceName.find("GeForce") != std::string::npos)
@ -920,7 +924,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 +1094,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 +1103,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