summaryrefslogtreecommitdiff
path: root/python/openvino/runtime/common/monitors/src/cpu_monitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'python/openvino/runtime/common/monitors/src/cpu_monitor.cpp')
-rw-r--r--python/openvino/runtime/common/monitors/src/cpu_monitor.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/python/openvino/runtime/common/monitors/src/cpu_monitor.cpp b/python/openvino/runtime/common/monitors/src/cpu_monitor.cpp
new file mode 100644
index 0000000..e5172a2
--- /dev/null
+++ b/python/openvino/runtime/common/monitors/src/cpu_monitor.cpp
@@ -0,0 +1,206 @@
+// Copyright (C) 2019 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "monitors/cpu_monitor.h"
+
+#include <algorithm>
+#ifdef _WIN32
+#include "monitors/query_wrapper.h"
+#include <string>
+#include <system_error>
+#include <PdhMsg.h>
+#include <Windows.h>
+
+namespace {
+const std::size_t nCores = []() {
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwNumberOfProcessors;
+ }();
+}
+
+class CpuMonitor::PerformanceCounter {
+public:
+ PerformanceCounter() : coreTimeCounters(nCores) {
+ PDH_STATUS status;
+ for (std::size_t i = 0; i < nCores; ++i) {
+ std::wstring fullCounterPath{L"\\Processor(" + std::to_wstring(i) + L")\\% Processor Time"};
+ status = PdhAddCounterW(query, fullCounterPath.c_str(), 0, &coreTimeCounters[i]);
+ if (ERROR_SUCCESS != status) {
+ throw std::system_error(status, std::system_category(), "PdhAddCounterW() failed");
+ }
+ status = PdhSetCounterScaleFactor(coreTimeCounters[i], -2); // scale counter to [0, 1]
+ if (ERROR_SUCCESS != status) {
+ throw std::system_error(status, std::system_category(), "PdhSetCounterScaleFactor() failed");
+ }
+ }
+ status = PdhCollectQueryData(query);
+ if (ERROR_SUCCESS != status) {
+ throw std::system_error(status, std::system_category(), "PdhCollectQueryData() failed");
+ }
+ }
+
+ std::vector<double> getCpuLoad() {
+ PDH_STATUS status;
+ status = PdhCollectQueryData(query);
+ if (ERROR_SUCCESS != status) {
+ throw std::system_error(status, std::system_category(), "PdhCollectQueryData() failed");
+ }
+
+ PDH_FMT_COUNTERVALUE displayValue;
+ std::vector<double> cpuLoad(coreTimeCounters.size());
+ for (std::size_t i = 0; i < coreTimeCounters.size(); ++i) {
+ status = PdhGetFormattedCounterValue(coreTimeCounters[i], PDH_FMT_DOUBLE, NULL,
+ &displayValue);
+ switch (status) {
+ case ERROR_SUCCESS: break;
+ // PdhGetFormattedCounterValue() can sometimes return PDH_CALC_NEGATIVE_DENOMINATOR for some reason
+ case PDH_CALC_NEGATIVE_DENOMINATOR: return {};
+ default:
+ throw std::system_error(status, std::system_category(), "PdhGetFormattedCounterValue() failed");
+ }
+ if (PDH_CSTATUS_VALID_DATA != displayValue.CStatus && PDH_CSTATUS_NEW_DATA != displayValue.CStatus) {
+ throw std::runtime_error("Error in counter data");
+ }
+
+ cpuLoad[i] = displayValue.doubleValue;
+ }
+ return cpuLoad;
+ }
+
+private:
+ QueryWrapper query;
+ std::vector<PDH_HCOUNTER> coreTimeCounters;
+};
+
+#elif __linux__
+#include <chrono>
+#include <regex>
+#include <utility>
+#include <fstream>
+#include <unistd.h>
+
+namespace {
+const long clockTicks = sysconf(_SC_CLK_TCK);
+
+const std::size_t nCores = sysconf(_SC_NPROCESSORS_CONF);
+
+std::vector<unsigned long> getIdleCpuStat() {
+ std::vector<unsigned long> idleCpuStat(nCores);
+ std::ifstream procStat("/proc/stat");
+ std::string line;
+ std::smatch match;
+ std::regex coreJiffies("^cpu(\\d+)\\s+"
+ "(\\d+)\\s+"
+ "(\\d+)\\s+"
+ "(\\d+)\\s+"
+ "(\\d+)\\s+" // idle
+ "(\\d+)"); // iowait
+
+ while (std::getline(procStat, line)) {
+ if (std::regex_search(line, match, coreJiffies)) {
+ // it doesn't handle overflow of sum and overflows of /proc/stat values
+ unsigned long idleInfo = stoul(match[5]) + stoul(match[6]),
+ coreId = stoul(match[1]);
+ if (nCores <= coreId) {
+ throw std::runtime_error("The number of cores has changed");
+ }
+ idleCpuStat[coreId] = idleInfo;
+ }
+ }
+ return idleCpuStat;
+}
+}
+
+class CpuMonitor::PerformanceCounter {
+public:
+ PerformanceCounter() : prevIdleCpuStat{getIdleCpuStat()}, prevTimePoint{std::chrono::steady_clock::now()} {}
+
+ std::vector<double> getCpuLoad() {
+ std::vector<unsigned long> idleCpuStat = getIdleCpuStat();
+ auto timePoint = std::chrono::steady_clock::now();
+ // don't update data too frequently which may result in negative values for cpuLoad.
+ // It may happen when collectData() is called just after setHistorySize().
+ if (timePoint - prevTimePoint > std::chrono::milliseconds{100}) {
+ std::vector<double> cpuLoad(nCores);
+ for (std::size_t i = 0; i < idleCpuStat.size(); ++i) {
+ double idleDiff = idleCpuStat[i] - prevIdleCpuStat[i];
+ typedef std::chrono::duration<double, std::chrono::seconds::period> Sec;
+ cpuLoad[i] = 1.0
+ - idleDiff / clockTicks / std::chrono::duration_cast<Sec>(timePoint - prevTimePoint).count();
+ }
+ prevIdleCpuStat = std::move(idleCpuStat);
+ prevTimePoint = timePoint;
+ return cpuLoad;
+ }
+ return {};
+ }
+private:
+ std::vector<unsigned long> prevIdleCpuStat;
+ std::chrono::steady_clock::time_point prevTimePoint;
+};
+
+#else
+// not implemented
+namespace {
+const std::size_t nCores{0};
+}
+
+class CpuMonitor::PerformanceCounter {
+public:
+ std::vector<double> getCpuLoad() {return {};};
+};
+#endif
+
+CpuMonitor::CpuMonitor() :
+ samplesNumber{0},
+ historySize{0},
+ cpuLoadSum(nCores, 0) {}
+
+// PerformanceCounter is incomplete in header and destructor can't be defined implicitly
+CpuMonitor::~CpuMonitor() = default;
+
+void CpuMonitor::setHistorySize(std::size_t size) {
+ if (0 == historySize && 0 != size) {
+ performanceCounter.reset(new PerformanceCounter);
+ } else if (0 != historySize && 0 == size) {
+ performanceCounter.reset();
+ }
+ historySize = size;
+ std::ptrdiff_t newSize = static_cast<std::ptrdiff_t>(std::min(size, cpuLoadHistory.size()));
+ cpuLoadHistory.erase(cpuLoadHistory.begin(), cpuLoadHistory.end() - newSize);
+}
+
+void CpuMonitor::collectData() {
+ std::vector<double> cpuLoad = performanceCounter->getCpuLoad();
+
+ if (!cpuLoad.empty()) {
+ for (std::size_t i = 0; i < cpuLoad.size(); ++i) {
+ cpuLoadSum[i] += cpuLoad[i];
+ }
+ ++samplesNumber;
+
+ cpuLoadHistory.push_back(std::move(cpuLoad));
+ if (cpuLoadHistory.size() > historySize) {
+ cpuLoadHistory.pop_front();
+ }
+ }
+}
+
+std::size_t CpuMonitor::getHistorySize() const {
+ return historySize;
+}
+
+std::deque<std::vector<double>> CpuMonitor::getLastHistory() const {
+ return cpuLoadHistory;
+}
+
+std::vector<double> CpuMonitor::getMeanCpuLoad() const {
+ std::vector<double> meanCpuLoad;
+ meanCpuLoad.reserve(cpuLoadSum.size());
+ for (double coreLoad : cpuLoadSum) {
+ meanCpuLoad.push_back(samplesNumber ? coreLoad / samplesNumber : 0);
+ }
+ return meanCpuLoad;
+}