]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
common: MemoryModel: keep /proc files open
authorRonen Friedman <rfriedma@redhat.com>
Mon, 17 Jun 2024 17:49:46 +0000 (12:49 -0500)
committerRonen Friedman <rfriedma@redhat.com>
Tue, 18 Jun 2024 11:35:31 +0000 (06:35 -0500)
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 <rfriedma@redhat.com>
src/common/MemoryModel.cc
src/common/MemoryModel.h

index e6511547db3272123a68916d8fb511e07a629a39..4a19946133cbc5f1c6fc105ae9d04b9a020a78b6 100644 (file)
@@ -5,7 +5,10 @@
 #include <malloc.h>
 #endif
 
-#include <fstream>
+#include <charconv>
+
+#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<int64_t> 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<long>(get_mapped_heap().value_or(0));
 }
index ca14819145424da42d20357a10a37b38dc1e6169..7191e6e31f9ff9490f1b385a195223731cc4753b 100644 (file)
 #ifndef CEPH_MEMORYMODEL_H
 #define CEPH_MEMORYMODEL_H
 
+#include <fstream>
+#include <optional>
 #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<int64_t> get_mapped_heap();
 
 public:
   explicit MemoryModel(CephContext *cct);