diff --git a/README.md b/README.md index 5b403e3..965aae9 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ The `prmon` binary is invoked with the following arguments: ```sh prmon [--pid PPP] [--filename prmon.txt] [--json-summary prmon.json] \ - [--interval 30] [--suppress-hw-info] [--netdev DEV] \ + [--interval 30] [--suppress-hw-info] [--units] [--netdev DEV] \ [-- prog arg arg ...] ``` @@ -91,6 +91,7 @@ prmon [--pid PPP] [--filename prmon.txt] [--json-summary prmon.json] \ * `--json-summmary` output file for summary data written in JSON format * `--interval` time, in seconds, between monitoring snapshots * `--suppress-hw-info` flag that turns-off hardware information collection +* `--units` add information on units for each metric to JSON file * `--netdev` restricts network statistics to one (or more) network devices * `--` after this argument the following arguments are treated as a program to invoke and remaining arguments are passed to it; `prmon` will then monitor this process @@ -104,7 +105,9 @@ In the `filename` output file, plain text with statistics written every In the `json-summmary` file values for the maximum and average statistics are given in JSON format. This file is rewritten every `interval` seconds -with the current summary values. +with the current summary values. Use the `--units` option to see exactly +which units are used for each metric (the value of `1` for a unit means +it is a pure number). Monitoring of CPU, I/O and memory is reliably accurate, at least to within the sampling time. Monitoring of network I/O is **not reliable** unless the diff --git a/cmake/clang-format.cmake b/cmake/clang-format.cmake index 985886f..e609dd9 100644 --- a/cmake/clang-format.cmake +++ b/cmake/clang-format.cmake @@ -3,6 +3,10 @@ # Requires clang-format to be available in the # environment +# Setup the target version of clang-format we will use +set(CLANG_FORMAT "clang-format" CACHE STRING "Clang format binary") +message(STATUS "Setting clang-format test binary to '${CLANG_FORMAT}' (use -DCLANG_FORMAT to change)") + # Get all project files file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.h) diff --git a/doc/ADDING_MONITORS.md b/doc/ADDING_MONITORS.md index 4272191..6e8c0f8 100644 --- a/doc/ADDING_MONITORS.md +++ b/doc/ADDING_MONITORS.md @@ -8,10 +8,16 @@ All of the prmon monitors are concrete implementations of the virtual `Imonitor.h` interface. Inside the `package/src` directory you will find all of the current examples and these are an excellent guide. -## `util.h` +## `parameter.h` -Every monitor describes its column headers (*what* it will monitor), so add -short, descriptive names for the columns you will output. +Every monitor describes its column headers (*what* it will monitor) and the +units for this parameter as a vector of `parameter` classes. This is a very +simple class, initialised with three strings: +- name of parameter +- units for maximum/continuous value +- units for average value +If the later is an empty string it means that there is no meaningful value +for the average and so nothing is output. ## Data Structures @@ -27,6 +33,10 @@ maximum values and average values. These are updated each update cycle. Use an RAII pattern, so that on initialisation the monitor is valid and ready to be used. +For most monitors a vector of monitored quantities is constructed from the +parameter class, as the units are only needed once. Counters are mostly +set to zero as well. + ## Registry All monitors should use the `REGISTER_MONITOR` macro to register themselves. The diff --git a/package/src/Imonitor.h b/package/src/Imonitor.h index db9e542..52513d4 100644 --- a/package/src/Imonitor.h +++ b/package/src/Imonitor.h @@ -30,6 +30,7 @@ class Imonitor { unsigned long long elapsed_clock_ticks) = 0; virtual void const get_hardware_info(nlohmann::json& hw_json) = 0; + virtual void const get_unit_info(nlohmann::json& unit_json) = 0; virtual bool const is_valid() = 0; }; diff --git a/package/src/countmon.cpp b/package/src/countmon.cpp index 616ee06..7902eaf 100644 --- a/package/src/countmon.cpp +++ b/package/src/countmon.cpp @@ -15,16 +15,19 @@ // Constructor; uses RAII pattern to be valid // after construction countmon::countmon() - : count_params{prmon::default_count_params}, + : count_params{}, count_stats{}, + count_peak_stats{}, count_average_stats{}, count_total_stats{}, iterations{0L} { - for (const auto& count_param : count_params) { - count_stats[count_param] = 0; - count_peak_stats[count_param] = 0; - count_average_stats[count_param] = 0; - count_total_stats[count_param] = 0; + count_params.reserve(params.size()); + for (const auto& param : params) { + count_params.push_back(param.get_name()); + count_stats[param.get_name()] = 0; + count_peak_stats[param.get_name()] = 0; + count_average_stats[param.get_name()] = 0; + count_total_stats[param.get_name()] = 0; } } @@ -80,3 +83,8 @@ std::map const countmon::get_json_average_stats( // Collect related hardware information void const countmon::get_hardware_info(nlohmann::json& hw_json) { return; } + +void const countmon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/countmon.h b/package/src/countmon.h index fd4f8d4..6176217 100644 --- a/package/src/countmon.h +++ b/package/src/countmon.h @@ -13,10 +13,15 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class countmon final : public Imonitor { private: + // Setup the parameters to monitor here + const prmon::parameter_list params = {{"nprocs", "1", "1"}, + {"nthreads", "1", "1"}}; + // Which network count paramters to measure and output key names std::vector count_params; @@ -42,6 +47,7 @@ class countmon final : public Imonitor { // This is the hardware information getter that runs once void const get_hardware_info(nlohmann::json& hw_json); + void const get_unit_info(nlohmann::json& unit_json); bool const is_valid() { return true; } }; REGISTER_MONITOR(Imonitor, countmon, "Monitor number of processes and threads") diff --git a/package/src/cpumon.cpp b/package/src/cpumon.cpp index 454c01e..f3e0c6e 100644 --- a/package/src/cpumon.cpp +++ b/package/src/cpumon.cpp @@ -15,8 +15,12 @@ // Constructor; uses RAII pattern to be valid // after construction -cpumon::cpumon() : cpu_params{prmon::default_cpu_params}, cpu_stats{} { - for (const auto& cpu_param : cpu_params) cpu_stats[cpu_param] = 0; +cpumon::cpumon() : cpu_params{}, cpu_stats{} { + cpu_params.reserve(params.size()); + for (const auto& param : params) { + cpu_params.push_back(param.get_name()); + cpu_stats[param.get_name()] = 0; + } } void cpumon::update_stats(const std::vector& pids) { @@ -120,3 +124,8 @@ void const cpumon::get_hardware_info(nlohmann::json& hw_json) { return; } + +void const cpumon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/cpumon.h b/package/src/cpumon.h index 9032e48..08a6272 100644 --- a/package/src/cpumon.h +++ b/package/src/cpumon.h @@ -13,11 +13,17 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class cpumon final : public Imonitor { private: + // Setup the parameters to monitor here + const prmon::parameter_list params = {{"utime", "s", ""}, {"stime", "s", ""}}; + // Which network cpu paramters to measure and output key names + // This will be filled at initialisation, taking the names + // from the above params std::vector cpu_params; // Container for total stats @@ -36,6 +42,8 @@ class cpumon final : public Imonitor { // This is the hardware information getter that runs once void const get_hardware_info(nlohmann::json& hw_json); + + void const get_unit_info(nlohmann::json& unit_json); bool const is_valid() { return true; } }; REGISTER_MONITOR(Imonitor, cpumon, "Monitor cpu time used") diff --git a/package/src/iomon.cpp b/package/src/iomon.cpp index 3c03e5c..4e03568 100644 --- a/package/src/iomon.cpp +++ b/package/src/iomon.cpp @@ -11,8 +11,12 @@ // Constructor; uses RAII pattern to be valid // after construction -iomon::iomon() : io_stats{} { - for (const auto& io_param : prmon::default_io_params) io_stats[io_param] = 0; +iomon::iomon() : io_params{}, io_stats{} { + io_params.reserve(params.size()); + for (const auto& param : params) { + io_params.push_back(param.get_name()); + io_stats[param.get_name()] = 0; + } } void iomon::update_stats(const std::vector& pids) { @@ -57,3 +61,8 @@ std::map const iomon::get_json_average_stats( // Collect related hardware information void const iomon::get_hardware_info(nlohmann::json& hw_json) { return; } + +void const iomon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/iomon.h b/package/src/iomon.h index edfd328..5fd4ebf 100644 --- a/package/src/iomon.h +++ b/package/src/iomon.h @@ -12,10 +12,17 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class iomon final : public Imonitor { private: + // Setup the parameters to monitor here + const prmon::parameter_list params = {{"rchar", "B", "B/s"}, + {"wchar", "B", "B/s"}, + {"read_bytes", "B", "B/s"}, + {"write_bytes", "B", "B/s"}}; + // Which network io paramters to measure and output key names std::vector io_params; @@ -35,6 +42,7 @@ class iomon final : public Imonitor { // This is the hardware information getter that runs once void const get_hardware_info(nlohmann::json& hw_json); + void const get_unit_info(nlohmann::json& unit_json); bool const is_valid() { return true; } }; REGISTER_MONITOR(Imonitor, iomon, "Monitor input and output activity") diff --git a/package/src/memmon.cpp b/package/src/memmon.cpp index 514da36..4c59823 100644 --- a/package/src/memmon.cpp +++ b/package/src/memmon.cpp @@ -16,12 +16,20 @@ // Constructor; uses RAII pattern to be valid // after construction -memmon::memmon() : mem_params{prmon::default_memory_params}, iterations{0} { - for (const auto& mem_param : mem_params) { - mem_stats[mem_param] = 0; - mem_peak_stats[mem_param] = 0; - mem_average_stats[mem_param] = 0; - mem_total_stats[mem_param] = 0; +memmon::memmon() + : mem_params{}, + mem_stats{}, + mem_peak_stats{}, + mem_average_stats{}, + mem_total_stats{}, + iterations{0} { + mem_params.reserve(params.size()); + for (const auto& param : params) { + mem_params.push_back(param.get_name()); + mem_stats[param.get_name()] = 0; + mem_peak_stats[param.get_name()] = 0; + mem_average_stats[param.get_name()] = 0; + mem_total_stats[param.get_name()] = 0; } } @@ -117,3 +125,8 @@ void const memmon::get_hardware_info(nlohmann::json& hw_json) { return; } + +void const memmon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/memmon.h b/package/src/memmon.h index 826df05..c637156 100644 --- a/package/src/memmon.h +++ b/package/src/memmon.h @@ -12,10 +12,19 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class memmon final : public Imonitor { private: + // Default paramater list + // const static std::vector default_memory_params{"vmem", "pss", + // "rss", "swap"}; + const prmon::parameter_list params = {{"vmem", "kB", "kB"}, + {"pss", "kB", "kB"}, + {"rss", "kB", "kB"}, + {"swap", "kB", "kB"}}; + // Which network memory parameters to measure and output key names std::vector mem_params; @@ -41,6 +50,7 @@ class memmon final : public Imonitor { // This is the hardware information getter that runs once void const get_hardware_info(nlohmann::json& hw_json); + void const get_unit_info(nlohmann::json& unit_json); bool const is_valid() { return true; } }; REGISTER_MONITOR(Imonitor, memmon, "Monitor memory usage") diff --git a/package/src/netmon.cpp b/package/src/netmon.cpp index 1128ed4..50b8afc 100644 --- a/package/src/netmon.cpp +++ b/package/src/netmon.cpp @@ -15,7 +15,10 @@ // network device streams and to take initial values // to the monitor relative differences netmon::netmon(std::vector netdevs) - : interface_params{prmon::default_network_if_params}, network_if_streams{} { + : interface_params{}, network_if_streams{} { + interface_params.reserve(params.size()); + for (const auto& param : params) interface_params.push_back(param.get_name()); + if (netdevs.size() == 0) { monitored_netdevs = get_all_network_devs(); } else { @@ -111,3 +114,8 @@ std::map const netmon::get_json_average_stats( // Collect related hardware information void const netmon::get_hardware_info(nlohmann::json& hw_json) { return; } + +void const netmon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/netmon.h b/package/src/netmon.h index 7955abb..fd42c38 100644 --- a/package/src/netmon.h +++ b/package/src/netmon.h @@ -19,12 +19,18 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class netmon final : public Imonitor { private: - // Which network interface paramters to measure (in this simple case - // these are also the output key names) + // Setup the parameters to monitor here + const prmon::parameter_list params = {{"rx_bytes", "B", "B/s"}, + {"rx_packets", "1", "1/s"}, + {"tx_bytes", "B", "B/s"}, + {"tx_packets", "1", "1/s"}}; + + // Vector for network interface paramters to measure (will be constructed) std::vector interface_params; // Which network interfaces to monitor @@ -71,6 +77,7 @@ class netmon final : public Imonitor { // This is the hardware information getter that runs once void const get_hardware_info(nlohmann::json& hw_json); + void const get_unit_info(nlohmann::json& unit_json); bool const is_valid() { return true; } }; REGISTER_MONITOR(Imonitor, netmon, "Monitor network activity (device level)") diff --git a/package/src/nvidiamon.cpp b/package/src/nvidiamon.cpp index 62f8d85..6dc4251 100644 --- a/package/src/nvidiamon.cpp +++ b/package/src/nvidiamon.cpp @@ -18,16 +18,18 @@ // Constructor; uses RAII pattern to be valid after construction nvidiamon::nvidiamon() - : nvidia_params{prmon::default_nvidia_params}, - nvidia_stats{}, + : nvidia_stats{}, + nvidia_peak_stats{}, nvidia_average_stats{}, nvidia_total_stats{}, iterations{0L} { - for (const auto& nvidia_param : nvidia_params) { - nvidia_stats[nvidia_param] = 0; - nvidia_peak_stats[nvidia_param] = 0; - nvidia_average_stats[nvidia_param] = 0; - nvidia_total_stats[nvidia_param] = 0; + nvidia_params.reserve(params.size()); + for (const auto& param : params) { + nvidia_params.push_back(param.get_name()); + nvidia_stats[param.get_name()] = 0; + nvidia_peak_stats[param.get_name()] = 0; + nvidia_average_stats[param.get_name()] = 0; + nvidia_total_stats[param.get_name()] = 0; } // Attempt to execute nvidia-smi @@ -206,3 +208,8 @@ void const nvidiamon::get_hardware_info(nlohmann::json& hw_json) { } return; } + +void const nvidiamon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/nvidiamon.h b/package/src/nvidiamon.h index 32ac40f..302599d 100644 --- a/package/src/nvidiamon.h +++ b/package/src/nvidiamon.h @@ -11,10 +11,18 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class nvidiamon final : public Imonitor { private: + // const static std::vector default_nvidia_params{ + // "ngpus", "gpusmpct", "gpumempct", "gpufbmem"}; + const prmon::parameter_list params = {{"ngpus", "1", "1"}, + {"gpusmpct", "%", "%"}, + {"gpumempct", "%", "%"}, + {"gpufbmem", "kB", "kB"}}; + // Which paramters to measure and output key names std::vector nvidia_params; @@ -52,7 +60,7 @@ class nvidiamon final : public Imonitor { unsigned long long elapsed_clock_ticks); void const get_hardware_info(nlohmann::json& hw_json); - + void const get_unit_info(nlohmann::json& unit_json); bool const is_valid() { return valid; } }; REGISTER_MONITOR(Imonitor, nvidiamon, "Monitor NVIDIA GPU activity") diff --git a/package/src/parameter.h b/package/src/parameter.h new file mode 100644 index 0000000..b3b9d50 --- /dev/null +++ b/package/src/parameter.h @@ -0,0 +1,36 @@ +// Copyright (C) 2018-2020 CERN +// License Apache2 - see LICENCE file + +// Monitored quantity class + +#include +#include + +#ifndef PRMON_PARAMETER_H +#define PRMON_PARAMETER_H 1 + +namespace prmon { +// parameter class holds three strings for each monitored value: +// - the name of the value +// - the units of the value for maxiumums and averages +// as quite a few units don't have meaningful average values then +// these should be set to and empty string, which will suppress +// adding that informtion to the JSON output file +class parameter { + private: + std::string name; + std::string max_unit, avg_unit; + + public: + inline const std::string get_name() const { return name; } + inline const std::string get_max_unit() const { return max_unit; } + inline const std::string get_avg_unit() const { return avg_unit; } + + parameter(std::string n, std::string m, std::string a) + : name{n}, max_unit{m}, avg_unit{a} {} +}; + +using parameter_list = std::vector; +} // namespace prmon + +#endif // PRMON_PARAMETER_H diff --git a/package/src/prmon.cpp b/package/src/prmon.cpp index b6fcb9d..f4a7fbc 100644 --- a/package/src/prmon.cpp +++ b/package/src/prmon.cpp @@ -30,7 +30,7 @@ bool prmon::sigusr1 = false; int ProcessMonitor(const pid_t mpid, const std::string filename, const std::string json_summary_file, const time_t interval, - const bool store_hw_info, + const bool store_hw_info, const bool store_unit_info, const std::vector netdevs) { signal(SIGUSR1, prmon::SignalCallbackHandler); @@ -85,6 +85,10 @@ int ProcessMonitor(const pid_t mpid, const std::string filename, for (const auto& monitor : monitors) monitor.second->get_hardware_info(json_summary); } + if (store_unit_info) { + for (const auto& monitor : monitors) + monitor.second->get_unit_info(json_summary); + } // See if the kernel is new enough to have /proc/PID/task/PID/children bool modern_kernel = prmon::kernel_proc_pid_test(mpid); @@ -177,6 +181,7 @@ int main(int argc, char* argv[]) { const char* default_json_summary = "prmon.json"; const unsigned int default_interval = 30; const bool default_store_hw_info = true; + const bool default_store_unit_info = false; pid_t pid = -1; bool got_pid = false; @@ -185,6 +190,7 @@ int main(int argc, char* argv[]) { std::vector netdevs{}; unsigned int interval{default_interval}; bool store_hw_info{default_store_hw_info}; + bool store_unit_info{default_store_unit_info}; int do_help{0}; static struct option long_options[] = { @@ -193,12 +199,13 @@ int main(int argc, char* argv[]) { {"json-summary", required_argument, NULL, 'j'}, {"interval", required_argument, NULL, 'i'}, {"suppress-hw-info", no_argument, NULL, 's'}, + {"units", no_argument, NULL, 'u'}, {"netdev", required_argument, NULL, 'n'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0}}; int c; - while ((c = getopt_long(argc, argv, "p:f:j:i:sn:h", long_options, NULL)) != + while ((c = getopt_long(argc, argv, "p:f:j:i:sun:h", long_options, NULL)) != -1) { switch (char(c)) { case 'p': @@ -217,6 +224,9 @@ int main(int argc, char* argv[]) { case 's': store_hw_info = false; break; + case 'u': + store_unit_info = true; + break; case 'n': netdevs.push_back(optarg); break; @@ -247,6 +257,9 @@ int main(int argc, char* argv[]) { << default_interval << ")\n" << "[--suppress-hw-info, -s] Disable hardware information (default " << (default_store_hw_info ? "false" : "true") << ")\n" + << "[--units, -u] Add units information to JSON file " + "(default " + << (default_store_unit_info ? "true" : "false") << ")\n" << "[--netdev, -n dev] Network device to monitor (can be given\n" << " multiple times; default ALL devices)\n" << "[--] prog [arg] ... Instead of monitoring a PID prmon will\n" @@ -291,7 +304,7 @@ int main(int argc, char* argv[]) { return 1; } ProcessMonitor(pid, filename, jsonSummary, interval, store_hw_info, - netdevs); + store_unit_info, netdevs); } else { if (child_args == argc) { std::cerr << "Found marker for child program to execute, but with no " @@ -303,7 +316,7 @@ int main(int argc, char* argv[]) { execvp(argv[child_args], &argv[child_args]); } else if (child > 0) { ProcessMonitor(child, filename, jsonSummary, interval, store_hw_info, - netdevs); + store_unit_info, netdevs); } } diff --git a/package/src/utils.cpp b/package/src/utils.cpp index 5ab8435..e63d1cb 100644 --- a/package/src/utils.cpp +++ b/package/src/utils.cpp @@ -12,8 +12,7 @@ #include #include -namespace prmon { -const std::pair> cmd_pipe_output( +const std::pair> prmon::cmd_pipe_output( const std::vector cmdargs) { std::vector split_output{}; std::string output; @@ -95,4 +94,13 @@ const std::pair> cmd_pipe_output( return ret; } -} // namespace prmon +const void prmon::fill_units(nlohmann::json& unit_json, + const parameter_list& params) { + for (const auto& param : params) { + if (!param.get_max_unit().empty()) + unit_json["Units"]["Max"][param.get_name()] = param.get_max_unit(); + if (!param.get_avg_unit().empty()) + unit_json["Units"]["Avg"][param.get_name()] = param.get_avg_unit(); + } + return; +} diff --git a/package/src/utils.h b/package/src/utils.h index d66bdb9..d265e0a 100644 --- a/package/src/utils.h +++ b/package/src/utils.h @@ -10,10 +10,14 @@ #include #include +#include #include +#include #include #include +#include "parameter.h" + namespace prmon { // These constants define where in the stat entry from proc // we find the parameters of interest @@ -26,20 +30,6 @@ const size_t num_threads = 19; const size_t stat_count_read_limit = 19; const size_t uptime_pos = 21; -// Default parameter lists for monitor classes -const static std::vector default_cpu_params{"utime", "stime"}; -const static std::vector default_network_if_params{ - "rx_bytes", "rx_packets", "tx_bytes", "tx_packets"}; -const static std::vector default_wall_params{"wtime"}; -const static std::vector default_memory_params{"vmem", "pss", - "rss", "swap"}; -const static std::vector default_io_params{ - "rchar", "wchar", "read_bytes", "write_bytes"}; -const static std::vector default_count_params{"nprocs", - "nthreads"}; -const static std::vector default_nvidia_params{ - "ngpus", "gpusmpct", "gpumempct", "gpufbmem"}; - // This is a utility function that executes a command and // pipes the output back, returning a vector of strings // for further processing. To make life easier for the caller @@ -57,6 +47,12 @@ const static std::vector default_nvidia_params{ const std::pair> cmd_pipe_output( const std::vector cmdargs); +// Utility function to add the units' values to the JSON output +// (the implementation is basically identical for all monitors, +// but as the base class is virtual we use this in each concrete +// monitor) +const void fill_units(nlohmann::json& unit_json, const parameter_list& params); + } // namespace prmon #endif // PRMON_UTILS_H diff --git a/package/src/wallmon.cpp b/package/src/wallmon.cpp index ae89dd8..56e06f4 100644 --- a/package/src/wallmon.cpp +++ b/package/src/wallmon.cpp @@ -15,8 +15,12 @@ // Constructor; uses RAII pattern to be valid // after construction wallmon::wallmon() - : start_time_clock_t{0}, current_clock_t{0}, got_mother_starttime{false} { - walltime_stats["wtime"] = 0; + : walltime_param{}, + start_time_clock_t{0}, + current_clock_t{0}, + got_mother_starttime{false} { + walltime_param.reserve(params.size()); + for (const auto& param : params) walltime_param.push_back(param.get_name()); } int wallmon::get_mother_starttime(pid_t mother_pid) { @@ -91,3 +95,8 @@ std::map const wallmon::get_json_average_stats( // Collect related hardware information void const wallmon::get_hardware_info(nlohmann::json& hw_json) { return; } + +void const wallmon::get_unit_info(nlohmann::json& unit_json) { + prmon::fill_units(unit_json, params); + return; +} diff --git a/package/src/wallmon.h b/package/src/wallmon.h index 982e7a7..9112b94 100644 --- a/package/src/wallmon.h +++ b/package/src/wallmon.h @@ -16,10 +16,15 @@ #include #include "Imonitor.h" +#include "parameter.h" #include "registry.h" class wallmon final : public Imonitor { private: + const prmon::parameter_list params = {{"wtime", "s", ""}}; + + std::vector walltime_param; + // Container for total stat std::map walltime_stats; @@ -43,6 +48,7 @@ class wallmon final : public Imonitor { // This is the hardware information getter that runs once void const get_hardware_info(nlohmann::json& hw_json); + void const get_unit_info(nlohmann::json& unit_json); // Class specific method to retrieve wallclock time in clock ticks unsigned long long const get_wallclock_clock_t(); diff --git a/package/tests/CMakeLists.txt b/package/tests/CMakeLists.txt index 08020c8..db3827c 100644 --- a/package/tests/CMakeLists.txt +++ b/package/tests/CMakeLists.txt @@ -39,6 +39,10 @@ script_install(SCRIPT netBurner.py) script_install(SCRIPT httpBlock.py DESTINATION cgi-bin) script_install(SCRIPT testCOUNT.py) +# Setup the target version of Python we will use for testing +set(PYTHON_TEST "python3" CACHE STRING "Python binary to use for tests") +message(STATUS "Setting Python test binary to '${PYTHON_TEST}' (use -DPYTHON_TEST to change)") + # Python2 has a different version of the network test # as the modules are significantly different from Python3 if(${PYTHON_TEST} MATCHES "python2") @@ -47,10 +51,6 @@ if(${PYTHON_TEST} MATCHES "python2") script_install(SCRIPT httpBlock2.py DESTINATION cgi-bin) endif() -# Setup the target version of Python we will use for testing -set(PYTHON_TEST "python3" CACHE STRING "Python binary to use for tests") -message(STATUS "Setting Python test binary to '${PYTHON_TEST}' (use -DPYTHON_TEST to change)") - # CPU Tests add_test(NAME testCPUsingle COMMAND ${PYTHON_TEST} testCPU.py --threads 1 --procs 1) add_test(NAME testCPUmultithread COMMAND ${PYTHON_TEST} testCPU.py --threads 2 --procs 1) @@ -76,3 +76,6 @@ add_test(NAME childMem COMMAND ${PYTHON_TEST} testMEM.py --procs 4) # Process and thread counting Tests add_test(NAME basicCOUNT COMMAND ${PYTHON_TEST} testCOUNT.py --procs 2 --threads 2) + +# Units check test +add_test(NAME testUnits COMMAND ${PYTHON_TEST} testCPU.py --units --time 3 --slack 0 --interval 1) diff --git a/package/tests/testCPU.py b/package/tests/testCPU.py index 2ec39a4..a3b9251 100755 --- a/package/tests/testCPU.py +++ b/package/tests/testCPU.py @@ -10,7 +10,8 @@ import sys import unittest -def setupConfigurableTest(threads=1, procs=1, child_fraction=1.0, time=10.0, slack=0.75, interval=1, invoke=False): +def setupConfigurableTest(threads=1, procs=1, child_fraction=1.0, time=10.0, + slack=0.75, interval=1, invoke=False, units=False): '''Wrap the class definition in a function to allow arguments to be passed''' class configurableProcessMonitor(unittest.TestCase): def test_runTestWithParams(self): @@ -23,6 +24,8 @@ def test_runTestWithParams(self): burn_cmd.extend(['--child-fraction', str(child_fraction)]) prmon_cmd = ['../prmon', '--interval', str(interval)] + if units: + prmon_cmd.append('--units') if invoke: prmon_cmd.append('--') prmon_cmd.extend(burn_cmd) @@ -56,6 +59,18 @@ def test_runTestWithParams(self): "(expected maximum of {0}, got {1})".format(time, totWALL)) self.assertGreaterEqual(totWALL, time*slack, "Too low value for wall time " "(expected minimum of {0}, got {1}".format(time*slack, totWALL)) + + # Unit test + if units: + for group in ("Max", "Avg"): + value_params = set(prmonJSON[group].keys()) + unit_params = set(prmonJSON["Units"][group].keys()) + missing = value_params - unit_params + self.assertEqual(len(missing), 0, + "Wrong number of unit values for '{0}' - missing parameters are {1}".format(group, missing)) + extras = unit_params - value_params + self.assertEqual(len(extras), 0, + "Wrong number of unit values for '{0}' - extra parameters are {1}".format(group, extras)) return configurableProcessMonitor @@ -68,12 +83,14 @@ def test_runTestWithParams(self): parser.add_argument('--time', type=float, default=10) parser.add_argument('--slack', type=float, default=0.7) parser.add_argument('--interval', type=int, default=1) - parser.add_argument('--invoke', dest='invoke', action='store_true', default=False) + parser.add_argument('--invoke', action='store_true') + parser.add_argument('--units', action='store_true') args = parser.parse_args() # Stop unittest from being confused by the arguments sys.argv=sys.argv[:1] - cpm = setupConfigurableTest(args.threads,args.procs,args.child_fraction,args.time,args.slack,args.interval,args.invoke) + cpm = setupConfigurableTest(args.threads,args.procs,args.child_fraction,args.time, + args.slack,args.interval,args.invoke,args.units) unittest.main()