Skip to content

Commit

Permalink
Provide a mechanism for querying and printing system load.
Browse files Browse the repository at this point in the history
+ Add class `CPUinfo` that has member functions `report_load_average` and `report_cpu_utilization`.
  These functions only work on Linux.  They query `/proc/loadavg` and `/proc/stat` respectively to
  retrieve the current machine status.
  • Loading branch information
KineticTheory committed Dec 24, 2020
1 parent b0ef4c7 commit c48cb8a
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 0 deletions.
9 changes: 9 additions & 0 deletions src/c4/test/tstOMP.cc
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,15 @@ void MandelbrotDriver(rtt_dsxx::UnitTest &ut) {
int main(int argc, char *argv[]) {
rtt_c4::ParallelUnitTest ut(argc, argv, rtt_dsxx::release);
try {

#ifndef MSVC
if (rtt_c4::node() == 0) {
// Machine load:
CPUinfo().report_load_average();
CPUinfo().report_cpu_utilization();
}
#endif

// One MPI rank per machine node?
bool omrpn(false);

Expand Down
127 changes: 127 additions & 0 deletions src/ds++/SystemCall.hh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@
#define rtt_dsxx_SystemCall_hh

#include "ds++/config.h"
#include <array>
#include <chrono>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#ifdef WIN32
#define _WINSOCKAPI_
#include <WinSock2.h>
Expand Down Expand Up @@ -97,6 +103,127 @@ void draco_remove(std::string const &path);
#define draco_setenv(k, v) setenv(k, v, 1)
#endif

#ifndef MSVC
//================================================================================================//
/*!
* \class CPUinfo
* \brief Read information from /proc/stat and provide information about CPU states.
*
* \example c4/test/tstOMP.cc
* The main() reports the average load and cpu utilization (for Linux).
*/
//================================================================================================//
class CPUinfo {

private:
//! The cpudata has 10 values (ref: /proc/stat)
static constexpr size_t cpudata_num_values{10};
/*!
* \struct CPUData
*
* Data struct for cpu information that will be captured. The format for /proc/stat is something
* like this example:
* <code>
* cpu 764699971 57752895 158644540 75321983666 67359813 0 736586 0 0 0
* </code>
* A string followed by 10 size_t values.
*
* The 10 values represent cpu states:
* - user (0)
* - nice (1)
* - system (2)
* - idle (3)
* - iowait (4)
* - irg (5)
* - softirq (6)
* - steal (7)
* - guest (8)
* - guest_nice (9)
* .
*/
struct CPUData {
std::string cpu;
size_t num_cpus;
std::array<size_t, cpudata_num_values> times;
};

/* Maniulators */

//! Read /proc/stat to determine the system load.
CPUData ReadStatsCPU() {
CPUData cpu_all_entry;
const std::string label_cpu_all("cpu");
std::ifstream fileStat("/proc/stat");
std::string line("");
size_t num_cpu(0);
while (std::getline(fileStat, line)) { // Read a line
// cpu stats line found
if (!line.compare(0, label_cpu_all.length(), label_cpu_all)) {
std::istringstream ss(line);
// read cpu label
ss >> cpu_all_entry.cpu;
// read times
if (cpu_all_entry.cpu == "cpu") {
for (auto &t : cpu_all_entry.times)
ss >> t;
} else {
num_cpu++;
}
}
cpu_all_entry.num_cpus = num_cpu;
}
return cpu_all_entry;
}

/* Private accessors */

size_t machIdleTime(CPUData const &c) const { return c.times[3] + c.times[4]; }
size_t machActiveTime(CPUData const &c) const {
return c.times[0] + c.times[1] + c.times[2] + c.times[5] + c.times[6] + c.times[7] +
c.times[8] + c.times[9];
}

//! Read /proc/loadavg data.
std::array<float, 3> ReadLoadAvg() {
std::array<float, 3> retvalue;
std::ifstream fileStat("/proc/loadavg");
std::string line("");
while (std::getline(fileStat, line)) { // Read a line
std::istringstream ss(line);
for (auto &t : retvalue)
ss >> t;
}
return retvalue;
}

public:
//! Report cpu usage
void report_cpu_utilization() {
// initial state
CPUData entry1 = ReadStatsCPU();
std::this_thread::sleep_for(std::chrono::milliseconds(500));
// state after 0.1 sec.
CPUData entry2 = ReadStatsCPU();

float const activeTime = static_cast<float>(machActiveTime(entry2) - machActiveTime(entry1));
float const idleTime = static_cast<float>(machIdleTime(entry2) - machIdleTime(entry1));
float const totalTime = activeTime + idleTime;
std::cout.width(6);
std::cout.precision(2);
std::cout << "Average CPU Utilization : " << 100.0f * activeTime / totalTime << "%\n"
<< "Number of cores (hw threads) :" << entry1.num_cpus << std::endl;
}

//! Report load average
void report_load_average() {
// 1, 5, and 15 minute load averages reported by /proc/loadavg.
std::array<float, 3> loadAvg = ReadLoadAvg();
std::cout << "Load Average: " << loadAvg[0] << ", " << loadAvg[1] << ", " << loadAvg[2]
<< " (1 min, 5 min, 15 min)" << std::endl;
}
};
#endif

#endif // rtt_dsxx_SystemCall_hh

//------------------------------------------------------------------------------------------------//
Expand Down

0 comments on commit c48cb8a

Please sign in to comment.