FD.io VPP  v17.04-9-g99c0734
Vector Packet Processing
threads_cli.c
Go to the documentation of this file.
1 /*
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:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15 #define _GNU_SOURCE
16 
17 #include <vppinfra/format.h>
18 #include <vlib/vlib.h>
19 
20 #include <vlib/threads.h>
21 #include <vlib/unix/unix.h>
22 
23 static u8 *
24 format_sched_policy_and_priority (u8 * s, va_list * args)
25 {
26  long i = va_arg (*args, long);
27  struct sched_param sched_param;
28  u8 *t = 0;
29 
30  switch (sched_getscheduler (i))
31  {
32 #define _(v,f,str) case SCHED_POLICY_##f: t = (u8 *) str; break;
34 #undef _
35  }
36  if (sched_getparam (i, &sched_param) == 0)
37  return format (s, "%s (%d)", t, sched_param.sched_priority);
38  else
39  return format (s, "%s (n/a)", t);
40 }
41 
42 static clib_error_t *
44  unformat_input_t * input, vlib_cli_command_t * cmd)
45 {
47  int i;
48 
49  vlib_cli_output (vm, "%-7s%-20s%-12s%-8s%-25s%-7s%-7s%-7s%-10s",
50  "ID", "Name", "Type", "LWP", "Sched Policy (Priority)",
51  "lcore", "Core", "Socket", "State");
52 
53 #if !defined(__powerpc64__)
54  for (i = 0; i < vec_len (vlib_worker_threads); i++)
55  {
56  w = vlib_worker_threads + i;
57  u8 *line = NULL;
58 
59  line = format (line, "%-7d%-20s%-12s%-8d",
60  i,
61  w->name ? w->name : (u8 *) "",
62  w->registration ? w->registration->name : "", w->lwp);
63 
64  line = format (line, "%-25U", format_sched_policy_and_priority, w->lwp);
65 
66  int lcore = -1;
67  cpu_set_t cpuset;
68  CPU_ZERO (&cpuset);
69  int ret = -1;
70 
71  ret =
72  pthread_getaffinity_np (w->thread_id, sizeof (cpu_set_t), &cpuset);
73  if (!ret)
74  {
75  int c;
76  for (c = 0; c < CPU_SETSIZE; c++)
77  if (CPU_ISSET (c, &cpuset))
78  {
79  if (lcore > -1)
80  {
81  lcore = -2;
82  break;
83  }
84  lcore = c;
85  }
86  }
87  else
88  {
89  lcore = w->lcore_id;
90  }
91 
92  if (lcore > -1)
93  {
94  const char *sys_cpu_path = "/sys/devices/system/cpu/cpu";
95  int socket_id = -1;
96  int core_id = -1;
97  u8 *p = 0;
98 
99  p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, lcore, 0);
100  vlib_sysfs_read ((char *) p, "%d", &core_id);
101 
102  vec_reset_length (p);
103  p =
104  format (p,
105  "%s%u/topology/physical_package_id%c",
106  sys_cpu_path, lcore, 0);
107  vlib_sysfs_read ((char *) p, "%d", &socket_id);
108  vec_free (p);
109 
110  line = format (line, "%-7u%-7u%-7u%", lcore, core_id, socket_id);
111  }
112  else
113  {
114  line =
115  format (line, "%-7s%-7s%-7s%", (lcore == -2) ? "M" : "n/a", "n/a",
116  "n/a");
117  }
118 
119  vlib_cli_output (vm, "%v", line);
120  vec_free (line);
121  }
122 #endif
123 
124  return 0;
125 }
126 
127 
128 /* *INDENT-OFF* */
129 VLIB_CLI_COMMAND (show_threads_command, static) = {
130  .path = "show threads",
131  .short_help = "Show threads",
132  .function = show_threads_fn,
133 };
134 /* *INDENT-ON* */
135 
136 /*
137  * Trigger threads to grab frame queue trace data
138  */
139 static clib_error_t *
141  vlib_cli_command_t * cmd)
142 {
143  unformat_input_t _line_input, *line_input = &_line_input;
144  clib_error_t *error = NULL;
145  frame_queue_trace_t *fqt;
149  u32 num_fq;
150  u32 fqix;
151  u32 enable = 2;
152  u32 index = ~(u32) 0;
153 
154  if (!unformat_user (input, unformat_line_input, line_input))
155  return 0;
156 
157  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
158  {
159  if (unformat (line_input, "on"))
160  enable = 1;
161  else if (unformat (line_input, "off"))
162  enable = 0;
163  else if (unformat (line_input, "index %u", &index))
164  ;
165  else
166  {
167  error = clib_error_return (0, "parse error: '%U'",
168  format_unformat_error, line_input);
169  goto done;
170  }
171  }
172 
173  if (enable > 1)
174  {
175  error = clib_error_return (0, "expecting on or off");
176  goto done;
177  }
178 
179  if (vec_len (tm->frame_queue_mains) == 0)
180  {
181  error = clib_error_return (0, "no worker handoffs exist");
182  goto done;
183  }
184 
185  if (index > vec_len (tm->frame_queue_mains) - 1)
186  {
187  error = clib_error_return (0,
188  "expecting valid worker handoff queue index");
189  goto done;
190  }
191 
192  fqm = vec_elt_at_index (tm->frame_queue_mains, index);
193 
194  num_fq = vec_len (fqm->vlib_frame_queues);
195  if (num_fq == 0)
196  {
197  vlib_cli_output (vm, "No frame queues exist\n");
198  goto done;
199  }
200 
201  // Allocate storage for trace if necessary
202  vec_validate_aligned (fqm->frame_queue_traces, num_fq - 1,
206 
207  for (fqix = 0; fqix < num_fq; fqix++)
208  {
209  fqt = &fqm->frame_queue_traces[fqix];
210  fqh = &fqm->frame_queue_histogram[fqix];
211 
212  memset (fqt->n_vectors, 0xff, sizeof (fqt->n_vectors));
213  fqt->written = 0;
214  memset (fqh, 0, sizeof (*fqh));
215  fqm->vlib_frame_queues[fqix]->trace = enable;
216  }
217 
218 done:
219  unformat_free (line_input);
220 
221  return error;
222 }
223 
224 /* *INDENT-OFF* */
225 VLIB_CLI_COMMAND (cmd_trace_frame_queue,static) = {
226  .path = "trace frame-queue",
227  .short_help = "trace frame-queue (on|off)",
228  .function = trace_frame_queue,
229  .is_mp_safe = 1,
230 };
231 /* *INDENT-ON* */
232 
233 
234 /*
235  * Adding two counters and compute percent of total
236  * Round up, e.g. 0.000001 => 1%
237  */
238 static u32
239 compute_percent (u64 * two_counters, u64 total)
240 {
241  if (total == 0)
242  {
243  return 0;
244  }
245  else
246  {
247  return (((two_counters[0] + two_counters[1]) * 100) +
248  (total - 1)) / total;
249  }
250 }
251 
252 /*
253  * Display frame queue trace data gathered by threads.
254  */
255 static clib_error_t *
257  vlib_frame_queue_main_t * fqm, u32 histogram)
258 {
259  clib_error_t *error = NULL;
260  frame_queue_trace_t *fqt;
262  u32 num_fq;
263  u32 fqix;
264 
265  num_fq = vec_len (fqm->frame_queue_traces);
266  if (num_fq == 0)
267  {
268  vlib_cli_output (vm, "No trace data for frame queues\n");
269  return error;
270  }
271 
272  if (histogram)
273  {
274  vlib_cli_output (vm, "0-1 2-3 4-5 6-7 8-9 10-11 12-13 14-15 "
275  "16-17 18-19 20-21 22-23 24-25 26-27 28-29 30-31\n");
276  }
277 
278  for (fqix = 0; fqix < num_fq; fqix++)
279  {
280  fqt = &(fqm->frame_queue_traces[fqix]);
281 
282  vlib_cli_output (vm, "Thread %d %v\n", fqix,
283  vlib_worker_threads[fqix].name);
284 
285  if (fqt->written == 0)
286  {
287  vlib_cli_output (vm, " no trace data\n");
288  continue;
289  }
290 
291  if (histogram)
292  {
293  fqh = &(fqm->frame_queue_histogram[fqix]);
294  u32 nelt;
295  u64 total = 0;
296 
297  for (nelt = 0; nelt < FRAME_QUEUE_MAX_NELTS; nelt++)
298  {
299  total += fqh->count[nelt];
300  }
301 
302  /*
303  * Print in pairs to condense the output.
304  * Allow entries with 0 counts to be clearly identified, by rounding up.
305  * Any non-zero value will be displayed as at least one percent. This
306  * also means the sum of percentages can be > 100, but that is fine. The
307  * histogram is counted from the last time "trace frame on" was issued.
308  */
309  vlib_cli_output (vm,
310  "%3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%% "
311  "%3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%% %3d%%\n",
312  compute_percent (&fqh->count[0], total),
313  compute_percent (&fqh->count[2], total),
314  compute_percent (&fqh->count[4], total),
315  compute_percent (&fqh->count[6], total),
316  compute_percent (&fqh->count[8], total),
317  compute_percent (&fqh->count[10], total),
318  compute_percent (&fqh->count[12], total),
319  compute_percent (&fqh->count[14], total),
320  compute_percent (&fqh->count[16], total),
321  compute_percent (&fqh->count[18], total),
322  compute_percent (&fqh->count[20], total),
323  compute_percent (&fqh->count[22], total),
324  compute_percent (&fqh->count[24], total),
325  compute_percent (&fqh->count[26], total),
326  compute_percent (&fqh->count[28], total),
327  compute_percent (&fqh->count[30], total));
328  }
329  else
330  {
331  vlib_cli_output (vm,
332  " vector-threshold %d ring size %d in use %d\n",
333  fqt->threshold, fqt->nelts, fqt->n_in_use);
334  vlib_cli_output (vm, " head %12d head_hint %12d tail %12d\n",
335  fqt->head, fqt->head_hint, fqt->tail);
336  vlib_cli_output (vm,
337  " %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
338  fqt->n_vectors[0], fqt->n_vectors[1],
339  fqt->n_vectors[2], fqt->n_vectors[3],
340  fqt->n_vectors[4], fqt->n_vectors[5],
341  fqt->n_vectors[6], fqt->n_vectors[7],
342  fqt->n_vectors[8], fqt->n_vectors[9],
343  fqt->n_vectors[10], fqt->n_vectors[11],
344  fqt->n_vectors[12], fqt->n_vectors[13],
345  fqt->n_vectors[14], fqt->n_vectors[15]);
346 
347  if (fqt->nelts > 16)
348  {
349  vlib_cli_output (vm,
350  " %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d %3d\n",
351  fqt->n_vectors[16], fqt->n_vectors[17],
352  fqt->n_vectors[18], fqt->n_vectors[19],
353  fqt->n_vectors[20], fqt->n_vectors[21],
354  fqt->n_vectors[22], fqt->n_vectors[23],
355  fqt->n_vectors[24], fqt->n_vectors[25],
356  fqt->n_vectors[26], fqt->n_vectors[27],
357  fqt->n_vectors[28], fqt->n_vectors[29],
358  fqt->n_vectors[30], fqt->n_vectors[31]);
359  }
360  }
361 
362  }
363  return error;
364 }
365 
366 static clib_error_t *
368  vlib_cli_command_t * cmd)
369 {
372  clib_error_t *error;
373 
374  vec_foreach (fqm, tm->frame_queue_mains)
375  {
376  vlib_cli_output (vm, "Worker handoff queue index %u (next node '%U'):",
377  fqm - tm->frame_queue_mains,
379  error = show_frame_queue_internal (vm, fqm, 0);
380  if (error)
381  return error;
382  }
383  return 0;
384 }
385 
386 static clib_error_t *
388  vlib_cli_command_t * cmd)
389 {
392  clib_error_t *error;
393 
394  vec_foreach (fqm, tm->frame_queue_mains)
395  {
396  vlib_cli_output (vm, "Worker handoff queue index %u (next node '%U'):",
397  fqm - tm->frame_queue_mains,
399  error = show_frame_queue_internal (vm, fqm, 1);
400  if (error)
401  return error;
402  }
403  return 0;
404 }
405 
406 /* *INDENT-OFF* */
407 VLIB_CLI_COMMAND (cmd_show_frame_queue_trace,static) = {
408  .path = "show frame-queue",
409  .short_help = "show frame-queue trace",
410  .function = show_frame_queue_trace,
411 };
412 /* *INDENT-ON* */
413 
414 /* *INDENT-OFF* */
415 VLIB_CLI_COMMAND (cmd_show_frame_queue_histogram,static) = {
416  .path = "show frame-queue histogram",
417  .short_help = "show frame-queue histogram",
418  .function = show_frame_queue_histogram,
419 };
420 /* *INDENT-ON* */
421 
422 
423 /*
424  * Modify the number of elements on the frame_queues
425  */
426 static clib_error_t *
428  vlib_cli_command_t * cmd)
429 {
430  unformat_input_t _line_input, *line_input = &_line_input;
433  clib_error_t *error = NULL;
434  u32 num_fq;
435  u32 fqix;
436  u32 nelts = 0;
437  u32 index = ~(u32) 0;
438 
439  if (!unformat_user (input, unformat_line_input, line_input))
440  return 0;
441 
442  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
443  {
444  if (unformat (line_input, "nelts %u", &nelts))
445  ;
446  else if (unformat (line_input, "index %u", &index))
447  ;
448  else
449  {
450  error = clib_error_return (0, "parse error: '%U'",
451  format_unformat_error, line_input);
452  goto done;
453  }
454  }
455 
456  if (index > vec_len (tm->frame_queue_mains) - 1)
457  {
458  error = clib_error_return (0,
459  "expecting valid worker handoff queue index");
460  goto done;
461  }
462 
463  fqm = vec_elt_at_index (tm->frame_queue_mains, index);
464 
465  if ((nelts != 4) && (nelts != 8) && (nelts != 16) && (nelts != 32))
466  {
467  error = clib_error_return (0, "expecting 4,8,16,32");
468  goto done;
469  }
470 
471  num_fq = vec_len (fqm->vlib_frame_queues);
472  if (num_fq == 0)
473  {
474  vlib_cli_output (vm, "No frame queues exist\n");
475  goto done;
476  }
477 
478  for (fqix = 0; fqix < num_fq; fqix++)
479  {
480  fqm->vlib_frame_queues[fqix]->nelts = nelts;
481  }
482 
483 done:
484  unformat_free (line_input);
485 
486  return error;
487 }
488 
489 /* *INDENT-OFF* */
490 VLIB_CLI_COMMAND (cmd_test_frame_queue_nelts,static) = {
491  .path = "test frame-queue nelts",
492  .short_help = "test frame-queue nelts (4,8,16,32)",
493  .function = test_frame_queue_nelts,
494 };
495 /* *INDENT-ON* */
496 
497 
498 /*
499  * Modify the max number of packets pulled off the frame queues
500  */
501 static clib_error_t *
503  vlib_cli_command_t * cmd)
504 {
505  unformat_input_t _line_input, *line_input = &_line_input;
508  clib_error_t *error = NULL;
509  u32 num_fq;
510  u32 fqix;
511  u32 threshold = ~(u32) 0;
512  u32 index = ~(u32) 0;
513 
514  if (!unformat_user (input, unformat_line_input, line_input))
515  return 0;
516 
517  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
518  {
519  if (unformat (line_input, "threshold %u", &threshold))
520  ;
521  else if (unformat (line_input, "index %u", &index))
522  ;
523  else
524  {
525  error = clib_error_return (0, "parse error: '%U'",
526  format_unformat_error, line_input);
527  goto done;
528  }
529  }
530 
531  if (index > vec_len (tm->frame_queue_mains) - 1)
532  {
533  error = clib_error_return (0,
534  "expecting valid worker handoff queue index");
535  goto done;
536  }
537 
538  fqm = vec_elt_at_index (tm->frame_queue_mains, index);
539 
540 
541  if (threshold == ~(u32) 0)
542  {
543  vlib_cli_output (vm, "expecting threshold value\n");
544  goto done;
545  }
546 
547  if (threshold == 0)
548  threshold = ~0;
549 
550  num_fq = vec_len (fqm->vlib_frame_queues);
551  if (num_fq == 0)
552  {
553  vlib_cli_output (vm, "No frame queues exist\n");
554  goto done;
555  }
556 
557  for (fqix = 0; fqix < num_fq; fqix++)
558  {
559  fqm->vlib_frame_queues[fqix]->vector_threshold = threshold;
560  }
561 
562 done:
563  unformat_free (line_input);
564 
565  return error;
566 }
567 
568 /* *INDENT-OFF* */
569 VLIB_CLI_COMMAND (cmd_test_frame_queue_threshold,static) = {
570  .path = "test frame-queue threshold",
571  .short_help = "test frame-queue threshold N (0=no limit)",
572  .function = test_frame_queue_threshold,
573 };
574 /* *INDENT-ON* */
575 
576 
577 /*
578  * fd.io coding-style-patch-verification: ON
579  *
580  * Local Variables:
581  * eval: (c-set-style "gnu")
582  * End:
583  */
static u32 compute_percent(u64 *two_counters, u64 total)
Definition: threads_cli.c:239
static u8 * format_sched_policy_and_priority(u8 *s, va_list *args)
Definition: threads_cli.c:24
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
format_function_t format_vlib_node_name
Definition: node_funcs.h:1103
#define NULL
Definition: clib.h:55
frame_queue_trace_t * frame_queue_traces
Definition: threads.h:149
static clib_error_t * show_frame_queue_trace(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: threads_cli.c:367
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:982
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:447
static clib_error_t * test_frame_queue_nelts(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: threads_cli.c:427
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u64 count[FRAME_QUEUE_MAX_NELTS]
Definition: node.h:717
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define clib_error_return(e, args...)
Definition: error.h:111
unsigned long u64
Definition: types.h:89
unformat_function_t unformat_line_input
Definition: format.h:281
vlib_worker_thread_t * vlib_worker_threads
Definition: threads.c:35
clib_error_t * vlib_sysfs_read(char *file_name, char *fmt,...)
Definition: util.c:126
struct _unformat_input_t unformat_input_t
#define FRAME_QUEUE_MAX_NELTS
Definition: node.h:701
static clib_error_t * show_frame_queue_internal(vlib_main_t *vm, vlib_frame_queue_main_t *fqm, u32 histogram)
Definition: threads_cli.c:256
i32 n_vectors[FRAME_QUEUE_MAX_NELTS]
Definition: node.h:712
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
svmdb_client_t * c
vlib_frame_queue_t ** vlib_frame_queues
Definition: threads.h:146
vlib_main_t * vm
Definition: buffer.c:276
static clib_error_t * show_threads_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: threads_cli.c:43
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:340
frame_queue_nelt_counter_t * frame_queue_histogram
Definition: threads.h:150
static clib_error_t * show_frame_queue_histogram(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: threads_cli.c:387
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
static clib_error_t * trace_frame_queue(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: threads_cli.c:140
unsigned int u32
Definition: types.h:88
vlib_frame_queue_main_t * frame_queue_mains
Definition: threads.h:314
static clib_error_t * test_frame_queue_threshold(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: threads_cli.c:502
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static vlib_thread_main_t * vlib_get_thread_main()
Definition: global_funcs.h:32
#define vec_foreach(var, vec)
Vector iterator.
#define foreach_sched_policy
Definition: threads.h:246
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
pthread_t thread_id
Definition: threads.h:108
vlib_thread_registration_t * registration
Definition: threads.h:102
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:577
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:971
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169