Skip to content

Commit

Permalink
new: usr: add a rndc command to toggle jemalloc profiling
Browse files Browse the repository at this point in the history
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.

Closes #4759

Merge branch '4759-add-a-trigger-to-dump-jeprof-data-or-memory-statistics' into 'main'

See merge request isc-projects/bind9!9370
  • Loading branch information
aydinmercan committed Jan 25, 2025
2 parents b9db917 + b495e99 commit 2bee113
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 0 deletions.
2 changes: 2 additions & 0 deletions bin/named/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,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)) {
Expand Down
1 change: 1 addition & 0 deletions bin/named/include/named/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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"
Expand Down
12 changes: 12 additions & 0 deletions bin/named/include/named/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,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);
172 changes: 172 additions & 0 deletions bin/named/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,15 @@
#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
Expand Down Expand Up @@ -358,6 +367,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.
*/
Expand Down Expand Up @@ -10058,6 +10083,39 @@ named_server_closelogswanted(void *arg, int signum) {
isc_async_run(named_g_mainloop, named_server_closelogs, 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_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
Expand Down Expand Up @@ -11930,6 +11988,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),
Expand Down Expand Up @@ -16140,3 +16202,113 @@ named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {

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_LOGCATEGORY_GENERAL,
NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
"failed to dump memory profile");

} else {
isc_log_write(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_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
ISC_LOG_ERROR,
"failed to toggle memory profiling");
} else {
isc_log_write(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 */
4 changes: 4 additions & 0 deletions bin/rndc/rndc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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\
Expand Down
13 changes: 13 additions & 0 deletions bin/rndc/rndc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,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
Expand Down

0 comments on commit 2bee113

Please sign in to comment.