X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlib%2Fcli.c;h=131a5931ac2ad5b12ca230306999c666b0a215fb;hb=c4abafd83;hp=ef02d27d2887d6c5d53ba8390a27ed5ec4b95388;hpb=af7dd5b32eca5c924695637bd3b922e6793b1d8a;p=vpp.git diff --git a/src/vlib/cli.c b/src/vlib/cli.c index ef02d27d288..131a5931ac2 100644 --- a/src/vlib/cli.c +++ b/src/vlib/cli.c @@ -40,9 +40,15 @@ #include #include #include +#include #include #include +int vl_api_set_elog_trace_api_messages (int enable); +int vl_api_get_elog_trace_api_messages (void); + +static void *current_traced_heap; + /* Root of all show commands. */ /* *INDENT-OFF* */ VLIB_CLI_COMMAND (vlib_cli_show_command, static) = { @@ -551,6 +557,39 @@ vlib_cli_dispatch_sub_commands (vlib_main_t * vm, parent_command_index); unformat_free (&sub_input); } + else if (unformat (input, "leak-check %U", + unformat_vlib_cli_sub_input, &sub_input)) + { + u8 *leak_report; + if (current_traced_heap) + { + void *oldheap; + oldheap = clib_mem_set_heap (current_traced_heap); + clib_mem_trace (0); + clib_mem_set_heap (oldheap); + current_traced_heap = 0; + } + clib_mem_trace (1); + error = + vlib_cli_dispatch_sub_commands (vm, cm, &sub_input, + parent_command_index); + unformat_free (&sub_input); + + /* Otherwise, the clib_error_t shows up as a leak... */ + if (error) + { + vlib_cli_output (vm, "%v", error->what); + clib_error_free (error); + error = 0; + } + + (void) clib_mem_trace_enable_disable (0); + leak_report = format (0, "%U", format_mheap, clib_mem_get_heap (), + 1 /* verbose, i.e. print leaks */ ); + clib_mem_trace (0); + vlib_cli_output (vm, "%v", leak_report); + vec_free (leak_report); + } else if (unformat_user (input, unformat_vlib_cli_sub_command, vm, parent, &c)) @@ -583,6 +622,23 @@ vlib_cli_dispatch_sub_commands (vlib_main_t * vm, } else { + if (PREDICT_FALSE (vm->elog_trace_cli_commands)) + { + /* *INDENT-OFF* */ + ELOG_TYPE_DECLARE (e) = + { + .format = "cli-cmd: %s", + .format_args = "T4", + }; + /* *INDENT-ON* */ + struct + { + u32 c; + } *ed; + ed = ELOG_DATA (&vm->elog_main, e); + ed->c = elog_string (&vm->elog_main, c->path); + } + if (!c->is_mp_safe) vlib_worker_thread_barrier_sync (vm); @@ -591,6 +647,32 @@ vlib_cli_dispatch_sub_commands (vlib_main_t * vm, if (!c->is_mp_safe) vlib_worker_thread_barrier_release (vm); + if (PREDICT_FALSE (vm->elog_trace_cli_commands)) + { + /* *INDENT-OFF* */ + ELOG_TYPE_DECLARE (e) = + { + .format = "cli-cmd: %s %s", + .format_args = "T4T4", + }; + /* *INDENT-ON* */ + struct + { + u32 c, err; + } *ed; + ed = ELOG_DATA (&vm->elog_main, e); + ed->c = elog_string (&vm->elog_main, c->path); + if (c_error) + { + vec_add1 (c_error->what, 0); + ed->err = elog_string (&vm->elog_main, + (char *) c_error->what); + _vec_len (c_error->what) -= 1; + } + else + ed->err = elog_string (&vm->elog_main, "OK"); + } + if (c_error) { error = @@ -640,7 +722,7 @@ vlib_unix_error_report (vlib_main_t * vm, clib_error_t * error) } /* Process CLI input. */ -void +int vlib_cli_input (vlib_main_t * vm, unformat_input_t * input, vlib_cli_output_function_t * function, uword function_arg) @@ -650,6 +732,7 @@ vlib_cli_input (vlib_main_t * vm, clib_error_t *error; vlib_cli_output_function_t *save_function; uword save_function_arg; + int rv = 0; save_function = cp->output_function; save_function_arg = cp->output_function_arg; @@ -669,11 +752,15 @@ vlib_cli_input (vlib_main_t * vm, { vlib_cli_output (vm, "%v", error->what); vlib_unix_error_report (vm, error); + /* clib_error_return is unfortunately often called with a '0' + return code */ + rv = error->code != 0 ? error->code : -1; clib_error_free (error); } cp->output_function = save_function; cp->output_function_arg = save_function_arg; + return rv; } /* Output to current CLI connection. */ @@ -701,15 +788,36 @@ vlib_cli_output (vlib_main_t * vm, char *fmt, ...) } void *vl_msg_push_heap (void) __attribute__ ((weak)); +void * +vl_msg_push_heap (void) +{ + return 0; +} + void vl_msg_pop_heap (void *oldheap) __attribute__ ((weak)); +void +vl_msg_pop_heap (void *oldheap) +{ +} + +void *vlib_stats_push_heap (void *) __attribute__ ((weak)); +void * +vlib_stats_push_heap (void *notused) +{ + return 0; +} static clib_error_t * show_memory_usage (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - int verbose __attribute__ ((unused)) = 0, api_segment = 0; + int verbose __attribute__ ((unused)) = 0; + int api_segment = 0, stats_segment = 0, main_heap = 0; clib_error_t *error; u32 index = 0; + uword clib_mem_trace_enable_disable (uword enable); + uword was_enabled; + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -717,6 +825,10 @@ show_memory_usage (vlib_main_t * vm, verbose = 1; else if (unformat (input, "api-segment")) api_segment = 1; + else if (unformat (input, "stats-segment")) + stats_segment = 1; + else if (unformat (input, "main-heap")) + main_heap = 1; else { error = clib_error_return (0, "unknown input `%U'", @@ -725,9 +837,14 @@ show_memory_usage (vlib_main_t * vm, } } + if ((api_segment + stats_segment + main_heap) == 0) + return clib_error_return + (0, "Please supply one of api-segment, stats-segment or main-heap"); + if (api_segment) { void *oldheap = vl_msg_push_heap (); + was_enabled = clib_mem_trace_enable_disable (0); u8 *s_in_svm = format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1); vl_msg_pop_heap (oldheap); @@ -735,10 +852,31 @@ show_memory_usage (vlib_main_t * vm, oldheap = vl_msg_push_heap (); vec_free (s_in_svm); + clib_mem_trace_enable_disable (was_enabled); vl_msg_pop_heap (oldheap); - vlib_cli_output (vm, "API segment start:"); + vlib_cli_output (vm, "API segment"); + vlib_cli_output (vm, "%v", s); + vec_free (s); + } + if (stats_segment) + { + void *oldheap = vlib_stats_push_heap (0); + was_enabled = clib_mem_trace_enable_disable (0); + u8 *s_in_svm = + format (0, "%U\n", format_mheap, clib_mem_get_heap (), 1); + if (oldheap) + clib_mem_set_heap (oldheap); + u8 *s = vec_dup (s_in_svm); + + oldheap = vlib_stats_push_heap (0); + vec_free (s_in_svm); + if (oldheap) + { + clib_mem_trace_enable_disable (was_enabled); + clib_mem_set_heap (oldheap); + } + vlib_cli_output (vm, "Stats segment"); vlib_cli_output (vm, "%v", s); - vlib_cli_output (vm, "API segment end:"); vec_free (s); } @@ -759,36 +897,37 @@ show_memory_usage (vlib_main_t * vm, /* *INDENT-ON* */ #else { - uword clib_mem_trace_enable_disable (uword enable); - uword was_enabled; - - /* - * Note: the foreach_vlib_main cause allocator traffic, - * so shut off tracing before we go there... - */ - was_enabled = clib_mem_trace_enable_disable (0); - - /* *INDENT-OFF* */ - foreach_vlib_main ( - ({ - struct dlmallinfo mi; - void *mspace; - mspace = clib_per_cpu_mheaps[index]; + if (main_heap) + { + /* + * Note: the foreach_vlib_main causes allocator traffic, + * so shut off tracing before we go there... + */ + was_enabled = clib_mem_trace_enable_disable (0); - mi = mspace_mallinfo (mspace); - vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index, - vlib_worker_threads[index].name); - vlib_cli_output (vm, " %U\n", format_page_map, - pointer_to_uword (mspace_least_addr(mspace)), - mi.arena); - vlib_cli_output (vm, " %U\n", format_mheap, clib_per_cpu_mheaps[index], - verbose); - index++; - })); - /* *INDENT-ON* */ + /* *INDENT-OFF* */ + foreach_vlib_main ( + ({ + struct dlmallinfo mi; + void *mspace; + mspace = clib_per_cpu_mheaps[index]; + + mi = mspace_mallinfo (mspace); + vlib_cli_output (vm, "%sThread %d %s\n", index ? "\n":"", index, + vlib_worker_threads[index].name); + vlib_cli_output (vm, " %U\n", format_page_map, + pointer_to_uword (mspace_least_addr(mspace)), + mi.arena); + vlib_cli_output (vm, " %U\n", format_mheap, + clib_per_cpu_mheaps[index], + verbose); + index++; + })); + /* *INDENT-ON* */ - /* Restore the trace flag */ - clib_mem_trace_enable_disable (was_enabled); + /* Restore the trace flag */ + clib_mem_trace_enable_disable (was_enabled); + } } #endif /* USE_DLMALLOC */ return 0; @@ -797,7 +936,7 @@ show_memory_usage (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_memory_usage_command, static) = { .path = "show memory", - .short_help = "[verbose | api-segment] Show current memory usage", + .short_help = "show memory [api-segment][stats-segment][verbose]", .function = show_memory_usage, }; /* *INDENT-ON* */ @@ -808,7 +947,7 @@ show_cpu (vlib_main_t * vm, unformat_input_t * input, { #define _(a,b,c) vlib_cli_output (vm, "%-25s " b, a ":", c); _("Model name", "%U", format_cpu_model_name); - _("Microarchitecture", "%U", format_cpu_uarch); + _("Microarch model (family)", "%U", format_cpu_uarch); _("Flags", "%U", format_cpu_flags); _("Base frequency", "%.2f GHz", ((f64) vm->clib_time.clocks_per_second) * 1e-9); @@ -833,7 +972,6 @@ VLIB_CLI_COMMAND (show_cpu_command, static) = { .short_help = "Show cpu information", .function = show_cpu, }; - /* *INDENT-ON* */ static clib_error_t * @@ -842,11 +980,12 @@ enable_disable_memory_trace (vlib_main_t * vm, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - int enable; + int enable = 1; int api_segment = 0; + int stats_segment = 0; + int main_heap = 0; void *oldheap; - if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -856,6 +995,10 @@ enable_disable_memory_trace (vlib_main_t * vm, ; else if (unformat (line_input, "api-segment")) api_segment = 1; + else if (unformat (line_input, "stats-segment")) + stats_segment = 1; + else if (unformat (line_input, "main-heap")) + main_heap = 1; else { unformat_free (line_input); @@ -864,11 +1007,52 @@ enable_disable_memory_trace (vlib_main_t * vm, } unformat_free (line_input); + if ((api_segment + stats_segment + main_heap + (enable == 0)) == 0) + { + return clib_error_return + (0, "Need one of main-heap, stats-segment or api-segment"); + } + + /* Turn off current trace, if any */ + if (current_traced_heap) + { + void *oldheap; + oldheap = clib_mem_set_heap (current_traced_heap); + clib_mem_trace (0); + clib_mem_set_heap (oldheap); + current_traced_heap = 0; + } + + if (enable == 0) + return 0; + + /* API segment */ if (api_segment) - oldheap = vl_msg_push_heap (); - clib_mem_trace (enable); - if (api_segment) - vl_msg_pop_heap (oldheap); + { + oldheap = vl_msg_push_heap (); + current_traced_heap = clib_mem_get_heap (); + clib_mem_trace (1); + vl_msg_pop_heap (oldheap); + + } + + /* Stats segment */ + if (stats_segment) + { + oldheap = vlib_stats_push_heap (0); + current_traced_heap = clib_mem_get_heap (); + clib_mem_trace (stats_segment); + /* We don't want to call vlib_stats_pop_heap... */ + if (oldheap) + clib_mem_set_heap (oldheap); + } + + /* main_heap */ + if (main_heap) + { + current_traced_heap = clib_mem_get_heap (); + clib_mem_trace (main_heap); + } return 0; } @@ -876,7 +1060,7 @@ enable_disable_memory_trace (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (enable_disable_memory_trace_command, static) = { .path = "memory-trace", - .short_help = "on|off [api-segment] Enable/disable memory allocation trace", + .short_help = "memory-trace on|off [api-segment][stats-segment][main-heap]\n", .function = enable_disable_memory_trace, }; /* *INDENT-ON* */ @@ -1415,6 +1599,132 @@ VLIB_CLI_COMMAND (show_cli_command, static) = { }; /* *INDENT-ON* */ +static clib_error_t * +elog_trace_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + int enable = 1; + int api = 0, cli = 0, barrier = 0, dispatch = 0, circuit = 0; + u32 circuit_node_index; + + if (!unformat_user (input, unformat_line_input, line_input)) + goto print_status; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "api")) + api = 1; + else if (unformat (line_input, "dispatch")) + dispatch = 1; + else if (unformat (line_input, "circuit-node %U", + unformat_vlib_node, vm, &circuit_node_index)) + circuit = 1; + else if (unformat (line_input, "cli")) + cli = 1; + else if (unformat (line_input, "barrier")) + barrier = 1; + else if (unformat (line_input, "disable")) + enable = 0; + else if (unformat (line_input, "enable")) + enable = 1; + else + break; + } + unformat_free (line_input); + + vl_api_set_elog_trace_api_messages + (api ? enable : vl_api_get_elog_trace_api_messages ()); + vm->elog_trace_cli_commands = cli ? enable : vm->elog_trace_cli_commands; + vm->elog_trace_graph_dispatch = dispatch ? + enable : vm->elog_trace_graph_dispatch; + vm->elog_trace_graph_circuit = circuit ? + enable : vm->elog_trace_graph_circuit; + vlib_worker_threads->barrier_elog_enabled = + barrier ? enable : vlib_worker_threads->barrier_elog_enabled; + vm->elog_trace_graph_circuit_node_index = circuit_node_index; + + /* + * Set up start-of-buffer logic-analyzer trigger + * for main loop event logs, which are fairly heavyweight. + * See src/vlib/main/vlib_elog_main_loop_event(...), which + * will fully disable the scheme when the elog buffer fills. + */ + if (dispatch || circuit) + { + elog_main_t *em = &vm->elog_main; + + em->n_total_events_disable_limit = + em->n_total_events + vec_len (em->event_ring); + } + + +print_status: + vlib_cli_output (vm, "Current status:"); + + vlib_cli_output + (vm, " Event log API message trace: %s\n CLI command trace: %s", + vl_api_get_elog_trace_api_messages ()? "on" : "off", + vm->elog_trace_cli_commands ? "on" : "off"); + vlib_cli_output + (vm, " Barrier sync trace: %s", + vlib_worker_threads->barrier_elog_enabled ? "on" : "off"); + vlib_cli_output + (vm, " Graph Dispatch: %s", + vm->elog_trace_graph_dispatch ? "on" : "off"); + vlib_cli_output + (vm, " Graph Circuit: %s", + vm->elog_trace_graph_circuit ? "on" : "off"); + if (vm->elog_trace_graph_circuit) + vlib_cli_output + (vm, " node %U", + format_vlib_node_name, vm, vm->elog_trace_graph_circuit_node_index); + + return 0; +} + +/*? + * Control event logging of api, cli, and thread barrier events + * With no arguments, displays the current trace status. + * Name the event groups you wish to trace or stop tracing. + * + * @cliexpar + * @clistart + * elog trace api cli barrier + * elog trace api cli barrier disable + * elog trace dispatch + * elog trace circuit-node ethernet-input + * elog trace + * @cliend + * @cliexcmd{elog trace [api][cli][barrier][disable]} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (elog_trace_command, static) = +{ + .path = "elog trace", + .short_help = "elog trace [api][cli][barrier][dispatch]\n" + "[circuit-node e.g. ethernet-input][disable]", + .function = elog_trace_command_fn, +}; +/* *INDENT-ON* */ + +static clib_error_t * +suspend_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + vlib_process_suspend (vm, 30e-3); + return 0; +} + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (suspend_command, static) = +{ + .path = "suspend", + .short_help = "suspend debug CLI for 30ms", + .function = suspend_command_fn, +}; +/* *INDENT-ON* */ + static clib_error_t * vlib_cli_init (vlib_main_t * vm) {