]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add a rndc command to toggle jemalloc profiling
authorAydın Mercan <aydin@isc.org>
Mon, 12 Aug 2024 15:17:05 +0000 (18:17 +0300)
committerNicki Křížek <nicki@isc.org>
Wed, 5 Feb 2025 09:40:05 +0000 (10:40 +0100)
The new command is `rndc memprof`. The memory profiling status is also
reported inside `rndc status`. The status also shows whether named can
toggle memory profiling or not and if the server is built with jemalloc.

(cherry picked from commit b495e9918eaf8f7546d6c51891aa8817b760ffa7)

bin/named/control.c
bin/named/include/named/control.h
bin/named/include/named/server.h
bin/named/server.c
bin/rndc/rndc.c
bin/rndc/rndc.rst

index 4f7ea425fdb66ec87a7cbb1693f6c1bd0f818278..36cd47c22f12d567a4c5fb56f3ac4c6666e3c382 100644 (file)
@@ -229,6 +229,8 @@ named_control_docommand(isccc_sexpr_t *message, bool readonly,
                   command_compare(command, NAMED_COMMAND_SIGN))
        {
                result = named_server_rekey(named_g_server, lex, text);
+       } else if (command_compare(command, NAMED_COMMAND_MEMPROF)) {
+               result = named_server_togglememprof(lex);
        } else if (command_compare(command, NAMED_COMMAND_MKEYS)) {
                result = named_server_mkeys(named_g_server, lex, text);
        } else if (command_compare(command, NAMED_COMMAND_NOTIFY)) {
index 102e4ce17feb8718a1338e583ad7baa5dd9df353..18bac081263f1d931e841d7153fc0906121aa595 100644 (file)
@@ -42,6 +42,7 @@
 #define NAMED_COMMAND_FREEZE      "freeze"
 #define NAMED_COMMAND_HALT        "halt"
 #define NAMED_COMMAND_LOADKEYS    "loadkeys"
+#define NAMED_COMMAND_MEMPROF     "memprof"
 #define NAMED_COMMAND_MKEYS       "managed-keys"
 #define NAMED_COMMAND_MODZONE     "modzone"
 #define NAMED_COMMAND_NOTIFY      "notify"
index 01dc22b50db8ddcebff6f95930bd225a67eca1fa..72597cd1aeacbda545a33361d6d0925a556ef01b 100644 (file)
@@ -391,3 +391,15 @@ named_server_fetchlimit(named_server_t *server, isc_lex_t *lex,
  */
 isc_result_t
 named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text);
+
+/*%
+ * Toggle memory profiling if supported.
+ */
+isc_result_t
+named_server_togglememprof(isc_lex_t *lex);
+
+/*%
+ * Get status of memory profiling.
+ */
+const char *
+named_server_getmemprof(void);
index a24929a49bbf65a4300d03fc61e90f3ad1e90508..1782d0261940433957ffb0c81853325f0112a2ab 100644 (file)
 #include <named/smf_globals.h>
 #endif /* ifdef HAVE_LIBSCF */
 
+/* On DragonFly BSD the header does not provide jemalloc API */
+#if defined(HAVE_MALLOC_NP_H) && !defined(__DragonFly__)
+#include <malloc_np.h>
+#define JEMALLOC_API_SUPPORTED 1
+#elif defined(HAVE_JEMALLOC)
+#include <jemalloc/jemalloc.h>
+#define JEMALLOC_API_SUPPORTED 1
+#endif
+
 #ifdef HAVE_LMDB
 #include <lmdb.h>
 #define configure_newzones configure_newzones_db
@@ -360,6 +369,22 @@ typedef struct {
        isc_result_t result;
 } ns_dzarg_t;
 
+typedef enum {
+       MEMPROF_UNSUPPORTED = 0x00,
+       MEMPROF_INACTIVE = 0x01,
+       MEMPROF_FAILING = 0x02,
+       MEMPROF_OFF = 0x03,
+       MEMPROF_ON = 0x04,
+} memprof_status;
+
+static const char *memprof_status_text[] = {
+       [MEMPROF_UNSUPPORTED] = "UNSUPPORTED",
+       [MEMPROF_INACTIVE] = "INACTIVE",
+       [MEMPROF_FAILING] = "FAILING",
+       [MEMPROF_OFF] = "OFF",
+       [MEMPROF_ON] = "ON",
+};
+
 /*
  * These zones should not leak onto the Internet.
  */
@@ -10715,6 +10740,39 @@ named_server_reloadwanted(void *arg, int signum) {
        isc_async_run(named_g_mainloop, named_server_reload, server);
 }
 
+#ifdef JEMALLOC_API_SUPPORTED
+static isc_result_t
+memprof_toggle(bool active) {
+       if (mallctl("prof.active", NULL, NULL, &active, sizeof(active)) != 0) {
+               return ISC_R_FAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+
+static isc_result_t
+memprof_dump(void) {
+       if (mallctl("prof.dump", NULL, NULL, NULL, 0) != 0) {
+               return ISC_R_FAILURE;
+       }
+
+       return ISC_R_SUCCESS;
+}
+#else
+static isc_result_t
+memprof_toggle(bool active) {
+       UNUSED(active);
+
+       return ISC_R_NOTIMPLEMENTED;
+}
+
+static isc_result_t
+memprof_dump(void) {
+       return ISC_R_NOTIMPLEMENTED;
+}
+
+#endif /* JEMALLOC_API_SUPPORTED */
+
 void
 named_server_scan_interfaces(named_server_t *server) {
        isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
@@ -12598,6 +12656,10 @@ named_server_status(named_server_t *server, isc_buffer_t **text) {
                         : "OFF");
        CHECK(putstr(text, line));
 
+       snprintf(line, sizeof(line), "memory profiling is %s\n",
+                named_server_getmemprof());
+       CHECK(putstr(text, line));
+
        snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
                 isc_quota_getused(&server->sctx->recursionquota),
                 isc_quota_getsoft(&server->sctx->recursionquota),
@@ -16821,3 +16883,114 @@ cleanup:
 
        return result;
 }
+
+isc_result_t
+named_server_togglememprof(isc_lex_t *lex) {
+       isc_result_t result = ISC_R_FAILURE;
+       bool active;
+       char *ptr;
+
+       /* Skip the command name. */
+       ptr = next_token(lex, NULL);
+       if (ptr == NULL) {
+               return ISC_R_UNEXPECTEDEND;
+       }
+
+       ptr = next_token(lex, NULL);
+       if (ptr == NULL) {
+               return ISC_R_UNEXPECTEDEND;
+       } else if (!strcasecmp(ptr, "dump")) {
+               result = memprof_dump();
+               if (result != ISC_R_SUCCESS) {
+                       isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+                                     NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+                                     "failed to dump memory profile");
+
+               } else {
+                       isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+                                     NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
+                                     "memory profile dumped");
+               }
+
+               goto done;
+       } else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
+                  !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true"))
+       {
+               active = true;
+       } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
+                  !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false"))
+       {
+               active = false;
+       } else {
+               return DNS_R_SYNTAX;
+       }
+
+       result = memprof_toggle(active);
+       if (result != ISC_R_SUCCESS) {
+               isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+                             NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
+                             "failed to toggle memory profiling");
+       } else {
+               isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
+                             NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
+                             "memory profiling %s",
+                             active ? "enabled" : "disabled");
+       }
+
+done:
+       return result;
+}
+
+#ifdef JEMALLOC_API_SUPPORTED
+const char *
+named_server_getmemprof(void) {
+       memprof_status status = MEMPROF_ON;
+       bool is_enabled;
+       size_t len = sizeof(is_enabled);
+
+       if (mallctl("config.prof", &is_enabled, &len, NULL, 0) != 0) {
+               status = MEMPROF_FAILING;
+               goto done;
+       }
+
+       INSIST(len == sizeof(is_enabled));
+
+       if (!is_enabled) {
+               status = MEMPROF_UNSUPPORTED;
+               goto done;
+       }
+
+       if (mallctl("opt.prof", &is_enabled, &len, NULL, 0) != 0) {
+               status = MEMPROF_FAILING;
+               goto done;
+       }
+
+       INSIST(len == sizeof(is_enabled));
+
+       if (!is_enabled) {
+               status = MEMPROF_INACTIVE;
+               goto done;
+       }
+
+       len = sizeof(is_enabled);
+       if (mallctl("prof.active", &is_enabled, &len, NULL, 0) != 0) {
+               status = MEMPROF_FAILING;
+               goto done;
+       }
+
+       INSIST(len == sizeof(is_enabled));
+
+       if (!is_enabled) {
+               status = MEMPROF_OFF;
+       }
+
+done:
+       return memprof_status_text[status];
+}
+
+#else  /* JEMALLOC_API_SUPPORTED */
+const char *
+named_server_getmemprof(void) {
+       return memprof_status_text[MEMPROF_UNSUPPORTED];
+}
+#endif /* JEMALLOC_API_SUPPORTED */
index b9350a25eccdd0ea7ac1c5d72eb17001b2dd1947..caa55c66a06b70a123d99c34eaefcc0e9d89e387 100644 (file)
@@ -143,6 +143,10 @@ command is one of the following:\n\
                Display RFC 5011 managed keys information\n\
   managed-keys sync [class [view]]\n\
                Write RFC 5011 managed keys to disk\n\
+  memprof [ on | off | dump ]\n\
+               Enable / disable memory profiling or dump the profile.\n\
+               Requires named to built with jemalloc and run with the relevant\n\
+               MALLOC_CONF environment variables.\n\
   modzone zone [class [view]] { zone-options }\n\
                Modify a zone's configuration.\n\
                Requires allow-new-zones option.\n\
index 1afc89693de757ab0471faeef57dab47a512956a..696ad79bffbb3c53174389b4eb193f1251799e56 100644 (file)
@@ -313,6 +313,19 @@ Currently supported commands are:
       keys in the event of a trust anchor rollover, or as a brute-force
       repair for key maintenance problems.
 
+.. option:: memprof [(on | off | dump)]
+
+   This command controls memory profiling. To have any effect, :iscman:`named` must be
+   built with jemalloc, the library have profiling support enabled and run with the
+   ``prof:true`` allocator configuration. (either via ``MALLOC_CONF`` or ``/etc/malloc.conf``)
+
+   The ``prof_active:false`` option is recommended to ensure the profiling overhead does
+   not affect :iscman:`named` when not needed.
+
+   The ``on`` and ``off`` options will start and stop the jemalloc memory profiling respectively.
+   When run with the `dump` option, :iscman:`named` will dump the profile to the working
+   directory. The name will be chosen automatically by jemalloc.
+
 .. option:: modzone zone [class [view]] configuration
 
    This command modifies the configuration of a zone while the server is running. This