From: Kefu Chai Date: Tue, 30 Jun 2026 01:29:18 +0000 (+0800) Subject: mgr: add heap admin socket command X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d8dde402b6dae6b6ebe0ee765bb83b25b0443271;p=ceph.git mgr: add heap admin socket command 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. 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 --- diff --git a/src/mgr/MgrStandby.cc b/src/mgr/MgrStandby.cc index 70db2135966..8209d4f8b4c 100644 --- a/src/mgr/MgrStandby.cc +++ b/src/mgr/MgrStandby.cc @@ -17,7 +17,10 @@ #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 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); diff --git a/src/mgr/MgrStandby.h b/src/mgr/MgrStandby.h index 32a277f4a2b..2bcd32f7668 100644 --- a/src/mgr/MgrStandby.h +++ b/src/mgr/MgrStandby.h @@ -39,7 +39,8 @@ public: std::vector get_tracked_keys() const noexcept override; void handle_conf_change(const ConfigProxy& conf, const std::set &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;