RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/service/process_stats.cc
00001 /* proc_stats.h                                                   -*- C++ -*-
00002    Rémi Attab, 19 January 2012
00003    Copyright (c) 2012 Datacratic.  All rights reserved.
00004 
00005    Gathers process and system stats from the proc files.
00006 */
00007 
00008 
00009 #include "soa/service/process_stats.h"
00010 #include "jml/arch/exception.h"
00011 
00012 #include <boost/algorithm/string/split.hpp>
00013 #include <boost/lexical_cast.hpp>
00014 #include <string>
00015 #include <vector>
00016 #include <array>
00017 #include <functional>
00018 #include <fstream>
00019 #include <iostream>
00020 #include <unistd.h>
00021 #include <sys/resource.h>
00022 
00023 
00024 using namespace Datacratic;
00025 using namespace std;
00026 using namespace boost;
00027 
00028 
00029 namespace {
00030 
00031 static const string ProcStatFile = "/proc/self/stat";
00032 enum ProcStatFields {
00033     STAT_MINFLT = 9,
00034     STAT_MAJFLT = 11,
00035     STAT_UTIME = 13,
00036     STAT_STIME = 14,
00037     STAT_VSIZE = 22,
00038     STAT_RSS = 23
00039 };
00040 
00041 static const string ProcStatmFile = "/proc/self/statm";
00042 enum ProcStatmFields {
00043     STATM_SIZE = 0,
00044     STATM_RESIDENT = 1,
00045     STATM_SHARED = 2,
00046 };
00047 
00048 
00049 static const string ProcLoadAvgFile = "/proc/loadavg";
00050 enum ProcLoadAvgFields {
00051     LOADAVG_1 = 0, 
00052     LOADAVG_5 = 1,
00053     LOADAVG_15 = 2
00054 };
00055 
00056 
00057 vector<string> readProcFile(const string& procFile) {
00058     ifstream ifs(procFile);
00059     if (ifs.fail()) {
00060         throw ML::Exception ("Unable to open proc file " + procFile);
00061     }
00062 
00063     std::array<char, 1024> buffer;
00064     ifs.getline(&buffer[0], buffer.max_size());
00065     if (ifs.fail() || ifs.eof()) {
00066         throw ML::Exception ("Unable to read proc file " + procFile);
00067     }
00068 
00069     std::string rawStats = &buffer[0];
00070 
00071     vector<string> stats;
00072     split(stats, rawStats, [](char rhs)->bool {return rhs == ' ';});
00073 
00074     return stats;
00075 }
00076 
00077 };
00078 
00079 void ProcessStats::sampleLoadAverage () {
00080     if (!doLoadAverage) {
00081         return;
00082     }
00083 
00084     vector<string> stats = readProcFile(ProcLoadAvgFile);
00085 
00086     loadAverage1 = lexical_cast<float>(stats[LOADAVG_1]);
00087     loadAverage5 = lexical_cast<float>(stats[LOADAVG_5]);
00088     loadAverage15 = lexical_cast<float>(stats[LOADAVG_15]);
00089 }
00090 
00092 void ProcessStats::sampleStat () {
00093     vector<string> stats = readProcFile(ProcStatFile);
00094 
00095     long ticks = sysconf(_SC_CLK_TCK);
00096 
00097     minorFaults = lexical_cast<uint64_t>(stats[STAT_MINFLT]);
00098     majorFaults = lexical_cast<uint64_t>(stats[STAT_MAJFLT]);
00099 
00100     userTime = lexical_cast<uint64_t>(stats[STAT_UTIME]) / ((double) ticks);
00101     systemTime = lexical_cast<uint64_t>(stats[STAT_STIME]) / ((double) ticks);
00102 
00103     virtualMem = lexical_cast<uint64_t>(stats[STAT_VSIZE]);
00104     residentMem = lexical_cast<uint64_t>(stats[STAT_RSS]);
00105 }
00106 
00107 void ProcessStats::sampleStatm () {
00108     vector<string> stats = readProcFile(ProcStatmFile);
00109 
00110     int pageSize = getpagesize();
00111     virtualMem = lexical_cast<uint64_t>(stats[STATM_SIZE]) * pageSize;
00112     residentMem = lexical_cast<uint64_t>(stats[STATM_RESIDENT]) * pageSize; 
00113     sharedMem = lexical_cast<uint64_t>(stats[STATM_SHARED]) * pageSize;
00114 }
00115 
00116 void ProcessStats::sampleRUsage () {
00117     struct rusage ru;
00118     getrusage(RUSAGE_SELF, &ru);
00119 
00120     userTime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 1000000.0);
00121     systemTime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 1000000.0);
00122 
00123     minorFaults = ru.ru_minflt;
00124     majorFaults = ru.ru_majflt;
00125 
00126     voluntaryContextSwitches = ru.ru_nvcsw;
00127     involuntaryContextSwitches = ru.ru_nivcsw;
00128 }
00129 
00130 
00131 void ProcessStats::logToCallback (
00132         LogCallback cb, 
00133         const ProcessStats& last,
00134         const ProcessStats& cur,
00135         const string& prefix)
00136 {
00137     std::string p = !prefix.empty() ? prefix + "." : "";
00138 
00139     cb(p + "timeUser", cur.userTime - last.userTime);
00140     cb(p + "timeSystem", cur.systemTime - last.systemTime);
00141 
00142     cb(p + "faultsMinor", cur.minorFaults - last.minorFaults);
00143     cb(p + "faultsMajor", cur.majorFaults - last.majorFaults);
00144 
00145     cb(p + "memVirtual", cur.virtualMem);
00146     cb(p + "memResident", cur.residentMem);
00147     cb(p + "memShared", cur.sharedMem);
00148 
00149     cb(p + "contextSwitchesVoluntary",
00150             cur.voluntaryContextSwitches - last.voluntaryContextSwitches);
00151     cb(p + "contextSwitchesInvoluntary",
00152             cur.involuntaryContextSwitches - last.involuntaryContextSwitches);
00153     
00154     if (cur.doLoadAverage) {
00155         cb(p + "loadAverage01", cur.loadAverage1);
00156         cb(p + "loadAverage05", cur.loadAverage5);
00157         cb(p + "loadAverage15", cur.loadAverage15);
00158     }
00159 }
00160 
00161 
00162 Json::Value ProcessStats::toJson (
00163         const ProcessStats& last, 
00164         const ProcessStats& cur, 
00165         const string& prefix) 
00166 {
00167     Json::Value result;
00168 
00169     auto cb = [&](string name, double val) {
00170         result[name] = (long long)val;
00171     };
00172     logToCallback(cb, last, cur, prefix);
00173 
00174     return result;
00175 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator