2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 #include <vppinfra/format.h>
17 #include <vlib/vlib.h>
19 #include <vlib/threads.h>
20 #include <linux/sched.h>
23 format_sched_policy (u8 * s, va_list * args)
25 u32 i = va_arg (*args, u32);
30 #define _(v,f,str) case SCHED_POLICY_##f: t = (u8 *) str; break;
34 s = format (s, "%-6s ", t);
39 show_threads_fn (vlib_main_t * vm,
40 unformat_input_t * input, vlib_cli_command_t * cmd)
42 vlib_worker_thread_t *w;
45 vlib_cli_output (vm, "%-7s%-20s%-12s%-8s%-7s%-9s%-7s%-7s%-7s%-10s",
46 "ID", "Name", "Type", "LWP", "Policy", "Priority",
47 "lcore", "Core", "Socket", "State");
49 #if !defined(__powerpc64__)
50 for (i = 0; i < vec_len (vlib_worker_threads); i++)
52 w = vlib_worker_threads + i;
55 line = format (line, "%-7d%-20s%-12s%-8d",
57 w->name ? w->name : (u8 *) "",
58 w->registration ? w->registration->name : "", w->lwp);
61 format (line, "%U", format_sched_policy, sched_getscheduler (w->lwp));
63 struct sched_param sched_param;
64 line = format (line, "%8d ",
65 (!sched_getparam (w->lwp, &sched_param)) ?
66 sched_param.sched_priority : -1);
69 int lcore = w->dpdk_lcore_id;
72 line = format (line, "%-7u%-7u%-7u",
74 lcore_config[lcore].core_id,
75 lcore_config[lcore].socket_id);
77 switch (lcore_config[lcore].state)
80 line = format (line, "wait");
83 line = format (line, "running");
86 line = format (line, "finished");
89 line = format (line, "unknown");
93 vlib_cli_output (vm, "%v", line);
103 VLIB_CLI_COMMAND (show_threads_command, static) = {
104 .path = "show threads",
105 .short_help = "Show threads",
106 .function = show_threads_fn,
111 * Trigger threads to grab frame queue trace data
113 static clib_error_t *
114 trace_frame_queue (vlib_main_t * vm, unformat_input_t * input,
115 vlib_cli_command_t * cmd)
117 clib_error_t *error = NULL;
118 frame_queue_trace_t *fqt;
119 frame_queue_nelt_counter_t *fqh;
120 vlib_thread_main_t *tm = vlib_get_thread_main ();
125 if (unformat (input, "on"))
129 else if (unformat (input, "off"))
135 return clib_error_return (0, "expecting on or off");
138 num_fq = vec_len (vlib_frame_queues);
141 vlib_cli_output (vm, "No frame queues exist\n");
145 // Allocate storage for trace if necessary
146 vec_validate_aligned (tm->frame_queue_traces, num_fq - 1,
147 CLIB_CACHE_LINE_BYTES);
148 vec_validate_aligned (tm->frame_queue_histogram, num_fq - 1,
149 CLIB_CACHE_LINE_BYTES);
151 for (fqix = 0; fqix < num_fq; fqix++)
153 fqt = &tm->frame_queue_traces[fqix];
154 fqh = &tm->frame_queue_histogram[fqix];
156 memset (fqt->n_vectors, 0xff, sizeof (fqt->n_vectors));
158 memset (fqh, 0, sizeof (*fqh));
159 vlib_frame_queues[fqix]->trace = enable;
165 VLIB_CLI_COMMAND (cmd_trace_frame_queue,static) = {
166 .path = "trace frame-queue",
167 .short_help = "trace frame-queue (on|off)",
168 .function = trace_frame_queue,
175 * Adding two counters and compute percent of total
176 * Round up, e.g. 0.000001 => 1%
179 compute_percent (u64 * two_counters, u64 total)
187 return (((two_counters[0] + two_counters[1]) * 100) +
188 (total - 1)) / total;
193 * Display frame queue trace data gathered by threads.
195 static clib_error_t *
196 show_frame_queue_internal (vlib_main_t * vm, u32 histogram)
198 vlib_thread_main_t *tm = vlib_get_thread_main ();
199 clib_error_t *error = NULL;
200 frame_queue_trace_t *fqt;
201 frame_queue_nelt_counter_t *fqh;
205 num_fq = vec_len (tm->frame_queue_traces);
208 vlib_cli_output (vm, "No trace data for frame queues\n");
214 vlib_cli_output (vm, "0-1 2-3 4-5 6-7 8-9 10-11 12-13 14-15 "
215 "16-17 18-19 20-21 22-23 24-25 26-27 28-29 30-31\n");
218 for (fqix = 0; fqix < num_fq; fqix++)
220 fqt = &(tm->frame_queue_traces[fqix]);
222 vlib_cli_output (vm, "Thread %d %v\n", fqix,
223 vlib_worker_threads[fqix].name);
225 if (fqt->written == 0)
227 vlib_cli_output (vm, " no trace data\n");
233 fqh = &(tm->frame_queue_histogram[fqix]);
237 for (nelt = 0; nelt < FRAME_QUEUE_MAX_NELTS; nelt++)
239 total += fqh->count[nelt];
243 * Print in pairs to condense the output.
244 * Allow entries with 0 counts to be clearly identified, by rounding up.
245 * Any non-zero value will be displayed as at least one percent. This
246 * also means the sum of percentages can be > 100, but that is fine. The
247 * histogram is counted from the last time "trace frame on" was issued.
250 "%3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%% "
251 "%3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%%\n",
252 compute_percent (&fqh->count[0], total),
253 compute_percent (&fqh->count[2], total),
254 compute_percent (&fqh->count[4], total),
255 compute_percent (&fqh->count[6], total),
256 compute_percent (&fqh->count[8], total),
257 compute_percent (&fqh->count[10], total),
258 compute_percent (&fqh->count[12], total),
259 compute_percent (&fqh->count[14], total),
260 compute_percent (&fqh->count[16], total),
261 compute_percent (&fqh->count[18], total),
262 compute_percent (&fqh->count[20], total),
263 compute_percent (&fqh->count[22], total),
264 compute_percent (&fqh->count[24], total),
265 compute_percent (&fqh->count[26], total),
266 compute_percent (&fqh->count[28], total),
267 compute_percent (&fqh->count[30], total));
272 " vector-threshold %d ring size %d in use %d\n",
273 fqt->threshold, fqt->nelts, fqt->n_in_use);
274 vlib_cli_output (vm, " head %12d head_hint %12d tail %12d\n",
275 fqt->head, fqt->head_hint, fqt->tail);
277 " %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
278 fqt->n_vectors[0], fqt->n_vectors[1],
279 fqt->n_vectors[2], fqt->n_vectors[3],
280 fqt->n_vectors[4], fqt->n_vectors[5],
281 fqt->n_vectors[6], fqt->n_vectors[7],
282 fqt->n_vectors[8], fqt->n_vectors[9],
283 fqt->n_vectors[10], fqt->n_vectors[11],
284 fqt->n_vectors[12], fqt->n_vectors[13],
285 fqt->n_vectors[14], fqt->n_vectors[15]);
290 " %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
291 fqt->n_vectors[16], fqt->n_vectors[17],
292 fqt->n_vectors[18], fqt->n_vectors[19],
293 fqt->n_vectors[20], fqt->n_vectors[21],
294 fqt->n_vectors[22], fqt->n_vectors[23],
295 fqt->n_vectors[24], fqt->n_vectors[25],
296 fqt->n_vectors[26], fqt->n_vectors[27],
297 fqt->n_vectors[28], fqt->n_vectors[29],
298 fqt->n_vectors[30], fqt->n_vectors[31]);
306 static clib_error_t *
307 show_frame_queue_trace (vlib_main_t * vm, unformat_input_t * input,
308 vlib_cli_command_t * cmd)
310 return show_frame_queue_internal (vm, 0);
313 static clib_error_t *
314 show_frame_queue_histogram (vlib_main_t * vm, unformat_input_t * input,
315 vlib_cli_command_t * cmd)
317 return show_frame_queue_internal (vm, 1);
321 VLIB_CLI_COMMAND (cmd_show_frame_queue_trace,static) = {
322 .path = "show frame-queue",
323 .short_help = "show frame-queue trace",
324 .function = show_frame_queue_trace,
329 VLIB_CLI_COMMAND (cmd_show_frame_queue_histogram,static) = {
330 .path = "show frame-queue histogram",
331 .short_help = "show frame-queue histogram",
332 .function = show_frame_queue_histogram,
338 * Modify the number of elements on the frame_queues
340 static clib_error_t *
341 test_frame_queue_nelts (vlib_main_t * vm, unformat_input_t * input,
342 vlib_cli_command_t * cmd)
344 clib_error_t *error = NULL;
349 if ((unformat (input, "%d", &nelts) != 1) ||
350 ((nelts != 4) && (nelts != 8) && (nelts != 16) && (nelts != 32)))
352 return clib_error_return (0, "expecting 4,8,16,32");
355 num_fq = vec_len (vlib_frame_queues);
358 vlib_cli_output (vm, "No frame queues exist\n");
362 for (fqix = 0; fqix < num_fq; fqix++)
364 vlib_frame_queues[fqix]->nelts = nelts;
371 VLIB_CLI_COMMAND (cmd_test_frame_queue_nelts,static) = {
372 .path = "test frame-queue nelts",
373 .short_help = "test frame-queue nelts (4,8,16,32)",
374 .function = test_frame_queue_nelts,
380 * Modify the max number of packets pulled off the frame queues
382 static clib_error_t *
383 test_frame_queue_threshold (vlib_main_t * vm, unformat_input_t * input,
384 vlib_cli_command_t * cmd)
386 clib_error_t *error = NULL;
391 if (unformat (input, "%d", &threshold))
396 vlib_cli_output (vm, "expecting threshold value\n");
403 num_fq = vec_len (vlib_frame_queues);
406 vlib_cli_output (vm, "No frame queues exist\n");
410 for (fqix = 0; fqix < num_fq; fqix++)
412 vlib_frame_queues[fqix]->vector_threshold = threshold;
419 VLIB_CLI_COMMAND (cmd_test_frame_queue_threshold,static) = {
420 .path = "test frame-queue threshold",
421 .short_help = "test frame-queue threshold N (0=no limit)",
422 .function = test_frame_queue_threshold,
428 * fd.io coding-style-patch-verification: ON
431 * eval: (c-set-style "gnu")