]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
common: MemoryModel: use charconv to parse /proc/status
authorRonen Friedman <rfriedma@redhat.com>
Mon, 17 Jun 2024 18:23:26 +0000 (13:23 -0500)
committerRonen Friedman <rfriedma@redhat.com>
Tue, 18 Jun 2024 11:36:02 +0000 (06:36 -0500)
Also - stopping the parsing of /proc/status once all the needed fields
have been found,
The resulting code is measurably faster than the previous version.

Signed-off-by: Ronen Friedman <rfriedma@redhat.com>
src/common/MemoryModel.cc
src/common/MemoryModel.h

index 4a19946133cbc5f1c6fc105ae9d04b9a020a78b6..354d66bad8305c8082aed23d9218ab27304276f7 100644 (file)
@@ -1,6 +1,8 @@
-#include "MemoryModel.h"
-#include "include/compat.h"
 #include "debug.h"
+
+#include "include/compat.h"
+
+#include "MemoryModel.h"
 #if defined(__linux__)
 #include <malloc.h>
 #endif
 using namespace std;
 using mem_snap_t = MemoryModel::mem_snap_t;
 
-MemoryModel::MemoryModel(CephContext *cct_)
-  : cct(cct_)
+MemoryModel::MemoryModel(CephContext *cct_) : cct(cct_) {}
+
+inline bool MemoryModel::cmp_against(
+    const std::string &ln,
+    std::string_view param,
+    long &v) const
 {
+  if (ln.size() < (param.size() + 10)) {
+    return false;
+  }
+  if (ln.starts_with(param)) {
+    auto p = ln.c_str();
+    auto s = p + param.size();
+    // charconv does not like leading spaces
+    while (*s && isblank(*s)) {
+      s++;
+    }
+    from_chars(s, p + ln.size(), v);
+    return true;
+  }
+  return false;
 }
 
+
 std::optional<int64_t> MemoryModel::get_mapped_heap()
 {
   if (!proc_maps.is_open()) {
-    ldout(cct, 0) <<  fmt::format("MemoryModel::get_mapped_heap() unable to open {}", proc_maps_fn) << dendl;
+    ldout(cct, 0) << fmt::format(
+                        "MemoryModel::get_mapped_heap() unable to open {}",
+                        proc_maps_fn)
+                 << dendl;
     return std::nullopt;
   }
   // always rewind before reading
@@ -38,15 +62,17 @@ std::optional<int64_t> MemoryModel::get_mapped_heap()
 
     const char *start = line.c_str();
     const char *dash = start;
-    while (*dash && *dash != '-') dash++;
+    while (*dash && *dash != '-')
+      dash++;
     if (!*dash)
       continue;
     const char *end = dash + 1;
-    while (*end && *end != ' ') end++;
+    while (*end && *end != ' ')
+      end++;
     if (!*end)
       continue;
     unsigned long long as = strtoll(start, 0, 16);
-    unsigned long long ae = strtoll(dash+1, 0, 16);
+    unsigned long long ae = strtoll(dash + 1, 0, 16);
 
     end++;
     const char *mode = end;
@@ -54,7 +80,8 @@ std::optional<int64_t> MemoryModel::get_mapped_heap()
     int skip = 4;
     while (skip--) {
       end++;
-      while (*end && *end != ' ') end++;
+      while (*end && *end != ' ')
+       end++;
     }
     if (*end)
       end++;
@@ -72,35 +99,47 @@ std::optional<int64_t> MemoryModel::get_mapped_heap()
 }
 
 
-
-void MemoryModel::_sample(mem_snap_t *psnap)
+std::optional<mem_snap_t> MemoryModel::full_sample()
 {
   if (!proc_status.is_open()) {
-    ldout(cct, 0) <<  fmt::format("MemoryModel::sample() unable to open {}", proc_stat_fn) << dendl;
-    return;
+    ldout(cct, 0) << fmt::format(
+                        "MemoryModel::sample() unable to open {}",
+                        proc_stat_fn)
+                 << dendl;
+    return std::nullopt;
   }
   // 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);
+  mem_snap_t s;
+  // we will be looking for 6 entries
+  int yet_to_find = 6;
+
+  while (!proc_status.eof() && yet_to_find > 0) {
+    string ln;
+    getline(proc_status, ln);
+
+    if (cmp_against(ln, "VmSize:", s.size) ||
+       cmp_against(ln, "VmRSS:", s.rss) || cmp_against(ln, "VmHWM:", s.hwm) ||
+       cmp_against(ln, "VmLib:", s.lib) ||
+       cmp_against(ln, "VmPeak:", s.peak) ||
+       cmp_against(ln, "VmData:", s.data)) {
+      yet_to_find--;
+    }
   }
 
   // get heap size
-  psnap->heap = static_cast<long>(get_mapped_heap().value_or(0));
+  s.heap = static_cast<long>(get_mapped_heap().value_or(0));
+  return s;
+}
+
+void MemoryModel::sample(mem_snap_t *p)
+{
+  auto s = full_sample();
+  if (s) {
+    last = *s;
+    if (p)
+      *p = last;
+  }
 }
index 7191e6e31f9ff9490f1b385a195223731cc4753b..bae3702696788d5f765d06b1f04aeda7fd9fdb9a 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <fstream>
 #include <optional>
+#include <string_view>
 #include "include/common_fwd.h"
 #include "include/compat.h"
 
@@ -50,16 +51,20 @@ private:
   std::ifstream proc_maps{proc_maps_fn};
 
   CephContext *cct;
-  void _sample(mem_snap_t *p);
   std::optional<int64_t> get_mapped_heap();
 
+  /**
+   * @brief Compare a line against an expected data label
+   *
+   * If the line starts with the expected label, extract the value and store it in v.
+   * \retval true if the line starts with the expected label
+   */
+  bool cmp_against(const std::string& ln, std::string_view param, long& v) const;
+
 public:
   explicit MemoryModel(CephContext *cct);
-  void sample(mem_snap_t *p = 0) {
-    _sample(&last);
-    if (p)
-      *p = last;
-  }
+  std::optional<mem_snap_t> full_sample();
+  void sample(mem_snap_t *p = nullptr);
 };
 
 #endif