233 lines
7.6 KiB
C++
Executable file
233 lines
7.6 KiB
C++
Executable file
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <fstream>
|
|
#include <set>
|
|
#include <iostream>
|
|
#include <mist/json.h>
|
|
#include <mist/timing.h>
|
|
|
|
///\brief A class storing information about the cpu the server is running on.
|
|
class cpudata{
|
|
public:
|
|
std::string model;///<A string describing the model of the cpu.
|
|
int cores;///<The amount of cores in the cpu.
|
|
int threads;///<The amount of threads this cpu can run.
|
|
int mhz;///<The speed of the cpu in mhz.
|
|
int id;///<The id of the cpu in the system.
|
|
|
|
///\brief The default constructor
|
|
cpudata(){
|
|
model = "Unknown";
|
|
cores = 1;
|
|
threads = 1;
|
|
mhz = 0;
|
|
id = 0;
|
|
}
|
|
;
|
|
|
|
///\brief Fills the structure by parsing a given description.
|
|
///\param data A description of the cpu.
|
|
void fill(char * data){
|
|
int i;
|
|
i = 0;
|
|
if (sscanf(data, "model name : %n", &i) != EOF && i > 0){
|
|
model = (data + i);
|
|
}
|
|
if (sscanf(data, "cpu cores : %d", &i) == 1){
|
|
cores = i;
|
|
}
|
|
if (sscanf(data, "siblings : %d", &i) == 1){
|
|
threads = i;
|
|
}
|
|
if (sscanf(data, "physical id : %d", &i) == 1){
|
|
id = i;
|
|
}
|
|
if (sscanf(data, "cpu MHz : %d", &i) == 1){
|
|
mhz = i;
|
|
}
|
|
}
|
|
;
|
|
};
|
|
|
|
///\brief Checks the capabilities of the system.
|
|
///\param capa The location to store the capabilities.
|
|
void checkCapable(JSON::Value & capa){
|
|
//capa.null();
|
|
capa.removeMember("cpu");
|
|
std::ifstream cpuinfo("/proc/cpuinfo");
|
|
if (cpuinfo){
|
|
std::map<int, cpudata> cpus;
|
|
char line[300];
|
|
int proccount = -1;
|
|
while (cpuinfo.good()){
|
|
cpuinfo.getline(line, 300);
|
|
if (cpuinfo.fail()){
|
|
//empty lines? ignore them, clear flags, continue
|
|
if ( !cpuinfo.eof()){
|
|
cpuinfo.ignore();
|
|
cpuinfo.clear();
|
|
}
|
|
continue;
|
|
}
|
|
if (memcmp(line, "processor", 9) == 0){
|
|
proccount++;
|
|
}
|
|
cpus[proccount].fill(line);
|
|
}
|
|
//fix wrong core counts
|
|
std::map<int, int> corecounts;
|
|
for (int i = 0; i <= proccount; ++i){
|
|
corecounts[cpus[i].id]++;
|
|
}
|
|
//remove double physical IDs - we only want real CPUs.
|
|
std::set<int> used_physids;
|
|
int total_speed = 0;
|
|
int total_threads = 0;
|
|
for (int i = 0; i <= proccount; ++i){
|
|
if ( !used_physids.count(cpus[i].id)){
|
|
used_physids.insert(cpus[i].id);
|
|
JSON::Value thiscpu;
|
|
thiscpu["model"] = cpus[i].model;
|
|
thiscpu["cores"] = cpus[i].cores;
|
|
if (cpus[i].cores < 2 && corecounts[cpus[i].id] > cpus[i].cores){
|
|
thiscpu["cores"] = corecounts[cpus[i].id];
|
|
}
|
|
thiscpu["threads"] = cpus[i].threads;
|
|
if (thiscpu["cores"].asInt() > thiscpu["threads"].asInt()){
|
|
thiscpu["threads"] = thiscpu["cores"];
|
|
}
|
|
thiscpu["mhz"] = cpus[i].mhz;
|
|
capa["cpu"].append(thiscpu);
|
|
total_speed += cpus[i].cores * cpus[i].mhz;
|
|
total_threads += cpus[i].threads;
|
|
}
|
|
}
|
|
capa["speed"] = total_speed;
|
|
capa["threads"] = total_threads;
|
|
}
|
|
std::ifstream cpuUsage("/proc/stat");
|
|
if (cpuUsage){
|
|
char line[300];
|
|
cpuUsage.getline(line, 300);
|
|
long long int i, o, p, q;
|
|
if (sscanf(line, "cpu %lli %lli %lli %lli ", &i, &o, &p, &q) == 4){
|
|
capa["usage"]["user"] = i;
|
|
capa["usage"]["nice"] = o;
|
|
capa["usage"]["system"] = p;
|
|
capa["usage"]["idle"] = q;
|
|
}else{
|
|
std::cerr << "HALP!" << std::endl;
|
|
}
|
|
}
|
|
std::ifstream meminfo("/proc/meminfo");
|
|
if (meminfo){
|
|
char line[300];
|
|
int bufcache = 0;
|
|
while (meminfo.good()){
|
|
meminfo.getline(line, 300);
|
|
if (meminfo.fail()){
|
|
//empty lines? ignore them, clear flags, continue
|
|
if ( !meminfo.eof()){
|
|
meminfo.ignore();
|
|
meminfo.clear();
|
|
}
|
|
continue;
|
|
}
|
|
long long int i;
|
|
if (sscanf(line, "MemTotal : %lli kB", &i) == 1){
|
|
capa["mem"]["total"] = i;
|
|
}
|
|
if (sscanf(line, "MemFree : %lli kB", &i) == 1){
|
|
capa["mem"]["free"] = i;
|
|
}
|
|
if (sscanf(line, "SwapTotal : %lli kB", &i) == 1){
|
|
capa["mem"]["swaptotal"] = i;
|
|
}
|
|
if (sscanf(line, "SwapFree : %lli kB", &i) == 1){
|
|
capa["mem"]["swapfree"] = i;
|
|
}
|
|
if (sscanf(line, "Buffers : %lli kB", &i) == 1){
|
|
bufcache += i;
|
|
}
|
|
if (sscanf(line, "Cached : %lli kB", &i) == 1){
|
|
bufcache += i;
|
|
}
|
|
}
|
|
capa["mem"]["used"] = capa["mem"]["total"].asInt() - capa["mem"]["free"].asInt() - bufcache;
|
|
capa["mem"]["cached"] = bufcache;
|
|
capa["load"]["memory"] = ((capa["mem"]["used"].asInt() + (capa["mem"]["swaptotal"].asInt() - capa["mem"]["swapfree"].asInt())) * 100) / capa["mem"]["total"].asInt();
|
|
}
|
|
std::ifstream loadavg("/proc/loadavg");
|
|
if (loadavg){
|
|
char line[300];
|
|
loadavg.getline(line, 300);
|
|
//parse lines here
|
|
float onemin;
|
|
if (sscanf(line, "%f %*f %*f", &onemin) == 1){
|
|
capa["load"]["one"] = (long long int)(onemin*1000);
|
|
}
|
|
}
|
|
std::ifstream netUsage("/proc/net/dev");
|
|
capa["net"]["sent"] = 0;
|
|
capa["net"]["recv"] = 0;
|
|
while (netUsage){
|
|
char line[300];
|
|
netUsage.getline(line, 300);
|
|
long long unsigned sent = 0;
|
|
long long unsigned recv = 0;
|
|
//std::cout << line;
|
|
if (sscanf(line, "%*s %llu %*u %*u %*u %*u %*u %*u %*u %llu", &recv, &sent) == 2){
|
|
//std::cout << "Net: " << recv << ", " << sent << std::endl;
|
|
capa["net"]["recv"] = (long long int)(capa["net"]["recv"].asInt() + recv);
|
|
capa["net"]["sent"] = (long long int)(capa["net"]["sent"].asInt() + sent);
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv){
|
|
JSON::Value stats;
|
|
checkCapable(stats);
|
|
std::ofstream file(argv[1]);
|
|
file << "Time in seconds,1m load average,Memory use in bytes,CPU percentage,Uploaded bytes,Downloaded bytes" << std::endl;
|
|
long long int totalCpu = 0;
|
|
long long int grandTotal = 0;
|
|
long long int usrCpu = 0;
|
|
long long int niceCpu = 0;
|
|
long long int systemCpu = 0;
|
|
long long int prevUsrCpu = stats["usage"]["user"].asInt();
|
|
long long int prevNiceCpu = stats["usage"]["nice"].asInt();
|
|
long long int prevSystemCpu = stats["usage"]["system"].asInt();
|
|
long long int prevIdleCpu = stats["usage"]["idle"].asInt();
|
|
long long int startUpload = stats["net"]["sent"].asInt();
|
|
long long int startDownload = stats["net"]["recv"].asInt();
|
|
long long int startTime = Util::epoch();
|
|
long long int lastTime = 0;
|
|
while (true){
|
|
Util::sleep(500);//faster than once per second, just in case we go out of sync somewhere
|
|
if (lastTime == Util::epoch()){
|
|
continue;//if a second hasn't passed yet, skip this run
|
|
}
|
|
lastTime = Util::epoch();
|
|
checkCapable(stats);
|
|
file << (lastTime - startTime) << ",";//time since start
|
|
file << (double)stats["load"]["one"].asInt()/1000.0 << ","; //LoadAvg
|
|
file << stats["mem"]["used"].asString() << ","; //MemUse
|
|
|
|
usrCpu = stats["usage"]["user"].asInt() - prevUsrCpu;
|
|
niceCpu = stats["usage"]["nice"].asInt() - prevNiceCpu;
|
|
systemCpu = stats["usage"]["system"].asInt() - prevSystemCpu;
|
|
totalCpu = usrCpu + niceCpu + systemCpu;
|
|
grandTotal = totalCpu + stats["usage"]["idle"].asInt() - prevIdleCpu;
|
|
if (grandTotal != 0){
|
|
file << 100 * (double)totalCpu / grandTotal << ",";//totalCpu
|
|
}else{
|
|
file << "," << std::endl;//unknown CPU usage
|
|
}
|
|
file << (stats["net"]["sent"].asInt() - startUpload) << "," << (stats["net"]["recv"].asInt() - startDownload) << std::endl;
|
|
prevUsrCpu = stats["usage"]["user"].asInt();
|
|
prevNiceCpu = stats["usage"]["nice"].asInt();
|
|
prevSystemCpu = stats["usage"]["system"].asInt();
|
|
prevIdleCpu = stats["usage"]["idle"].asInt();
|
|
}
|
|
return 0;
|
|
}
|