blob: 7757146c7a7c33f30c5083490343db5a6694727a [file] [log] [blame]
Dave Barach9b8ffd92016-07-08 08:13:45 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
3 * cj.c
4 *
5 * Copyright (c) 2013 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
18 */
19
Chris Luke90f52bf2016-09-12 08:55:13 -040020/**
21 * @file
22 * Circular joournal diagnostic mechanism.
23 *
24 * The @c cj thread-safe circular log buffer scheme is occasionally useful
25 * when chasing bugs. Calls to it should not be checked in.
26 */
27/*? %%clicmd:group_label Circular Journal %% ?*/
28/*? %%syscfg:group_label Circular Journal %% ?*/
29
Ed Warnickecb9cada2015-12-08 15:45:58 -070030#include <stdio.h>
31#include <vlib/vlib.h>
32
33#include <vlib/unix/cj.h>
34
35cj_main_t cj_main;
36
37void
Dave Barach9b8ffd92016-07-08 08:13:45 -040038cj_log (u32 type, void *data0, void *data1)
Ed Warnickecb9cada2015-12-08 15:45:58 -070039{
40 u64 new_tail;
Dave Barach9b8ffd92016-07-08 08:13:45 -040041 cj_main_t *cjm = &cj_main;
42 cj_record_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -070043
44 if (cjm->enable == 0)
45 return;
46
Sirshak Das2f6d7bb2018-10-03 22:53:51 +000047 new_tail = clib_atomic_add_fetch (&cjm->tail, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Dave Barach9b8ffd92016-07-08 08:13:45 -040049 r = (cj_record_t *) & (cjm->records[new_tail & (cjm->num_records - 1)]);
Ed Warnickecb9cada2015-12-08 15:45:58 -070050 r->time = vlib_time_now (cjm->vlib_main);
Damjan Marion586afd72017-04-05 19:18:20 +020051 r->thread_index = vlib_get_thread_index ();
Ed Warnickecb9cada2015-12-08 15:45:58 -070052 r->type = type;
Dave Barach9b8ffd92016-07-08 08:13:45 -040053 r->data[0] = pointer_to_uword (data0);
54 r->data[1] = pointer_to_uword (data1);
Ed Warnickecb9cada2015-12-08 15:45:58 -070055}
56
Dave Barach9b8ffd92016-07-08 08:13:45 -040057void
58cj_stop (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070059{
Dave Barach9b8ffd92016-07-08 08:13:45 -040060 cj_main_t *cjm = &cj_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070061
62 cjm->enable = 0;
63}
64
65
Dave Barach9b8ffd92016-07-08 08:13:45 -040066clib_error_t *
67cj_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
Dave Barach9b8ffd92016-07-08 08:13:45 -040069 cj_main_t *cjm = &cj_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
71 cjm->vlib_main = vm;
72 return 0;
73}
Dave Barach9b8ffd92016-07-08 08:13:45 -040074
Ed Warnickecb9cada2015-12-08 15:45:58 -070075VLIB_INIT_FUNCTION (cj_init);
76
77static clib_error_t *
78cj_config (vlib_main_t * vm, unformat_input_t * input)
79{
Dave Barach9b8ffd92016-07-08 08:13:45 -040080 cj_main_t *cjm = &cj_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 int matched = 0;
82 int enable = 0;
83
Dave Barach9b8ffd92016-07-08 08:13:45 -040084 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -070085 {
86 if (unformat (input, "records %d", &cjm->num_records))
Dave Barach9b8ffd92016-07-08 08:13:45 -040087 matched = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 else if (unformat (input, "on"))
Dave Barach9b8ffd92016-07-08 08:13:45 -040089 enable = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 else
Dave Barach9b8ffd92016-07-08 08:13:45 -040091 return clib_error_return (0, "cj_config: unknown input '%U'",
92 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 }
94
95 if (matched == 0)
96 return 0;
97
98 cjm->num_records = max_pow2 (cjm->num_records);
Dave Barach9b8ffd92016-07-08 08:13:45 -040099 vec_validate (cjm->records, cjm->num_records - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100 memset (cjm->records, 0xff, cjm->num_records * sizeof (cj_record_t));
101 cjm->tail = ~0;
102 cjm->enable = enable;
103
104 return 0;
105}
106
Chris Luke90f52bf2016-09-12 08:55:13 -0400107/*?
108 * Configure the circular journal diagnostic mechanism. This is only useful
109 * if you, the deveoper, have written code to make use of the circular
110 * journal.
111 *
112 * @cfgcmd{records, &lt;number&gt;}
113 * Configure the number of records to allocate for the circular journal.
114 *
115 * @cfgcmd{on}
116 * Enable the collection of records in the circular journal at the
117 * earliest opportunity.
118?*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119VLIB_CONFIG_FUNCTION (cj_config, "cj");
120
Dave Barach9b8ffd92016-07-08 08:13:45 -0400121void
122cj_enable_disable (int is_enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400124 cj_main_t *cjm = &cj_main;
125
Ed Warnickecb9cada2015-12-08 15:45:58 -0700126 if (cjm->num_records)
127 cjm->enable = is_enable;
128 else
129 vlib_cli_output (cjm->vlib_main, "CJ not configured...");
130}
131
Dave Barach9b8ffd92016-07-08 08:13:45 -0400132static inline void
133cj_dump_one_record (cj_record_t * r)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134{
135 fprintf (stderr, "[%d]: %10.6f T%02d %llx %llx\n",
Damjan Marion586afd72017-04-05 19:18:20 +0200136 r->thread_index, r->time, r->type,
137 (long long unsigned int) r->data[0],
Dave Barach9b8ffd92016-07-08 08:13:45 -0400138 (long long unsigned int) r->data[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139}
140
Dave Barach9b8ffd92016-07-08 08:13:45 -0400141static void
142cj_dump_internal (u8 filter0_enable, u64 filter0,
143 u8 filter1_enable, u64 filter1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400145 cj_main_t *cjm = &cj_main;
146 cj_record_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147 u32 i, index;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400148
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149 if (cjm->num_records == 0)
150 {
151 fprintf (stderr, "CJ not configured...\n");
152 return;
153 }
154
Dave Barach9b8ffd92016-07-08 08:13:45 -0400155 if (cjm->tail == (u64) ~ 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156 {
157 fprintf (stderr, "No data collected...\n");
158 return;
159 }
160
161 /* Has the trace wrapped? */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400162 index = (cjm->tail + 1) & (cjm->num_records - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 r = &(cjm->records[index]);
164
Damjan Marion586afd72017-04-05 19:18:20 +0200165 if (r->thread_index != (u32) ~ 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400167 /* Yes, dump from tail + 1 to the end */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168 for (i = index; i < cjm->num_records; i++)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400169 {
170 if (filter0_enable && (r->data[0] != filter0))
171 goto skip;
172 if (filter1_enable && (r->data[1] != filter1))
173 goto skip;
174 cj_dump_one_record (r);
175 skip:
176 r++;
177 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 }
179 /* dump from the beginning through the final tail */
180 r = cjm->records;
181 for (i = 0; i <= cjm->tail; i++)
182 {
183 if (filter0_enable && (r->data[0] != filter0))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400184 goto skip2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185 if (filter1_enable && (r->data[1] != filter1))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400186 goto skip2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 cj_dump_one_record (r);
188 skip2:
189 r++;
190 }
191}
192
Dave Barach9b8ffd92016-07-08 08:13:45 -0400193void
194cj_dump (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195{
196 cj_dump_internal (0, 0, 0, 0);
197}
198
Dave Barach9b8ffd92016-07-08 08:13:45 -0400199void
200cj_dump_filter_data0 (u64 filter0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400202 cj_dump_internal (1 /* enable f0 */ , filter0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203}
204
Dave Barach9b8ffd92016-07-08 08:13:45 -0400205void
206cj_dump_filter_data1 (u64 filter1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400208 cj_dump_internal (0, 0, 1 /* enable f1 */ , filter1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209}
210
Dave Barach9b8ffd92016-07-08 08:13:45 -0400211void
212cj_dump_filter_data12 (u64 filter0, u64 filter1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213{
214 cj_dump_internal (1, filter0, 1, filter1);
215}
216
217static clib_error_t *
218cj_command_fn (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400219 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220{
221 int is_enable = -1;
222 int is_dump = -1;
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530223 unformat_input_t _line_input, *line_input = &_line_input;
224 clib_error_t *error = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530226 /* Get a line of input. */
227 if (!unformat_user (input, unformat_line_input, line_input))
228 return clib_error_return (0, "expected enable | disable | dump");
229
230 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400231 {
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530232 if (unformat (line_input, "enable") || unformat (line_input, "on"))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400233 is_enable = 1;
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530234 else if (unformat (line_input, "disable")
235 || unformat (line_input, "off"))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400236 is_enable = 0;
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530237 else if (unformat (line_input, "dump"))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400238 is_dump = 1;
239 else
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530240 {
241 error = clib_error_return (0, "unknown input `%U'",
242 format_unformat_error, line_input);
243 goto done;
244 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 }
246
247 if (is_enable >= 0)
248 cj_enable_disable (is_enable);
249
250 if (is_dump > 0)
251 cj_dump ();
252
Swarup Nayak82d8ec22017-12-04 11:54:43 +0530253done:
254 unformat_free (line_input);
255 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256}
257
Chris Luke90f52bf2016-09-12 08:55:13 -0400258/*?
259 * Enable, disable the collection of diagnostic data into a
260 * circular journal or dump the circular journal diagnostic data.
261 * This is only useful if you, the deveoper, have written code to make
262 * use of the circular journal.
263 *
264 * When dumping the data it is formatted and sent to @c stderr of the
265 * VPP process; when running VPP in <code>unix interactive</code> mode
266 * this is typically the same place as the Debug CLI.
267?*/
268
Dave Barach9b8ffd92016-07-08 08:13:45 -0400269/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700270VLIB_CLI_COMMAND (cj_command,static) = {
271 .path = "cj",
Chris Luke90f52bf2016-09-12 08:55:13 -0400272 .short_help = "cj <enable | disable | dump>",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273 .function = cj_command_fn,
274};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400275/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276
Dave Barach9b8ffd92016-07-08 08:13:45 -0400277
278/*
279 * fd.io coding-style-patch-verification: ON
280 *
281 * Local Variables:
282 * eval: (c-set-style "gnu")
283 * End:
284 */