]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: centralized memstats-at-exit
authorDavid Lamparter <equinox@opensourcerouting.org>
Wed, 23 Aug 2017 14:18:49 +0000 (16:18 +0200)
committerDavid Lamparter <equinox@opensourcerouting.org>
Wed, 23 Aug 2017 22:18:50 +0000 (00:18 +0200)
adds a new all-daemon "debug memstats-at-exit" command.  Also saves
memstats to a file in /tmp, useful if a long-running daemon is having
weird issues (e.g. in a user install).

Fixes: #437
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
bgpd/bgp_main.c
lib/command.c
lib/libfrr.c
lib/libfrr.h
lib/log.c
lib/memory.c
lib/memory.h
lib/sigevent.c
tests/isisd/test_fuzz_isis_tlv.c
tests/lib/cli/common_cli.c

index 3bf9ea02d501e7793e40d24b57ca10e88b37e17b..fa8c45b004a849e6e804fe7cd14ed53a2ac81518 100644 (file)
@@ -219,9 +219,6 @@ static __attribute__((__noreturn__)) void bgp_exit(int status)
        memset(bm, 0, sizeof(*bm));
 
        frr_fini();
-
-       if (bgp_debug_count())
-               log_memstats_stderr("bgpd");
        exit(status);
 }
 
index 45b5593a3e8c675c5368c1b102e6a8978559964b..f47bf81452c656e91542589b92173dbc46d6c013 100644 (file)
@@ -42,6 +42,7 @@
 #include "command_graph.h"
 #include "qobj.h"
 #include "defaults.h"
+#include "libfrr.h"
 
 DEFINE_MTYPE(LIB, HOST, "Host config")
 DEFINE_MTYPE(LIB, STRVEC, "String vector")
@@ -555,6 +556,9 @@ static int config_write_host(struct vty *vty)
        else if (!host.motd)
                vty_out(vty, "no banner motd\n");
 
+       if (debug_memstats_at_exit)
+               vty_out(vty, "!\ndebug memstats-at-exit\n");
+
        return 1;
 }
 
@@ -2366,6 +2370,17 @@ DEFUN (no_config_log_timestamp_precision,
        return CMD_SUCCESS;
 }
 
+DEFUN (debug_memstats,
+       debug_memstats_cmd,
+       "[no] debug memstats-at-exit",
+       NO_STR
+       DEBUG_STR
+       "Print memory type statistics at exit\n")
+{
+       debug_memstats_at_exit = !!strcmp(argv[0]->text, "no");
+       return CMD_SUCCESS;
+}
+
 int cmd_banner_motd_file(const char *file)
 {
        int success = CMD_SUCCESS;
@@ -2527,6 +2542,7 @@ void cmd_init(int terminal)
        /* Each node's basic commands. */
        install_element(VIEW_NODE, &show_version_cmd);
        install_element(ENABLE_NODE, &show_startup_config_cmd);
+       install_element(ENABLE_NODE, &debug_memstats_cmd);
 
        if (terminal) {
                install_element(VIEW_NODE, &config_list_cmd);
@@ -2560,6 +2576,7 @@ void cmd_init(int terminal)
        install_element(CONFIG_NODE, &hostname_cmd);
        install_element(CONFIG_NODE, &no_hostname_cmd);
        install_element(CONFIG_NODE, &frr_version_defaults_cmd);
+       install_element(CONFIG_NODE, &debug_memstats_cmd);
 
        if (terminal > 0) {
                install_element(CONFIG_NODE, &password_cmd);
index 255f91ec71f85564ded01ec90b29d054c7fdd783..c3ef04c673a50760f524d00fb9275ad509fc343f 100644 (file)
@@ -52,6 +52,8 @@ char frr_zclientpath[256];
 static char pidfile_default[256];
 static char vtypath_default[256];
 
+bool debug_memstats_at_exit = 0;
+
 static char comb_optstr[256];
 static struct option comb_lo[64];
 static struct option *comb_next_lo = &comb_lo[0];
@@ -841,6 +843,10 @@ void frr_early_fini(void)
 
 void frr_fini(void)
 {
+       FILE *fp;
+       char filename[128];
+       int have_leftovers;
+
        hook_call(frr_fini);
 
        /* memory_init -> nothing needed */
@@ -851,4 +857,28 @@ void frr_fini(void)
        thread_master_free(master);
        closezlog();
        /* frrmod_init -> nothing needed / hooks */
+
+       if (!debug_memstats_at_exit)
+               return;
+
+       have_leftovers = log_memstats(stderr, di->name);
+
+       /* in case we decide at runtime that we want exit-memstats for
+        * a daemon, but it has no stderr because it's daemonized
+        * (only do this if we actually have something to print though)
+        */
+       if (!have_leftovers)
+               return;
+
+       snprintf(filename, sizeof(filename),
+                "/tmp/frr-memstats-%s-%llu-%llu",
+                di->name,
+                (unsigned long long)getpid(),
+                (unsigned long long)time(NULL));
+
+       fp = fopen(filename, "w");
+       if (fp) {
+               log_memstats(fp, di->name);
+               fclose(fp);
+       }
 }
index 8a15d168a1722290d39693b54798833036bca57d..f7d69eecb3fbe004f8df52210fdc64d68cb5f0cb 100644 (file)
@@ -121,4 +121,6 @@ extern const char frr_moduledir[];
 extern char frr_protoname[];
 extern char frr_protonameinst[];
 
+extern bool debug_memstats_at_exit;
+
 #endif /* _ZEBRA_FRR_H */
index 5c89e7080eafaef5b5955b2374028f20567a8228..5b2429b31a9f39d8d7858a8dcee0d5605ada4651 100644 (file)
--- a/lib/log.c
+++ b/lib/log.c
@@ -701,7 +701,7 @@ void _zlog_assert_failed(const char *assertion, const char *file,
             assertion, file, line, (function ? function : "?"));
        zlog_backtrace(LOG_CRIT);
        zlog_thread_info(LOG_CRIT);
-       log_memstats_stderr("log");
+       log_memstats(stderr, "log");
        abort();
 }
 
index 0ccc2040023c26d71453a2270d75280743971bc6..c684c7605c00b9063b9390fbc45adb89ecb41e49 100644 (file)
@@ -104,6 +104,7 @@ int qmem_walk(qmem_walk_fn *func, void *arg)
 }
 
 struct exit_dump_args {
+       FILE *fp;
        const char *prefix;
        int error;
 };
@@ -113,7 +114,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
        struct exit_dump_args *eda = arg;
 
        if (!mt) {
-               fprintf(stderr,
+               fprintf(eda->fp,
                        "%s: showing active allocations in "
                        "memory group %s\n",
                        eda->prefix, mg->name);
@@ -122,15 +123,16 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt)
                char size[32];
                eda->error++;
                snprintf(size, sizeof(size), "%10zu", mt->size);
-               fprintf(stderr, "%s: memstats:  %-30s: %6zu * %s\n",
+               fprintf(eda->fp, "%s: memstats:  %-30s: %6zu * %s\n",
                        eda->prefix, mt->name, mt->n_alloc,
                        mt->size == SIZE_VAR ? "(variably sized)" : size);
        }
        return 0;
 }
 
-void log_memstats_stderr(const char *prefix)
+int log_memstats(FILE *fp, const char *prefix)
 {
-       struct exit_dump_args eda = {.prefix = prefix, .error = 0};
+       struct exit_dump_args eda = { .fp = fp, .prefix = prefix, .error = 0 };
        qmem_walk(qmem_exit_walker, &eda);
+       return eda.error;
 }
index d5facad583363030caf0f641bd0f4fec48e2ed5c..132d4abd3035336a9cdcb26e196534b225ee666a 100644 (file)
@@ -18,6 +18,7 @@
 #define _QUAGGA_MEMORY_H
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <frratomic.h>
 
 #define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
@@ -194,7 +195,8 @@ static inline size_t mtype_stats_alloc(struct memtype *mt)
  * last value from qmem_walk_fn. */
 typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt);
 extern int qmem_walk(qmem_walk_fn *func, void *arg);
-extern void log_memstats_stderr(const char *);
+extern int log_memstats(FILE *fp, const char *);
+#define log_memstats_stderr(prefix) log_memstats(stderr, prefix)
 
 extern void memory_oom(size_t size, const char *name);
 
index 2a04fa23cb793f00fab46b7f05a5a97a221f47a8..d55f368dfb7f4cf0763d43a10dce400bab7d3d2a 100644 (file)
@@ -245,7 +245,7 @@ core_handler(int signo
 #endif
                            );
        /* dump memory stats on core */
-       log_memstats_stderr("core_handler");
+       log_memstats(stderr, "core_handler");
        abort();
 }
 
index 6727e663f544e466c6596d4fe02a7fd2e1f37aae..e61e9639ee94d2b7fb4029c0f1aa5bf0e0f5d731 100644 (file)
@@ -23,7 +23,7 @@ static bool atexit_registered;
 
 static void show_meminfo_at_exit(void)
 {
-       log_memstats_stderr("isis fuzztest");
+       log_memstats(stderr, "isis fuzztest");
 }
 
 static int comp_line(const void *p1, const void *p2)
index 77f1610fe23ba16b09ac362704b038482a087399..0fd2f80a39b5b12878588868a672e368270b0cb5 100644 (file)
@@ -53,7 +53,7 @@ static void vty_do_exit(int isexit)
        thread_master_free(master);
        closezlog();
 
-       log_memstats_stderr("testcli");
+       log_memstats(stderr, "testcli");
        if (!isexit)
                exit(0);
 }