summaryrefslogtreecommitdiff
path: root/python/openvino/runtime/common/monitors/src/presenter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'python/openvino/runtime/common/monitors/src/presenter.cpp')
-rw-r--r--python/openvino/runtime/common/monitors/src/presenter.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/python/openvino/runtime/common/monitors/src/presenter.cpp b/python/openvino/runtime/common/monitors/src/presenter.cpp
new file mode 100644
index 0000000..61f5e15
--- /dev/null
+++ b/python/openvino/runtime/common/monitors/src/presenter.cpp
@@ -0,0 +1,330 @@
+// Copyright (C) 2019 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <cctype>
+#include <chrono>
+#include <iomanip>
+#include <numeric>
+#include <string>
+#include <vector>
+
+#include "monitors/presenter.h"
+
+namespace {
+const std::map<int, MonitorType> keyToMonitorType{
+ {'C', MonitorType::CpuAverage},
+ {'D', MonitorType::DistributionCpu},
+ {'M', MonitorType::Memory}};
+
+std::set<MonitorType> strKeysToMonitorSet(const std::string& keys) {
+ std::set<MonitorType> enabledMonitors;
+ if (keys == "h") {
+ return enabledMonitors;
+ }
+ for (unsigned char key: keys) {
+ if (key == 'h') {
+ throw std::runtime_error("Unacceptable combination of monitor types-can't show and hide info at the same time");
+ }
+ auto iter = keyToMonitorType.find(std::toupper(key));
+ if (keyToMonitorType.end() == iter) {
+ throw std::runtime_error("Unknown monitor type");
+ } else {
+ enabledMonitors.insert(iter->second);
+ }
+ }
+ return enabledMonitors;
+}
+}
+
+Presenter::Presenter(std::set<MonitorType> enabledMonitors,
+ int yPos,
+ cv::Size graphSize,
+ std::size_t historySize) :
+ yPos{yPos},
+ graphSize{graphSize},
+ graphPadding{std::max(1, static_cast<int>(graphSize.width * 0.05))},
+ historySize{historySize},
+ distributionCpuEnabled{false},
+ strStream{std::ios_base::app} {
+ for (MonitorType monitor : enabledMonitors) {
+ addRemoveMonitor(monitor);
+ }
+}
+
+Presenter::Presenter(const std::string& keys, int yPos, cv::Size graphSize, std::size_t historySize) :
+ Presenter{strKeysToMonitorSet(keys), yPos, graphSize, historySize} {}
+
+void Presenter::addRemoveMonitor(MonitorType monitor) {
+ unsigned updatedHistorySize = 1;
+ if (historySize > 1) {
+ int sampleStep = std::max(1, static_cast<int>(graphSize.width / (historySize - 1)));
+ // +1 to plot graphSize.width/sampleStep segments
+ // add round up to and an extra element if don't reach graph edge
+ updatedHistorySize = (graphSize.width + sampleStep - 1) / sampleStep + 1;
+ }
+ switch(monitor) {
+ case MonitorType::CpuAverage: {
+ if (cpuMonitor.getHistorySize() > 1 && distributionCpuEnabled) {
+ cpuMonitor.setHistorySize(1);
+ } else if (cpuMonitor.getHistorySize() > 1 && !distributionCpuEnabled) {
+ cpuMonitor.setHistorySize(0);
+ } else { // cpuMonitor.getHistorySize() <= 1
+ cpuMonitor.setHistorySize(updatedHistorySize);
+ }
+ break;
+ }
+ case MonitorType::DistributionCpu: {
+ if (distributionCpuEnabled) {
+ distributionCpuEnabled = false;
+ if (1 == cpuMonitor.getHistorySize()) { // cpuMonitor was used only for DistributionCpu => disable it
+ cpuMonitor.setHistorySize(0);
+ }
+ } else {
+ distributionCpuEnabled = true;
+ cpuMonitor.setHistorySize(std::max(std::size_t{1}, cpuMonitor.getHistorySize()));
+ }
+ break;
+ }
+ case MonitorType::Memory: {
+ if (memoryMonitor.getHistorySize() > 1) {
+ memoryMonitor.setHistorySize(0);
+ } else {
+ memoryMonitor.setHistorySize(updatedHistorySize);
+ }
+ break;
+ }
+ }
+}
+
+void Presenter::handleKey(int key) {
+ key = std::toupper(key);
+ if ('H' == key) {
+ if (0 == cpuMonitor.getHistorySize() && memoryMonitor.getHistorySize() <= 1) {
+ addRemoveMonitor(MonitorType::CpuAverage);
+ addRemoveMonitor(MonitorType::DistributionCpu);
+ addRemoveMonitor(MonitorType::Memory);
+ } else {
+ cpuMonitor.setHistorySize(0);
+ distributionCpuEnabled = false;
+ memoryMonitor.setHistorySize(0);
+ }
+ } else {
+ auto iter = keyToMonitorType.find(key);
+ if (keyToMonitorType.end() != iter) {
+ addRemoveMonitor(iter->second);
+ }
+ }
+}
+
+void Presenter::drawGraphs(cv::Mat& frame) {
+ const std::chrono::steady_clock::time_point curTimeStamp = std::chrono::steady_clock::now();
+ if (curTimeStamp - prevTimeStamp >= std::chrono::milliseconds{1000}) {
+ prevTimeStamp = curTimeStamp;
+ if (0 != cpuMonitor.getHistorySize()) {
+ cpuMonitor.collectData();
+ }
+ if (memoryMonitor.getHistorySize() > 1) {
+ memoryMonitor.collectData();
+ }
+ }
+
+ int numberOfEnabledMonitors = (cpuMonitor.getHistorySize() > 1) + distributionCpuEnabled
+ + (memoryMonitor.getHistorySize() > 1);
+ int panelWidth = graphSize.width * numberOfEnabledMonitors
+ + std::max(0, numberOfEnabledMonitors - 1) * graphPadding;
+ while (panelWidth > frame.cols) {
+ panelWidth = std::max(0, panelWidth - graphSize.width - graphPadding);
+ --numberOfEnabledMonitors; // can't draw all monitors
+ }
+ int graphPos = std::max(0, (frame.cols - 1 - panelWidth) / 2);
+ int textGraphSplittingLine = graphSize.height / 5;
+ int graphRectHeight = graphSize.height - textGraphSplittingLine;
+ int sampleStep = 1;
+ unsigned possibleHistorySize = 1;
+ if (historySize > 1) {
+ sampleStep = std::max(1, static_cast<int>(graphSize.width / (historySize - 1)));
+ possibleHistorySize = (graphSize.width + sampleStep - 1) / sampleStep + 1;
+ }
+
+ if (cpuMonitor.getHistorySize() > 1 && possibleHistorySize > 1 && --numberOfEnabledMonitors >= 0) {
+ std::deque<std::vector<double>> lastHistory = cpuMonitor.getLastHistory();
+ cv::Rect intersection = cv::Rect{cv::Point(graphPos, yPos), graphSize} & cv::Rect{0, 0, frame.cols, frame.rows};
+ if (!intersection.area()) {
+ return;
+ }
+ cv::Mat graph = frame(intersection);
+ graph = graph / 2 + cv::Scalar{127, 127, 127};
+
+ int lineXPos = graph.cols - 1;
+ std::vector<cv::Point> averageLoad(lastHistory.size());
+
+ for (int i = lastHistory.size() - 1; i >= 0; --i) {
+ double mean = std::accumulate(lastHistory[i].begin(), lastHistory[i].end(), 0.0) / lastHistory[i].size();
+ averageLoad[i] = {lineXPos, graphSize.height - static_cast<int>(mean * graphRectHeight)};
+ lineXPos -= sampleStep;
+ }
+
+ cv::polylines(graph, averageLoad, false, {255, 0, 0}, 2);
+ cv::rectangle(frame, cv::Rect{
+ cv::Point{graphPos, yPos + textGraphSplittingLine},
+ cv::Size{graphSize.width, graphSize.height - textGraphSplittingLine}
+ }, {0, 0, 0});
+ strStream.str("CPU");
+ if (!lastHistory.empty()) {
+ strStream << ": " << std::fixed << std::setprecision(1)
+ << std::accumulate(lastHistory.back().begin(), lastHistory.back().end(), 0.0)
+ / lastHistory.back().size() * 100 << '%';
+ }
+ int baseline;
+ int textWidth = cv::getTextSize(strStream.str(),
+ cv::FONT_HERSHEY_SIMPLEX,
+ textGraphSplittingLine * 0.04,
+ 1,
+ &baseline).width;
+ cv::putText(graph,
+ strStream.str(),
+ cv::Point{(graphSize.width - textWidth) / 2, textGraphSplittingLine - 1},
+ cv::FONT_HERSHEY_SIMPLEX,
+ textGraphSplittingLine * 0.04,
+ {70, 0, 0},
+ 1);
+ graphPos += graphSize.width + graphPadding;
+ }
+
+ if (distributionCpuEnabled && --numberOfEnabledMonitors >= 0) {
+ std::deque<std::vector<double>> lastHistory = cpuMonitor.getLastHistory();
+ cv::Rect intersection = cv::Rect{cv::Point(graphPos, yPos), graphSize} & cv::Rect{0, 0, frame.cols, frame.rows};
+ if (!intersection.area()) {
+ return;
+ }
+ cv::Mat graph = frame(intersection);
+ graph = graph / 2 + cv::Scalar{127, 127, 127};
+
+ if (!lastHistory.empty()) {
+ int rectXPos = 0;
+ int step = (graph.cols + lastHistory.back().size() - 1) / lastHistory.back().size(); // round up
+ double sum = 0;
+ for (double coreLoad : lastHistory.back()) {
+ sum += coreLoad;
+ int height = static_cast<int>(graphRectHeight * coreLoad);
+ cv::Rect pillar{cv::Point{rectXPos, graph.rows - height}, cv::Size{step, height}};
+ cv::rectangle(graph, pillar, {255, 0, 0}, cv::FILLED);
+ cv::rectangle(graph, pillar, {0, 0, 0});
+ rectXPos += step;
+ }
+ sum /= lastHistory.back().size();
+ int yLine = graph.rows - static_cast<int>(graphRectHeight * sum);
+ cv::line(graph, cv::Point{0, yLine}, cv::Point{graph.cols, yLine}, {0, 255, 0}, 2);
+ }
+ cv::Rect border{cv::Point{graphPos, yPos + textGraphSplittingLine},
+ cv::Size{graphSize.width, graphSize.height - textGraphSplittingLine}};
+ cv::rectangle(frame, border, {0, 0, 0});
+ strStream.str("Core load");
+ if (!lastHistory.empty()) {
+ strStream << ": " << std::fixed << std::setprecision(1)
+ << std::accumulate(lastHistory.back().begin(), lastHistory.back().end(), 0.0)
+ / lastHistory.back().size() * 100 << '%';
+ }
+ int baseline;
+ int textWidth = cv::getTextSize(strStream.str(),
+ cv::FONT_HERSHEY_SIMPLEX,
+ textGraphSplittingLine * 0.04,
+ 1,
+ &baseline).width;
+ cv::putText(graph,
+ strStream.str(),
+ cv::Point{(graphSize.width - textWidth) / 2, textGraphSplittingLine - 1},
+ cv::FONT_HERSHEY_SIMPLEX,
+ textGraphSplittingLine * 0.04,
+ {0, 70, 0});
+ graphPos += graphSize.width + graphPadding;
+ }
+
+ if (memoryMonitor.getHistorySize() > 1 && possibleHistorySize > 1 && --numberOfEnabledMonitors >= 0) {
+ std::deque<std::pair<double, double>> lastHistory = memoryMonitor.getLastHistory();
+ cv::Rect intersection = cv::Rect{cv::Point(graphPos, yPos), graphSize} & cv::Rect{0, 0, frame.cols, frame.rows};
+ if (!intersection.area()) {
+ return;
+ }
+ cv::Mat graph = frame(intersection);
+ graph = graph / 2 + cv::Scalar{127, 127, 127};
+ int histxPos = graph.cols - 1;
+ double range = std::min(memoryMonitor.getMaxMemTotal() + memoryMonitor.getMaxSwap(),
+ (memoryMonitor.getMaxMem() + memoryMonitor.getMaxSwap()) * 1.2);
+ if (lastHistory.size() > 1) {
+ for (auto memUsageIt = lastHistory.rbegin(); memUsageIt != lastHistory.rend() - 1; ++memUsageIt) {
+ constexpr double SWAP_THRESHOLD = 10.0 / 1024; // 10 MiB
+ cv::Vec3b color =
+ (memoryMonitor.getMemTotal() * 0.95 > memUsageIt->first) || (memUsageIt->second < SWAP_THRESHOLD) ?
+ cv::Vec3b{0, 255, 255} :
+ cv::Vec3b{0, 0, 255};
+ cv::Point right{histxPos,
+ graph.rows - static_cast<int>(graphRectHeight * (memUsageIt->first + memUsageIt->second) / range)};
+ cv::Point left{histxPos - sampleStep,
+ graph.rows - static_cast<int>(
+ graphRectHeight * ((memUsageIt + 1)->first + (memUsageIt + 1)->second) / range)};
+ cv::line(graph, right, left, color, 2);
+ histxPos -= sampleStep;
+ }
+ }
+
+ cv::Rect border{cv::Point{graphPos, yPos + textGraphSplittingLine},
+ cv::Size{graphSize.width, graphSize.height - textGraphSplittingLine}};
+ cv::rectangle(frame, {border}, {0, 0, 0});
+ if (lastHistory.empty()) {
+ strStream.str("Memory");
+ } else {
+ strStream.str("");
+ strStream << std::fixed << std::setprecision(1) << lastHistory.back().first << " + "
+ << lastHistory.back().second << " GiB";
+ }
+ int baseline;
+ int textWidth = cv::getTextSize(strStream.str(),
+ cv::FONT_HERSHEY_SIMPLEX,
+ textGraphSplittingLine * 0.04,
+ 1,
+ &baseline).width;
+ cv::putText(graph,
+ strStream.str(),
+ cv::Point{(graphSize.width - textWidth) / 2, textGraphSplittingLine - 1},
+ cv::FONT_HERSHEY_SIMPLEX,
+ textGraphSplittingLine * 0.04,
+ {0, 35, 35});
+ }
+}
+
+std::vector<std::string> Presenter::reportMeans() const {
+ std::vector<std::string> collectedData;
+ if (cpuMonitor.getHistorySize() > 1 || distributionCpuEnabled || memoryMonitor.getHistorySize() > 1) {
+ collectedData.push_back("Resources usage:");
+ }
+ if (cpuMonitor.getHistorySize() > 1) {
+ std::ostringstream collectedDataStream;
+ collectedDataStream << std::fixed << std::setprecision(1);
+ collectedDataStream << "\tMean core utilization: ";
+ for (double mean : cpuMonitor.getMeanCpuLoad()) {
+ collectedDataStream << mean * 100 << "% ";
+ }
+ collectedData.push_back(collectedDataStream.str());
+ }
+ if (distributionCpuEnabled) {
+ std::ostringstream collectedDataStream;
+ collectedDataStream << std::fixed << std::setprecision(1);
+ std::vector<double> meanCpuLoad = cpuMonitor.getMeanCpuLoad();
+ double mean = std::accumulate(meanCpuLoad.begin(), meanCpuLoad.end(), 0.0) / meanCpuLoad.size();
+ collectedDataStream << "\tMean CPU utilization: " << mean * 100 << "%";
+ collectedData.push_back(collectedDataStream.str());
+ }
+ if (memoryMonitor.getHistorySize() > 1) {
+ std::ostringstream collectedDataStream;
+ collectedDataStream << std::fixed << std::setprecision(1);
+ collectedDataStream << "\tMemory mean usage: " << memoryMonitor.getMeanMem() << " GiB";
+ collectedData.push_back(collectedDataStream.str());
+ collectedDataStream.str("");
+ collectedDataStream << "\tMean swap usage: " << memoryMonitor.getMeanSwap() << " GiB";
+ collectedData.push_back(collectedDataStream.str());
+ }
+
+ return collectedData;
+}