mistserver/scripts/capa_service.cpp

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