diff options
Diffstat (limited to 'python/openvino/runtime/common/monitors/src/memory_monitor.cpp')
| -rw-r--r-- | python/openvino/runtime/common/monitors/src/memory_monitor.cpp | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/python/openvino/runtime/common/monitors/src/memory_monitor.cpp b/python/openvino/runtime/common/monitors/src/memory_monitor.cpp new file mode 100644 index 0000000..70879d6 --- /dev/null +++ b/python/openvino/runtime/common/monitors/src/memory_monitor.cpp @@ -0,0 +1,213 @@ +// Copyright (C) 2019 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "monitors/memory_monitor.h" + +struct MemState { + double memTotal, usedMem, usedSwap; +}; + +#ifdef _WIN32 +#include "monitors/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 = std::min(size, memSwapUsageHistory.size()); + memSwapUsageHistory.erase(memSwapUsageHistory.begin(), memSwapUsageHistory.end() - newSize); +} + +void MemoryMonitor::collectData() { + MemState memState = performanceCounter->getMemState(); + maxMemTotal = std::max(maxMemTotal, memState.memTotal); + memSum += memState.usedMem; + swapSum += memState.usedSwap; + ++samplesNumber; + maxMem = std::max(maxMem, memState.usedMem); + maxSwap = std::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; +} |
