Initial setup for CLion

This commit is contained in:
2026-03-28 16:54:11 +11:00
parent 239cc02591
commit 7b4134133c
1136 changed files with 811916 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
// Copyright (C) 2019-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "monitors/cpu_monitor.h"
#include <algorithm>
#ifdef _WIN32
#include "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>(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;
}

View File

@@ -0,0 +1,213 @@
// Copyright (C) 2019-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "monitors/memory_monitor.h"
struct MemState {
double memTotal, usedMem, usedSwap;
};
#ifdef _WIN32
#include "query_wrapper.h"
#include <algorithm>
#define PSAPI_VERSION 2
#include <system_error>
#include <Windows.h>
#include <PdhMsg.h>
#include <Psapi.h>
namespace {
double getMemTotal() {
PERFORMANCE_INFORMATION performanceInformation;
if (!GetPerformanceInfo(&performanceInformation, sizeof(performanceInformation))) {
throw std::runtime_error("GetPerformanceInfo() failed");
}
return static_cast<double>(performanceInformation.PhysicalTotal * performanceInformation.PageSize)
/ (1024 * 1024 * 1024);
}
}
class MemoryMonitor::PerformanceCounter {
public:
PerformanceCounter() {
PDH_STATUS status = PdhAddCounterW(query, L"\\Paging File(_Total)\\% Usage", 0, &pagingFileUsageCounter);
if (ERROR_SUCCESS != status) {
throw std::system_error(status, std::system_category(), "PdhAddCounterW() failed");
}
status = PdhSetCounterScaleFactor(pagingFileUsageCounter, -2); // scale counter to [0, 1]
if (ERROR_SUCCESS != status) {
throw std::system_error(status, std::system_category(), "PdhSetCounterScaleFactor() failed");
}
}
MemState getMemState() {
PERFORMANCE_INFORMATION performanceInformation;
if (!GetPerformanceInfo(&performanceInformation, sizeof(performanceInformation))) {
throw std::runtime_error("GetPerformanceInfo() failed");
}
PDH_STATUS status;
status = PdhCollectQueryData(query);
if (ERROR_SUCCESS != status) {
throw std::system_error(status, std::system_category(), "PdhCollectQueryData() failed");
}
PDH_FMT_COUNTERVALUE displayValue;
status = PdhGetFormattedCounterValue(pagingFileUsageCounter, PDH_FMT_DOUBLE, NULL, &displayValue);
if (ERROR_SUCCESS != status) {
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");
}
double pagingFilesSize = static_cast<double>(
(performanceInformation.CommitLimit - performanceInformation.PhysicalTotal)
* performanceInformation.PageSize) / (1024 * 1024 * 1024);
return {static_cast<double>(performanceInformation.PhysicalTotal * performanceInformation.PageSize)
/ (1024 * 1024 * 1024),
static_cast<double>(
(performanceInformation.PhysicalTotal - performanceInformation.PhysicalAvailable)
* performanceInformation.PageSize) / (1024 * 1024 * 1024),
pagingFilesSize * displayValue.doubleValue};
}
private:
QueryWrapper query;
PDH_HCOUNTER pagingFileUsageCounter;
};
#elif __linux__
#include <fstream>
#include <utility>
#include <vector>
#include <regex>
namespace {
std::pair<std::pair<double, double>, std::pair<double, double>> getAvailableMemSwapTotalMemSwap() {
double memAvailable = 0, swapFree = 0, memTotal = 0, swapTotal = 0;
std::regex memRegex("^(.+):\\s+(\\d+) kB$");
std::string line;
std::smatch match;
std::ifstream meminfo("/proc/meminfo");
while (std::getline(meminfo, line)) {
if (std::regex_match(line, match, memRegex)) {
if ("MemAvailable" == match[1]) {
memAvailable = stod(match[2]) / (1024 * 1024);
} else if ("SwapFree" == match[1]) {
swapFree = stod(match[2]) / (1024 * 1024);
} else if ("MemTotal" == match[1]) {
memTotal = stod(match[2]) / (1024 * 1024);
} else if ("SwapTotal" == match[1]) {
swapTotal = stod(match[2]) / (1024 * 1024);
}
}
}
if (0 == memTotal) {
throw std::runtime_error("Can't get MemTotal");
}
return {{memAvailable, swapFree}, {memTotal, swapTotal}};
}
double getMemTotal() {
return getAvailableMemSwapTotalMemSwap().second.first;
}
}
class MemoryMonitor::PerformanceCounter {
public:
MemState getMemState() {
std::pair<std::pair<double, double>, std::pair<double, double>> availableMemSwapTotalMemSwap
= getAvailableMemSwapTotalMemSwap();
double memTotal = availableMemSwapTotalMemSwap.second.first;
double swapTotal = availableMemSwapTotalMemSwap.second.second;
return {memTotal, memTotal - availableMemSwapTotalMemSwap.first.first, swapTotal - availableMemSwapTotalMemSwap.first.second};
}
};
#else
// not implemented
namespace {
double getMemTotal() {return 0.0;}
}
class MemoryMonitor::PerformanceCounter {
public:
MemState getMemState() {return {0.0, 0.0, 0.0};}
};
#endif
MemoryMonitor::MemoryMonitor() :
samplesNumber{0},
historySize{0},
memSum{0.0},
swapSum{0.0},
maxMem{0.0},
maxSwap{0.0},
memTotal{0.0},
maxMemTotal{0.0} {}
// PerformanceCounter is incomplete in header and destructor can't be defined implicitly
MemoryMonitor::~MemoryMonitor() = default;
void MemoryMonitor::setHistorySize(std::size_t size) {
if (0 == historySize && 0 != size) {
performanceCounter.reset(new MemoryMonitor::PerformanceCounter);
// memTotal is not initialized in constructor because for linux its initialization involves constructing
// std::regex which is unimplemented and throws an exception for gcc 4.8.5 (default for CentOS 7.4).
// Delaying initialization triggers the error only when the monitor is used
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631
memTotal = ::getMemTotal();
} else if (0 != historySize && 0 == size) {
performanceCounter.reset();
}
historySize = size;
std::size_t newSize = min(size, memSwapUsageHistory.size());
memSwapUsageHistory.erase(memSwapUsageHistory.begin(), memSwapUsageHistory.end() - newSize);
}
void MemoryMonitor::collectData() {
MemState memState = performanceCounter->getMemState();
maxMemTotal = max(maxMemTotal, memState.memTotal);
memSum += memState.usedMem;
swapSum += memState.usedSwap;
++samplesNumber;
maxMem = max(maxMem, memState.usedMem);
maxSwap = max(maxSwap, memState.usedSwap);
memSwapUsageHistory.emplace_back(memState.usedMem, memState.usedSwap);
if (memSwapUsageHistory.size() > historySize) {
memSwapUsageHistory.pop_front();
}
}
std::size_t MemoryMonitor::getHistorySize() const {
return historySize;
}
std::deque<std::pair<double, double>> MemoryMonitor::getLastHistory() const {
return memSwapUsageHistory;
}
double MemoryMonitor::getMeanMem() const {
return samplesNumber ? memSum / samplesNumber : 0;
}
double MemoryMonitor::getMeanSwap() const {
return samplesNumber ? swapSum / samplesNumber : 0;
}
double MemoryMonitor::getMaxMem() const {
return maxMem;
}
double MemoryMonitor::getMaxSwap() const {
return maxSwap;
}
double MemoryMonitor::getMemTotal() const {
return memTotal;
}
double MemoryMonitor::getMaxMemTotal() const {
return maxMemTotal;
}

View File

@@ -0,0 +1,330 @@
// Copyright (C) 2019-2024 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;
}

View File

@@ -0,0 +1,22 @@
// Copyright (C) 2019-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "query_wrapper.h"
#include <Windows.h>
#include <system_error>
QueryWrapper::QueryWrapper() {
PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query);
if (ERROR_SUCCESS != status) {
throw std::system_error(status, std::system_category(), "PdhOpenQuery() failed");
}
}
QueryWrapper::~QueryWrapper() {
PdhCloseQuery(query);
}
QueryWrapper::operator PDH_HQUERY() const {
return query;
}

View File

@@ -0,0 +1,17 @@
// Copyright (C) 2019-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#pragma once
#include <Pdh.h>
class QueryWrapper {
public:
QueryWrapper();
~QueryWrapper();
QueryWrapper(const QueryWrapper&) = delete;
QueryWrapper& operator=(const QueryWrapper&) = delete;
operator PDH_HQUERY() const;
private:
PDH_HQUERY query;
};