diff options
Diffstat (limited to 'extras/deprecated/vlib/unix')
-rw-r--r-- | extras/deprecated/vlib/unix/cj.c | 284 | ||||
-rw-r--r-- | extras/deprecated/vlib/unix/cj.h | 79 |
2 files changed, 363 insertions, 0 deletions
diff --git a/extras/deprecated/vlib/unix/cj.c b/extras/deprecated/vlib/unix/cj.c new file mode 100644 index 00000000000..e163e1ae017 --- /dev/null +++ b/extras/deprecated/vlib/unix/cj.c @@ -0,0 +1,284 @@ +/* + *------------------------------------------------------------------ + * cj.c + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +/** + * @file + * Circular journal diagnostic mechanism. + * + * The @c cj thread-safe circular log buffer scheme is occasionally useful + * when chasing bugs. Calls to it should not be checked in. + */ +/*? %%clicmd:group_label Circular Journal %% ?*/ +/*? %%syscfg:group_label Circular Journal %% ?*/ + +#include <stdio.h> +#include <vlib/vlib.h> + +#include <vlib/unix/cj.h> + +cj_main_t cj_main; + +void +cj_log (u32 type, void *data0, void *data1) +{ + u64 new_tail; + cj_main_t *cjm = &cj_main; + cj_record_t *r; + + if (cjm->enable == 0) + return; + + new_tail = clib_atomic_add_fetch (&cjm->tail, 1); + + r = (cj_record_t *) & (cjm->records[new_tail & (cjm->num_records - 1)]); + r->time = vlib_time_now (cjm->vlib_main); + r->thread_index = vlib_get_thread_index (); + r->type = type; + r->data[0] = pointer_to_uword (data0); + r->data[1] = pointer_to_uword (data1); +} + +void +cj_stop (void) +{ + cj_main_t *cjm = &cj_main; + + cjm->enable = 0; +} + + +clib_error_t * +cj_init (vlib_main_t * vm) +{ + cj_main_t *cjm = &cj_main; + + cjm->vlib_main = vm; + return 0; +} + +VLIB_INIT_FUNCTION (cj_init); + +static clib_error_t * +cj_config (vlib_main_t * vm, unformat_input_t * input) +{ + cj_main_t *cjm = &cj_main; + int matched = 0; + int enable = 0; + + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "records %d", &cjm->num_records)) + matched = 1; + else if (unformat (input, "on")) + enable = 1; + else + return clib_error_return (0, "cj_config: unknown input '%U'", + format_unformat_error, input); + } + + if (matched == 0) + return 0; + + cjm->num_records = max_pow2 (cjm->num_records); + vec_validate (cjm->records, cjm->num_records - 1); + clib_memset (cjm->records, 0xff, cjm->num_records * sizeof (cj_record_t)); + cjm->tail = ~0; + cjm->enable = enable; + + return 0; +} + +/*? + * Configure the circular journal diagnostic mechanism. This is only useful + * if you, the developer, have written code to make use of the circular + * journal. + * + * @cfgcmd{records, <number>} + * Configure the number of records to allocate for the circular journal. + * + * @cfgcmd{on} + * Enable the collection of records in the circular journal at the + * earliest opportunity. +?*/ +VLIB_CONFIG_FUNCTION (cj_config, "cj"); + +void +cj_enable_disable (int is_enable) +{ + cj_main_t *cjm = &cj_main; + + if (cjm->num_records) + cjm->enable = is_enable; + else + vlib_cli_output (cjm->vlib_main, "CJ not configured..."); +} + +static inline void +cj_dump_one_record (cj_record_t * r) +{ + fprintf (stderr, "[%d]: %10.6f T%02d %llx %llx\n", + r->thread_index, r->time, r->type, + (long long unsigned int) r->data[0], + (long long unsigned int) r->data[1]); +} + +static void +cj_dump_internal (u8 filter0_enable, u64 filter0, + u8 filter1_enable, u64 filter1) +{ + cj_main_t *cjm = &cj_main; + cj_record_t *r; + u32 i, index; + + if (cjm->num_records == 0) + { + fprintf (stderr, "CJ not configured...\n"); + return; + } + + if (cjm->tail == (u64) ~ 0) + { + fprintf (stderr, "No data collected...\n"); + return; + } + + /* Has the trace wrapped? */ + index = (cjm->tail + 1) & (cjm->num_records - 1); + r = &(cjm->records[index]); + + if (r->thread_index != (u32) ~ 0) + { + /* Yes, dump from tail + 1 to the end */ + for (i = index; i < cjm->num_records; i++) + { + if (filter0_enable && (r->data[0] != filter0)) + goto skip; + if (filter1_enable && (r->data[1] != filter1)) + goto skip; + cj_dump_one_record (r); + skip: + r++; + } + } + /* dump from the beginning through the final tail */ + r = cjm->records; + for (i = 0; i < index; i++) + { + if (filter0_enable && (r->data[0] != filter0)) + goto skip2; + if (filter1_enable && (r->data[1] != filter1)) + goto skip2; + cj_dump_one_record (r); + skip2: + r++; + } +} + +void +cj_dump (void) +{ + cj_dump_internal (0, 0, 0, 0); +} + +void +cj_dump_filter_data0 (u64 filter0) +{ + cj_dump_internal (1 /* enable f0 */ , filter0, 0, 0); +} + +void +cj_dump_filter_data1 (u64 filter1) +{ + cj_dump_internal (0, 0, 1 /* enable f1 */ , filter1); +} + +void +cj_dump_filter_data12 (u64 filter0, u64 filter1) +{ + cj_dump_internal (1, filter0, 1, filter1); +} + +static clib_error_t * +cj_command_fn (vlib_main_t * vm, + unformat_input_t * input, vlib_cli_command_t * cmd) +{ + int is_enable = -1; + int is_dump = -1; + unformat_input_t _line_input, *line_input = &_line_input; + clib_error_t *error = NULL; + + /* Get a line of input. */ + if (!unformat_user (input, unformat_line_input, line_input)) + return clib_error_return (0, "expected enable | disable | dump"); + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (line_input, "enable") || unformat (line_input, "on")) + is_enable = 1; + else if (unformat (line_input, "disable") + || unformat (line_input, "off")) + is_enable = 0; + else if (unformat (line_input, "dump")) + is_dump = 1; + else + { + error = clib_error_return (0, "unknown input `%U'", + format_unformat_error, line_input); + goto done; + } + } + + if (is_enable >= 0) + cj_enable_disable (is_enable); + + if (is_dump > 0) + cj_dump (); + +done: + unformat_free (line_input); + return error; +} + +/*? + * Enable, disable the collection of diagnostic data into a + * circular journal or dump the circular journal diagnostic data. + * This is only useful if you, the developer, have written code to make + * use of the circular journal. + * + * When dumping the data it is formatted and sent to @c stderr of the + * VPP process; when running VPP in <code>unix interactive</code> mode + * this is typically the same place as the Debug CLI. +?*/ + +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (cj_command,static) = { + .path = "cj", + .short_help = "cj <enable | disable | dump>", + .function = cj_command_fn, +}; +/* *INDENT-ON* */ + + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ diff --git a/extras/deprecated/vlib/unix/cj.h b/extras/deprecated/vlib/unix/cj.h new file mode 100644 index 00000000000..d0a1d46ee99 --- /dev/null +++ b/extras/deprecated/vlib/unix/cj.h @@ -0,0 +1,79 @@ +/* + *------------------------------------------------------------------ + * cj.h + * + * Copyright (c) 2013 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------ + */ + +#ifndef __included_cj_h__ +#define __included_cj_h__ + +typedef struct +{ + f64 time; + u32 thread_index; + u32 type; + u64 data[2]; +} cj_record_t; + +typedef struct +{ + volatile u64 tail; + cj_record_t *records; + u32 num_records; + volatile u32 enable; + + vlib_main_t *vlib_main; +} cj_main_t; + +void cj_log (u32 type, void *data0, void *data1); + +/* + * Supply in application main, so we can log from any library... + * Declare a weak reference in the library, off you go. + */ + +#define DECLARE_CJ_GLOBAL_LOG \ +void cj_global_log (unsigned type, void * data0, void * data1) \ + __attribute__ ((weak)); \ + \ +unsigned __cj_type; \ +void * __cj_data0; \ +void * __cj_data1; \ + \ +void \ +cj_global_log (unsigned type, void * data0, void * data1) \ +{ \ + __cj_type = type; \ + __cj_data0 = data0; \ + __cj_data1 = data1; \ +} + +#define CJ_GLOBAL_LOG_PROTOTYPE +void +cj_global_log (unsigned type, void *data0, void *data1) +__attribute__ ((weak)); + +void cj_stop (void); + +#endif /* __included_cj_h__ */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ |