]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr: add heap admin socket command 69939/head
authorKefu Chai <k.chai@proxmox.com>
Tue, 30 Jun 2026 01:29:18 +0000 (09:29 +0800)
committerKefu Chai <k.chai@proxmox.com>
Sat, 4 Jul 2026 12:41:57 +0000 (20:41 +0800)
the mon, osd and mds register a "heap" asok command that forwards to
ceph_heap_profiler_handle_command, but the mgr never did, so
`ceph daemon mgr.<id> heap stats` returns "no valid command found".
that leaves no way to tcmalloc-profile a leaking mgr through its admin
socket, which is what chasing mgr memory growth needs.

register the same command on MgrStandby's admin socket. its hook lives
for the whole process, so it works on both the standby and the active
mgr. heap output goes to the bufferlist, as on the other daemons, while
status keeps using the formatter.

Signed-off-by: Kefu Chai <k.chai@proxmox.com>
src/mgr/MgrStandby.cc
src/mgr/MgrStandby.h

index 70db213596652ac17c3addfb0b00ce8470fceaa8..8209d4f8b4c40b74a629d1acdcb239f70a44e587 100644 (file)
 
 #include "common/errno.h"
 #include "common/signal.h"
+#include "common/cmdparse.h"
 #include "include/compat.h"
+#include "include/str_list.h"
+#include "perfglue/heap_profiler.h"
 
 #include "include/stringify.h"
 #include "global/global_context.h"
@@ -42,6 +45,7 @@ using std::map;
 using std::string;
 using std::vector;
 using namespace std::literals;
+using ceph::common::cmd_getval;
 
 class MgrHook : public AdminSocketHook {
   MgrStandby* mgr;
@@ -55,7 +59,7 @@ public:
            bufferlist& outbl) override {
     int r = 0;
     try {
-      r = mgr->asok_command(admin_command, cmdmap, f, errss);
+      r = mgr->asok_command(admin_command, cmdmap, f, errss, outbl);
     } catch (const TOPNSPC::common::bad_cmd_get& e) {
       errss << e.what();
       r = -EINVAL;
@@ -141,13 +145,32 @@ void MgrStandby::handle_conf_change(
   }
 }
 
-int MgrStandby::asok_command(std::string_view cmd, const cmdmap_t& cmdmap, Formatter* f, std::ostream& errss)
+int MgrStandby::asok_command(std::string_view cmd, const cmdmap_t& cmdmap,
+                            Formatter* f, std::ostream& errss,
+                            ceph::buffer::list& outbl)
 {
   dout(10) << __func__ << ": " << cmd << dendl;
   if (cmd == "status") {
     f->open_object_section("status");
     f->close_section();
     return 0;
+  } else if (cmd == "heap") {
+    if (!ceph_using_tcmalloc()) {
+      errss << "could not issue heap profiler command -- not using tcmalloc!";
+      return -EOPNOTSUPP;
+    }
+    std::string heapcmd;
+    cmd_getval(cmdmap, "heapcmd", heapcmd);
+    std::vector<std::string> cmd_vec;
+    get_str_vec(heapcmd, cmd_vec);
+    std::string val;
+    if (cmd_getval(cmdmap, "value", val)) {
+      cmd_vec.push_back(val);
+    }
+    std::ostringstream outss;
+    ceph_heap_profiler_handle_command(cmd_vec, outss);
+    outbl.append(outss.str());
+    return 0;
   } else {
     return -ENOSYS;
   }
@@ -182,6 +205,14 @@ int MgrStandby::init()
   {
     int r = admin_socket->register_command("status", asok_hook.get(), "show status");
     ceph_assert(r == 0);
+    r = admin_socket->register_command(
+      "heap " \
+      "name=heapcmd,type=CephChoices,strings=" \
+      "dump|start_profiler|stop_profiler|release|get_release_rate|set_release_rate|stats " \
+      "name=value,type=CephString,req=false",
+      asok_hook.get(),
+      "show heap usage info (available only if compiled with tcmalloc)");
+    ceph_assert(r == 0);
   }
 
   poolctx.start(2);
index 32a277f4a2b82c119a8cebedd08c27034ad398de..2bcd32f76688f15425756d994c945ec244d7f817 100644 (file)
@@ -39,7 +39,8 @@ public:
   std::vector<std::string> get_tracked_keys() const noexcept override;
   void handle_conf_change(const ConfigProxy& conf,
                          const std::set <std::string> &changed) override;
-  int asok_command(std::string_view cmd, const cmdmap_t& cmdmap, Formatter* f, std::ostream& errss);
+  int asok_command(std::string_view cmd, const cmdmap_t& cmdmap, Formatter* f,
+                  std::ostream& errss, ceph::buffer::list& outbl);
 
 protected:
   ceph::async::io_context_pool poolctx;