blob: 33ba163abcaadbeec9cac3ee24e66f17012683a3 [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
47 new_tail = __sync_add_and_fetch (&cjm->tail, 1);
48
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);
Dave Barach9b8ffd92016-07-08 08:13:45 -040051 r->cpu = os_get_cpu_number ();
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",
Dave Barach9b8ffd92016-07-08 08:13:45 -0400136 r->cpu, r->time, r->type, (long long unsigned int) r->data[0],
137 (long long unsigned int) r->data[1]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138}
139
Dave Barach9b8ffd92016-07-08 08:13:45 -0400140static void
141cj_dump_internal (u8 filter0_enable, u64 filter0,
142 u8 filter1_enable, u64 filter1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400144 cj_main_t *cjm = &cj_main;
145 cj_record_t *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146 u32 i, index;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400147
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148 if (cjm->num_records == 0)
149 {
150 fprintf (stderr, "CJ not configured...\n");
151 return;
152 }
153
Dave Barach9b8ffd92016-07-08 08:13:45 -0400154 if (cjm->tail == (u64) ~ 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700155 {
156 fprintf (stderr, "No data collected...\n");
157 return;
158 }
159
160 /* Has the trace wrapped? */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400161 index = (cjm->tail + 1) & (cjm->num_records - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162 r = &(cjm->records[index]);
163
Dave Barach9b8ffd92016-07-08 08:13:45 -0400164 if (r->cpu != (u32) ~ 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700165 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400166 /* Yes, dump from tail + 1 to the end */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167 for (i = index; i < cjm->num_records; i++)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400168 {
169 if (filter0_enable && (r->data[0] != filter0))
170 goto skip;
171 if (filter1_enable && (r->data[1] != filter1))
172 goto skip;
173 cj_dump_one_record (r);
174 skip:
175 r++;
176 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177 }
178 /* dump from the beginning through the final tail */
179 r = cjm->records;
180 for (i = 0; i <= cjm->tail; i++)
181 {
182 if (filter0_enable && (r->data[0] != filter0))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400183 goto skip2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 if (filter1_enable && (r->data[1] != filter1))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400185 goto skip2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 cj_dump_one_record (r);
187 skip2:
188 r++;
189 }
190}
191
Dave Barach9b8ffd92016-07-08 08:13:45 -0400192void
193cj_dump (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194{
195 cj_dump_internal (0, 0, 0, 0);
196}
197
Dave Barach9b8ffd92016-07-08 08:13:45 -0400198void
199cj_dump_filter_data0 (u64 filter0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400201 cj_dump_internal (1 /* enable f0 */ , filter0, 0, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202}
203
Dave Barach9b8ffd92016-07-08 08:13:45 -0400204void
205cj_dump_filter_data1 (u64 filter1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400207 cj_dump_internal (0, 0, 1 /* enable f1 */ , filter1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208}
209
Dave Barach9b8ffd92016-07-08 08:13:45 -0400210void
211cj_dump_filter_data12 (u64 filter0, u64 filter1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212{
213 cj_dump_internal (1, filter0, 1, filter1);
214}
215
216static clib_error_t *
217cj_command_fn (vlib_main_t * vm,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400218 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219{
220 int is_enable = -1;
221 int is_dump = -1;
222
Dave Barach9b8ffd92016-07-08 08:13:45 -0400223 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
224 {
225 if (unformat (input, "enable") || unformat (input, "on"))
226 is_enable = 1;
227 else if (unformat (input, "disable") || unformat (input, "off"))
228 is_enable = 0;
229 else if (unformat (input, "dump"))
230 is_dump = 1;
231 else
232 return clib_error_return (0, "unknown input `%U'",
233 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 }
235
236 if (is_enable >= 0)
237 cj_enable_disable (is_enable);
238
239 if (is_dump > 0)
240 cj_dump ();
241
242 return 0;
243}
244
Chris Luke90f52bf2016-09-12 08:55:13 -0400245/*?
246 * Enable, disable the collection of diagnostic data into a
247 * circular journal or dump the circular journal diagnostic data.
248 * This is only useful if you, the deveoper, have written code to make
249 * use of the circular journal.
250 *
251 * When dumping the data it is formatted and sent to @c stderr of the
252 * VPP process; when running VPP in <code>unix interactive</code> mode
253 * this is typically the same place as the Debug CLI.
254?*/
255
Dave Barach9b8ffd92016-07-08 08:13:45 -0400256/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257VLIB_CLI_COMMAND (cj_command,static) = {
258 .path = "cj",
Chris Luke90f52bf2016-09-12 08:55:13 -0400259 .short_help = "cj <enable | disable | dump>",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 .function = cj_command_fn,
261};
Dave Barach9b8ffd92016-07-08 08:13:45 -0400262/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263
Dave Barach9b8ffd92016-07-08 08:13:45 -0400264
265/*
266 * fd.io coding-style-patch-verification: ON
267 *
268 * Local Variables:
269 * eval: (c-set-style "gnu")
270 * End:
271 */