From a6e2a7c53dc21928aaa3a051833d3a09de3bc7d0 Mon Sep 17 00:00:00 2001 From: Ronen Friedman Date: Mon, 17 Jun 2024 12:49:46 -0500 Subject: [PATCH] common: MemoryModel: keep /proc files open Allowing clients to hold on to the MemoryModel object for multiple "snapshots", saving (per measurements) ~40% of the sampling run time. Also: separating the parsing of /proc/maps (which consumes most of the remaining execution time) into a separate function. This will allow us to create a "no need for precise heap" fast mode (in a future commit). Signed-off-by: Ronen Friedman --- src/common/MemoryModel.cc | 87 +++++++++++++++++++++------------------ src/common/MemoryModel.h | 11 +++++ 2 files changed, 59 insertions(+), 39 deletions(-) diff --git a/src/common/MemoryModel.cc b/src/common/MemoryModel.cc index e6511547db3..4a19946133c 100644 --- a/src/common/MemoryModel.cc +++ b/src/common/MemoryModel.cc @@ -5,7 +5,10 @@ #include #endif -#include +#include + +#include "common/fmt_common.h" + #define dout_subsys ceph_subsys_ @@ -17,45 +20,21 @@ MemoryModel::MemoryModel(CephContext *cct_) { } -void MemoryModel::_sample(mem_snap_t *psnap) +std::optional MemoryModel::get_mapped_heap() { - ifstream f; - - f.open(PROCPREFIX "/proc/self/status"); - if (!f.is_open()) { - ldout(cct, 0) << "check_memory_usage unable to open " PROCPREFIX "/proc/self/status" << dendl; - return; + if (!proc_maps.is_open()) { + ldout(cct, 0) << fmt::format("MemoryModel::get_mapped_heap() unable to open {}", proc_maps_fn) << dendl; + return std::nullopt; } - while (!f.eof()) { - string line; - getline(f, line); - - if (strncmp(line.c_str(), "VmSize:", 7) == 0) - psnap->size = atol(line.c_str() + 7); - else if (strncmp(line.c_str(), "VmRSS:", 6) == 0) - psnap->rss = atol(line.c_str() + 7); - else if (strncmp(line.c_str(), "VmHWM:", 6) == 0) - psnap->hwm = atol(line.c_str() + 7); - else if (strncmp(line.c_str(), "VmLib:", 6) == 0) - psnap->lib = atol(line.c_str() + 7); - else if (strncmp(line.c_str(), "VmPeak:", 7) == 0) - psnap->peak = atol(line.c_str() + 7); - else if (strncmp(line.c_str(), "VmData:", 7) == 0) - psnap->data = atol(line.c_str() + 7); - } - f.close(); + // always rewind before reading + proc_maps.clear(); + proc_maps.seekg(0); - f.open(PROCPREFIX "/proc/self/maps"); - if (!f.is_open()) { - ldout(cct, 0) << "check_memory_usage unable to open " PROCPREFIX "/proc/self/maps" << dendl; - return; - } + int64_t heap = 0; - long heap = 0; - while (f.is_open() && !f.eof()) { + while (proc_maps.is_open() && !proc_maps.eof()) { string line; - getline(f, line); - //ldout(cct, 0) << "line is " << line << dendl; + getline(proc_maps, line); const char *start = line.c_str(); const char *dash = start; @@ -69,8 +48,6 @@ void MemoryModel::_sample(mem_snap_t *psnap) unsigned long long as = strtoll(start, 0, 16); unsigned long long ae = strtoll(dash+1, 0, 16); - //ldout(cct, 0) << std::hex << as << " to " << ae << std::dec << dendl; - end++; const char *mode = end; @@ -83,7 +60,6 @@ void MemoryModel::_sample(mem_snap_t *psnap) end++; long size = ae - as; - //ldout(cct, 0) << "size " << size << " mode is '" << mode << "' end is '" << end << "'" << dendl; /* * anything 'rw' and anon is assumed to be heap. @@ -92,6 +68,39 @@ void MemoryModel::_sample(mem_snap_t *psnap) heap += size; } - psnap->heap = heap >> 10; + return heap; +} + + + +void MemoryModel::_sample(mem_snap_t *psnap) +{ + if (!proc_status.is_open()) { + ldout(cct, 0) << fmt::format("MemoryModel::sample() unable to open {}", proc_stat_fn) << dendl; + return; + } + // always rewind before reading + proc_status.clear(); + proc_status.seekg(0); + + while (!proc_status.eof()) { + string line; + getline(proc_status, line); + + if (strncmp(line.c_str(), "VmSize:", 7) == 0) + psnap->size = atol(line.c_str() + 7); + else if (strncmp(line.c_str(), "VmRSS:", 6) == 0) + psnap->rss = atol(line.c_str() + 7); + else if (strncmp(line.c_str(), "VmHWM:", 6) == 0) + psnap->hwm = atol(line.c_str() + 7); + else if (strncmp(line.c_str(), "VmLib:", 6) == 0) + psnap->lib = atol(line.c_str() + 7); + else if (strncmp(line.c_str(), "VmPeak:", 7) == 0) + psnap->peak = atol(line.c_str() + 7); + else if (strncmp(line.c_str(), "VmData:", 7) == 0) + psnap->data = atol(line.c_str() + 7); + } + // get heap size + psnap->heap = static_cast(get_mapped_heap().value_or(0)); } diff --git a/src/common/MemoryModel.h b/src/common/MemoryModel.h index ca148191454..7191e6e31f9 100644 --- a/src/common/MemoryModel.h +++ b/src/common/MemoryModel.h @@ -15,7 +15,11 @@ #ifndef CEPH_MEMORYMODEL_H #define CEPH_MEMORYMODEL_H +#include +#include #include "include/common_fwd.h" +#include "include/compat.h" + class MemoryModel { public: @@ -39,8 +43,15 @@ public: } last; private: + static inline constexpr const char* proc_stat_fn = PROCPREFIX "/proc/self/status"; + static inline constexpr const char* proc_maps_fn = PROCPREFIX "/proc/self/maps"; + + std::ifstream proc_status{proc_stat_fn}; + std::ifstream proc_maps{proc_maps_fn}; + CephContext *cct; void _sample(mem_snap_t *p); + std::optional get_mapped_heap(); public: explicit MemoryModel(CephContext *cct); -- 2.39.5