memset(bm, 0, sizeof(*bm));
frr_fini();
-
- if (bgp_debug_count())
- log_memstats_stderr("bgpd");
exit(status);
}
#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")
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;
}
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;
/* 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);
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);
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];
void frr_fini(void)
{
+ FILE *fp;
+ char filename[128];
+ int have_leftovers;
+
hook_call(frr_fini);
/* memory_init -> nothing needed */
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);
+ }
}
extern char frr_protoname[];
extern char frr_protonameinst[];
+extern bool debug_memstats_at_exit;
+
#endif /* _ZEBRA_FRR_H */
assertion, file, line, (function ? function : "?"));
zlog_backtrace(LOG_CRIT);
zlog_thread_info(LOG_CRIT);
- log_memstats_stderr("log");
+ log_memstats(stderr, "log");
abort();
}
}
struct exit_dump_args {
+ FILE *fp;
const char *prefix;
int error;
};
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);
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;
}
#define _QUAGGA_MEMORY_H
#include <stdlib.h>
+#include <stdio.h>
#include <frratomic.h>
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
* 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);
#endif
);
/* dump memory stats on core */
- log_memstats_stderr("core_handler");
+ log_memstats(stderr, "core_handler");
abort();
}
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)
thread_master_free(master);
closezlog();
- log_memstats_stderr("testcli");
+ log_memstats(stderr, "testcli");
if (!isexit)
exit(0);
}