vlib: add "save memory-trace" debug CLI
Save memory traces of the currently traced heap in JSON format to file which can be used as machine-readable data for memory leak diagnose. Type: improvement Change-Id: I277f5be5838510e907c4dd7a8a4e9a883cb67bc3 Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:

committed by
Florin Coras

parent
ef827b3efc
commit
7561c45bcc
106
src/vlib/cli.c
106
src/vlib/cli.c
@ -43,6 +43,7 @@
|
|||||||
#include <vppinfra/callback.h>
|
#include <vppinfra/callback.h>
|
||||||
#include <vppinfra/cpu.h>
|
#include <vppinfra/cpu.h>
|
||||||
#include <vppinfra/elog.h>
|
#include <vppinfra/elog.h>
|
||||||
|
#include <vppinfra/cJSON.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@ -1114,6 +1115,111 @@ VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = {
|
|||||||
.function = enable_disable_memory_trace,
|
.function = enable_disable_memory_trace,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static clib_error_t *
|
||||||
|
save_memory_trace (vlib_main_t *vm, unformat_input_t *input,
|
||||||
|
vlib_cli_command_t *cmd)
|
||||||
|
{
|
||||||
|
char *file, *chroot_file;
|
||||||
|
uword was_enabled;
|
||||||
|
mheap_trace_t *t, *mem_traces = 0;
|
||||||
|
u8 *tmp;
|
||||||
|
cJSON *traces, *trace, *traceback, *symbol;
|
||||||
|
int i;
|
||||||
|
FILE *fp;
|
||||||
|
char *json_str = 0;
|
||||||
|
|
||||||
|
cJSON_Hooks cjson_hooks = {
|
||||||
|
.malloc_fn = clib_mem_alloc,
|
||||||
|
.free_fn = clib_mem_free,
|
||||||
|
.realloc_fn = clib_mem_realloc,
|
||||||
|
};
|
||||||
|
cJSON_InitHooks (&cjson_hooks);
|
||||||
|
|
||||||
|
if (!unformat (input, "%s", &file))
|
||||||
|
{
|
||||||
|
vlib_cli_output (vm, "expected file name, got `%U'",
|
||||||
|
format_unformat_error, input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It's fairly hard to get "../oopsie" through unformat; just in case */
|
||||||
|
if (strstr (file, "..") || strchr (file, '/'))
|
||||||
|
{
|
||||||
|
vlib_cli_output (vm, "illegal characters in filename '%s'", file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
chroot_file = (char *) format (0, "/tmp/%s%c", file, 0);
|
||||||
|
vec_free (file);
|
||||||
|
fp = fopen ((char *) chroot_file, "w");
|
||||||
|
if (fp == NULL)
|
||||||
|
{
|
||||||
|
vlib_cli_output (vm, "couldn't open output file %s '%s'", chroot_file);
|
||||||
|
vec_free (chroot_file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
was_enabled = clib_mem_trace_enable_disable (0);
|
||||||
|
vlib_cli_output (vm, "Saving trace to '%s'", chroot_file);
|
||||||
|
mem_traces = clib_mem_trace_dup (current_traced_heap);
|
||||||
|
traces = cJSON_CreateArray ();
|
||||||
|
vec_foreach (t, mem_traces)
|
||||||
|
{
|
||||||
|
/* Skip over free elements. */
|
||||||
|
if (t->n_allocations == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
trace = cJSON_CreateObject ();
|
||||||
|
cJSON_AddNumberToObject (trace, "count", t->n_allocations);
|
||||||
|
cJSON_AddNumberToObject (trace, "bytes", t->n_bytes);
|
||||||
|
tmp = format (0, "%p%c", t->offset, 0);
|
||||||
|
cJSON_AddStringToObject (trace, "sample", (char *) tmp);
|
||||||
|
vec_free (tmp);
|
||||||
|
traceback = cJSON_AddArrayToObject (trace, "traceback");
|
||||||
|
for (i = 0; i < ARRAY_LEN (t->callers) && t->callers[i]; i++)
|
||||||
|
{
|
||||||
|
#if defined(CLIB_UNIX) && !defined(__APPLE__)
|
||||||
|
tmp = format (0, "%U%c\n", format_clib_elf_symbol_with_address,
|
||||||
|
t->callers[i], 0);
|
||||||
|
symbol = cJSON_CreateString ((char *) tmp);
|
||||||
|
cJSON_AddItemToArray (traceback, symbol);
|
||||||
|
vec_free (tmp);
|
||||||
|
#else
|
||||||
|
tmp = format (0, "%p%c\n", t->callers[i], 0);
|
||||||
|
symbol = cJSON_CreateString ((char *) tmp);
|
||||||
|
cJSON_AddItemToArray (traceback, symbol);
|
||||||
|
vec_free (tmp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_AddItemToArray (traces, trace);
|
||||||
|
}
|
||||||
|
json_str = cJSON_PrintUnformatted (traces);
|
||||||
|
cJSON_Delete (traces);
|
||||||
|
fputs (json_str, fp);
|
||||||
|
fclose (fp);
|
||||||
|
clib_mem_free (json_str);
|
||||||
|
|
||||||
|
vec_free (mem_traces);
|
||||||
|
clib_mem_trace_enable_disable (was_enabled);
|
||||||
|
|
||||||
|
vec_free (chroot_file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*?
|
||||||
|
* Save memory traces of the currently traced heap in JSON format to file.
|
||||||
|
* Only filename can be specified, path is fixed (/tmp/<filename>).
|
||||||
|
*
|
||||||
|
* @cliexpar
|
||||||
|
* @cliexcmd{save memory-trace mem_trace.json}
|
||||||
|
?*/
|
||||||
|
VLIB_CLI_COMMAND (save_memory_trace_command, static) = {
|
||||||
|
.path = "save memory-trace",
|
||||||
|
.short_help = "save memory-trace <filename>",
|
||||||
|
.function = save_memory_trace,
|
||||||
|
};
|
||||||
|
|
||||||
static clib_error_t *
|
static clib_error_t *
|
||||||
restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
|
restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input,
|
||||||
vlib_cli_command_t * cmd)
|
vlib_cli_command_t * cmd)
|
||||||
|
Reference in New Issue
Block a user