diff options
author | Matus Fabian <matfabia@cisco.com> | 2024-07-19 15:40:59 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-07-22 15:50:22 +0000 |
commit | 7561c45bcce4913620388a60be36dc1284d484a0 (patch) | |
tree | f028f1572a2460d0e35675f02f7551a0f5202a28 | |
parent | ef827b3efc5270d4772cf8482b0b08ef7fbbf8c5 (diff) |
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>
-rw-r--r-- | src/vlib/cli.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/src/vlib/cli.c b/src/vlib/cli.c index 98d57c6ccb0..4198b4b0976 100644 --- a/src/vlib/cli.c +++ b/src/vlib/cli.c @@ -43,6 +43,7 @@ #include <vppinfra/callback.h> #include <vppinfra/cpu.h> #include <vppinfra/elog.h> +#include <vppinfra/cJSON.h> #include <unistd.h> #include <ctype.h> @@ -1115,6 +1116,111 @@ VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = { }; 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 * restart_cmd_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { |