blob: f0cb69b34008a8c8b2047587a309b51ff87d7f91 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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 */
Christophe Fontainefef15b42016-04-09 12:38:49 +090015#define _GNU_SOURCE
Christophe Fontainefef15b42016-04-09 12:38:49 +090016
Ed Warnickecb9cada2015-12-08 15:45:58 -070017#include <signal.h>
18#include <math.h>
19#include <vppinfra/format.h>
Dave Barach19718002020-03-11 10:31:36 -040020#include <vppinfra/time_range.h>
Damjan Marion94100532020-11-06 23:25:57 +010021#include <vppinfra/interrupt.h>
Mohsin Kazmi5d64c782018-09-11 20:27:09 +020022#include <vppinfra/linux/sysfs.h>
Damjan Marion4b661402024-02-29 16:14:27 +010023#include <vppinfra/bitmap.h>
24#include <vppinfra/unix.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070025#include <vlib/vlib.h>
26
27#include <vlib/threads.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070028
Damjan Marion8973b072022-03-01 15:51:18 +010029#include <vlib/stats/stats.h>
Ole Troan233e4682019-05-16 15:01:34 +020030
Dave Barach9b8ffd92016-07-08 08:13:45 -040031u32
32vl (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -070033{
34 return vec_len (p);
35}
36
Damjan Marion6a7acc22016-12-19 16:28:36 +010037vlib_worker_thread_t *vlib_worker_threads;
Ed Warnickecb9cada2015-12-08 15:45:58 -070038vlib_thread_main_t vlib_thread_main;
39
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010040/*
41 * Barrier tracing can be enabled on a normal build to collect information
42 * on barrier use, including timings and call stacks. Deliberately not
43 * keyed off CLIB_DEBUG, because that can add significant overhead which
44 * imapacts observed timings.
45 */
46
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010047static inline void
48barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed)
49{
Dave Barach88c6e002018-09-30 15:54:06 -040050 if (!vlib_worker_threads->barrier_elog_enabled)
51 return;
52
Damjan Marion14361002021-03-11 12:17:33 +010053 ELOG_TYPE_DECLARE (e) = {
54 .format = "bar-trace-%s-#%d",
55 .format_args = "T4i4",
56 };
57
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010058 struct
59 {
Dave Barach88c6e002018-09-30 15:54:06 -040060 u32 caller, count, t_entry, t_open, t_closed;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010061 } *ed = 0;
62
63 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
64 ed->count = (int) vlib_worker_threads[0].barrier_sync_count;
Dave Barachb09f4d02019-07-15 16:00:03 -040065 ed->caller = elog_string (&vlib_global_main.elog_main,
66 (char *) vlib_worker_threads[0].barrier_caller);
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010067 ed->t_entry = (int) (1000000.0 * t_entry);
68 ed->t_open = (int) (1000000.0 * t_open);
69 ed->t_closed = (int) (1000000.0 * t_closed);
70}
71
72static inline void
73barrier_trace_sync_rec (f64 t_entry)
74{
Dave Barach88c6e002018-09-30 15:54:06 -040075 if (!vlib_worker_threads->barrier_elog_enabled)
76 return;
77
Damjan Marion14361002021-03-11 12:17:33 +010078 ELOG_TYPE_DECLARE (e) = {
79 .format = "bar-syncrec-%s-#%d",
80 .format_args = "T4i4",
81 };
82
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010083 struct
84 {
Dave Barach88c6e002018-09-30 15:54:06 -040085 u32 caller, depth;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010086 } *ed = 0;
87
88 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
89 ed->depth = (int) vlib_worker_threads[0].recursion_level - 1;
Dave Barachb09f4d02019-07-15 16:00:03 -040090 ed->caller = elog_string (&vlib_global_main.elog_main,
91 (char *) vlib_worker_threads[0].barrier_caller);
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010092}
93
94static inline void
95barrier_trace_release_rec (f64 t_entry)
96{
Dave Barach88c6e002018-09-30 15:54:06 -040097 if (!vlib_worker_threads->barrier_elog_enabled)
98 return;
99
Damjan Marion14361002021-03-11 12:17:33 +0100100 ELOG_TYPE_DECLARE (e) = {
101 .format = "bar-relrrec-#%d",
102 .format_args = "i4",
103 };
104
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100105 struct
106 {
Dave Barach88c6e002018-09-30 15:54:06 -0400107 u32 depth;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100108 } *ed = 0;
109
110 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100111 ed->depth = (int) vlib_worker_threads[0].recursion_level;
112}
113
114static inline void
115barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main)
116{
Dave Barach88c6e002018-09-30 15:54:06 -0400117 if (!vlib_worker_threads->barrier_elog_enabled)
118 return;
119
Damjan Marion14361002021-03-11 12:17:33 +0100120 ELOG_TYPE_DECLARE (e) = {
121 .format = "bar-rel-#%d-e%d-u%d-t%d",
122 .format_args = "i4i4i4i4",
123 };
124
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100125 struct
126 {
Dave Barach88c6e002018-09-30 15:54:06 -0400127 u32 count, t_entry, t_update_main, t_closed_total;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100128 } *ed = 0;
129
130 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
131 ed->t_entry = (int) (1000000.0 * t_entry);
132 ed->t_update_main = (int) (1000000.0 * t_update_main);
133 ed->t_closed_total = (int) (1000000.0 * t_closed_total);
134 ed->count = (int) vlib_worker_threads[0].barrier_sync_count;
135
136 /* Reset context for next trace */
137 vlib_worker_threads[0].barrier_context = NULL;
138}
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100139
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140uword
Damjan Marionf55f9b82017-05-10 21:06:28 +0200141os_get_nthreads (void)
Dave Barach01d86c72016-08-08 15:13:42 -0400142{
Dave Barach2180bac2019-05-10 15:25:10 -0400143 return vec_len (vlib_thread_stacks);
Dave Barach01d86c72016-08-08 15:13:42 -0400144}
145
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146void
147vlib_set_thread_name (char *name)
148{
149 int pthread_setname_np (pthread_t __target_thread, const char *__name);
Dave Barachb2a6e252016-07-27 10:00:58 -0400150 int rv;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400151 pthread_t thread = pthread_self ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153 if (thread)
Dave Barachb2a6e252016-07-27 10:00:58 -0400154 {
155 rv = pthread_setname_np (thread, name);
156 if (rv)
Ed Warnicke853e7202016-08-12 11:42:26 -0700157 clib_warning ("pthread_setname_np returned %d", rv);
Dave Barachb2a6e252016-07-27 10:00:58 -0400158 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159}
160
Dave Barach9b8ffd92016-07-08 08:13:45 -0400161static int
162sort_registrations_by_no_clone (void *a0, void *a1)
163{
164 vlib_thread_registration_t **tr0 = a0;
165 vlib_thread_registration_t **tr1 = a1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166
Dave Barach9b8ffd92016-07-08 08:13:45 -0400167 return ((i32) ((*tr0)->no_data_structure_clone)
168 - ((i32) ((*tr1)->no_data_structure_clone)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169}
170
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
172/* Called early in the init sequence */
173
174clib_error_t *
175vlib_thread_init (vlib_main_t * vm)
176{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400177 vlib_thread_main_t *tm = &vlib_thread_main;
178 vlib_worker_thread_t *w;
179 vlib_thread_registration_t *tr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180 u32 n_vlib_mains = 1;
181 u32 first_index = 1;
182 u32 i;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400183 uword *avail_cpu;
Damjan Marion8973b072022-03-01 15:51:18 +0100184 u32 stats_num_worker_threads_dir_index;
185
186 stats_num_worker_threads_dir_index =
187 vlib_stats_add_gauge ("/sys/num_worker_threads");
188 ASSERT (stats_num_worker_threads_dir_index != ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189
190 /* get bitmaps of active cpu cores and sockets */
Damjan Marion4b661402024-02-29 16:14:27 +0100191 tm->cpu_core_bitmap = os_get_online_cpu_core_bitmap ();
192 tm->cpu_socket_bitmap = os_get_online_cpu_node_bitmap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193
Dave Barach9b8ffd92016-07-08 08:13:45 -0400194 avail_cpu = clib_bitmap_dup (tm->cpu_core_bitmap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
196 /* skip cores */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400197 for (i = 0; i < tm->skip_cores; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400199 uword c = clib_bitmap_first_set (avail_cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 if (c == ~0)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400201 return clib_error_return (0, "no available cpus to skip");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202
Dave Barach9b8ffd92016-07-08 08:13:45 -0400203 avail_cpu = clib_bitmap_set (avail_cpu, c, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 }
205
206 /* grab cpu for main thread */
Benoît Ganne8b153de2021-12-09 18:24:21 +0100207 if (tm->main_lcore != ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400209 if (clib_bitmap_get (avail_cpu, tm->main_lcore) == 0)
210 return clib_error_return (0, "cpu %u is not available to be used"
211 " for the main thread", tm->main_lcore);
Benoît Ganne8b153de2021-12-09 18:24:21 +0100212 avail_cpu = clib_bitmap_set (avail_cpu, tm->main_lcore, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700213 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214
215 /* assume that there is socket 0 only if there is no data from sysfs */
216 if (!tm->cpu_socket_bitmap)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400217 tm->cpu_socket_bitmap = clib_bitmap_set (0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218
Christophe Fontainefef15b42016-04-09 12:38:49 +0900219 /* pin main thread to main_lcore */
Benoît Ganne8b153de2021-12-09 18:24:21 +0100220 if (tm->main_lcore != ~0)
221 {
222 cpu_set_t cpuset;
223 CPU_ZERO (&cpuset);
224 CPU_SET (tm->main_lcore, &cpuset);
hsandid832342e2023-12-20 15:41:54 +0100225 if (pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t),
226 &cpuset))
227 {
228 return clib_error_return (0, "could not pin main thread to cpu %u",
229 tm->main_lcore);
230 }
Benoît Ganne8b153de2021-12-09 18:24:21 +0100231 }
Christophe Fontainefef15b42016-04-09 12:38:49 +0900232
Dave Barach2180bac2019-05-10 15:25:10 -0400233 /* Set up thread 0 */
234 vec_validate_aligned (vlib_worker_threads, 0, CLIB_CACHE_LINE_BYTES);
Damjan Marion8bea5892022-04-04 22:40:45 +0200235 vec_set_len (vlib_worker_threads, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 w = vlib_worker_threads;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400237 w->thread_mheap = clib_mem_get_heap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238 w->thread_stack = vlib_thread_stacks[0];
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200239 w->cpu_id = tm->main_lcore;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400240 w->lwp = syscall (SYS_gettid);
Pavel Kotucek98765202016-10-07 08:37:28 +0200241 w->thread_id = pthread_self ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242 tm->n_vlib_mains = 1;
243
Jon Loeligerf617b142020-01-30 18:37:47 -0600244 vlib_get_thread_core_numa (w, w->cpu_id);
245
Pavel Kotucek1e765832016-09-23 08:54:14 +0200246 if (tm->sched_policy != ~0)
247 {
248 struct sched_param sched_param;
249 if (!sched_getparam (w->lwp, &sched_param))
250 {
251 if (tm->sched_priority != ~0)
252 sched_param.sched_priority = tm->sched_priority;
253 sched_setscheduler (w->lwp, tm->sched_policy, &sched_param);
254 }
255 }
256
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 /* assign threads to cores and set n_vlib_mains */
258 tr = tm->next;
259
260 while (tr)
261 {
262 vec_add1 (tm->registrations, tr);
263 tr = tr->next;
264 }
265
Dave Barach9b8ffd92016-07-08 08:13:45 -0400266 vec_sort_with_function (tm->registrations, sort_registrations_by_no_clone);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
268 for (i = 0; i < vec_len (tm->registrations); i++)
269 {
270 int j;
271 tr = tm->registrations[i];
272 tr->first_index = first_index;
273 first_index += tr->count;
274 n_vlib_mains += (tr->no_data_structure_clone == 0) ? tr->count : 0;
275
276 /* construct coremask */
277 if (tr->use_pthreads || !tr->count)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400278 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
280 if (tr->coremask)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400281 {
282 uword c;
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100283 clib_bitmap_foreach (c, tr->coremask) {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284 if (clib_bitmap_get(avail_cpu, c) == 0)
285 return clib_error_return (0, "cpu %u is not available to be used"
286 " for the '%s' thread",c, tr->name);
287
288 avail_cpu = clib_bitmap_set(avail_cpu, c, 0);
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100289 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400290 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400292 {
293 for (j = 0; j < tr->count; j++)
294 {
Vladimir Isaev2ed42042020-03-17 12:56:31 +0300295 /* Do not use CPU 0 by default - leave it to the host and IRQs */
296 uword avail_c0 = clib_bitmap_get (avail_cpu, 0);
297 avail_cpu = clib_bitmap_set (avail_cpu, 0, 0);
298
Dave Barach9b8ffd92016-07-08 08:13:45 -0400299 uword c = clib_bitmap_first_set (avail_cpu);
Vladimir Isaev2ed42042020-03-17 12:56:31 +0300300 /* Use CPU 0 as a last resort */
301 if (c == ~0 && avail_c0)
302 {
303 c = 0;
304 avail_c0 = 0;
305 }
306
Dave Barach9b8ffd92016-07-08 08:13:45 -0400307 if (c == ~0)
308 return clib_error_return (0,
309 "no available cpus to be used for"
hsandid832342e2023-12-20 15:41:54 +0100310 " the '%s' thread #%u",
311 tr->name, tr->count);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312
Vladimir Isaev2ed42042020-03-17 12:56:31 +0300313 avail_cpu = clib_bitmap_set (avail_cpu, 0, avail_c0);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400314 avail_cpu = clib_bitmap_set (avail_cpu, c, 0);
315 tr->coremask = clib_bitmap_set (tr->coremask, c, 1);
316 }
317 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 }
319
Dave Barach9b8ffd92016-07-08 08:13:45 -0400320 clib_bitmap_free (avail_cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700321
322 tm->n_vlib_mains = n_vlib_mains;
Damjan Marion8973b072022-03-01 15:51:18 +0100323 vlib_stats_set_gauge (stats_num_worker_threads_dir_index, n_vlib_mains - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324
Dave Barach2180bac2019-05-10 15:25:10 -0400325 /*
326 * Allocate the remaining worker threads, and thread stack vector slots
327 * from now on, calls to os_get_nthreads() will return the correct
328 * answer.
329 */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400330 vec_validate_aligned (vlib_worker_threads, first_index - 1,
331 CLIB_CACHE_LINE_BYTES);
Dave Barach2180bac2019-05-10 15:25:10 -0400332 vec_validate (vlib_thread_stacks, vec_len (vlib_worker_threads) - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333 return 0;
334}
335
Dave Barach9b8ffd92016-07-08 08:13:45 -0400336vlib_frame_queue_t *
337vlib_frame_queue_alloc (int nelts)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400339 vlib_frame_queue_t *fq;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
Dave Barach9b8ffd92016-07-08 08:13:45 -0400341 fq = clib_mem_alloc_aligned (sizeof (*fq), CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400342 clib_memset (fq, 0, sizeof (*fq));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 fq->nelts = nelts;
Damjan Marionc0d9ca72021-05-11 09:39:24 +0200344 fq->vector_threshold = 2 * VLIB_FRAME_SIZE;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400345 vec_validate_aligned (fq->elts, nelts - 1, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346
Damjan Marionc0d9ca72021-05-11 09:39:24 +0200347 if (nelts & (nelts - 1))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400348 {
Damjan Marionc0d9ca72021-05-11 09:39:24 +0200349 fformat (stderr, "FATAL: nelts MUST be a power of 2\n");
350 abort ();
Dave Barach9b8ffd92016-07-08 08:13:45 -0400351 }
352
Ed Warnickecb9cada2015-12-08 15:45:58 -0700353 return (fq);
354}
355
356void vl_msg_api_handler_no_free (void *) __attribute__ ((weak));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400357void
358vl_msg_api_handler_no_free (void *v)
359{
360}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700361
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362/* To be called by vlib worker threads upon startup */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400363void
364vlib_worker_thread_init (vlib_worker_thread_t * w)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400366 vlib_thread_main_t *tm = vlib_get_thread_main ();
367
Dave Barachfdf49442016-12-20 12:48:14 -0500368 /*
369 * Note: disabling signals in worker threads as follows
370 * prevents the api post-mortem dump scheme from working
371 * {
372 * sigset_t s;
373 * sigfillset (&s);
374 * pthread_sigmask (SIG_SETMASK, &s, 0);
375 * }
376 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377
378 clib_mem_set_heap (w->thread_mheap);
379
Dave Barach9b8ffd92016-07-08 08:13:45 -0400380 if (vec_len (tm->thread_prefix) && w->registration->short_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400382 w->name = format (0, "%v_%s_%d%c", tm->thread_prefix,
383 w->registration->short_name, w->instance_id, '\0');
384 vlib_set_thread_name ((char *) w->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700385 }
386
387 if (!w->registration->use_pthreads)
388 {
389
390 /* Initial barrier sync, for both worker and i/o threads */
Sirshak Das2f6d7bb2018-10-03 22:53:51 +0000391 clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392
393 while (*vlib_worker_threads->wait_at_barrier)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400394 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700395
Sirshak Das2f6d7bb2018-10-03 22:53:51 +0000396 clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, -1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397 }
398}
399
Dave Barach9b8ffd92016-07-08 08:13:45 -0400400void *
401vlib_worker_thread_bootstrap_fn (void *arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403 vlib_worker_thread_t *w = arg;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400404
405 w->lwp = syscall (SYS_gettid);
Pavel Kotucek98765202016-10-07 08:37:28 +0200406 w->thread_id = pthread_self ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407
Damjan Marionf55f9b82017-05-10 21:06:28 +0200408 __os_thread_index = w - vlib_worker_threads;
Damjan Marion586afd72017-04-05 19:18:20 +0200409
Damjan Marion7bf23172022-03-28 01:47:33 +0200410 if (CLIB_DEBUG > 0)
411 {
412 void *frame_addr = __builtin_frame_address (0);
413 if (frame_addr < (void *) w->thread_stack ||
414 frame_addr > (void *) w->thread_stack + VLIB_THREAD_STACK_SIZE)
415 {
416 /* heap is not set yet */
417 fprintf (stderr, "thread stack is not set properly\n");
418 exit (1);
419 }
420 }
Dave Barach37579c32021-07-27 09:27:07 -0400421
Damjan Marion7bf23172022-03-28 01:47:33 +0200422 w->thread_function (arg);
423
424 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425}
426
Dave Baracha690fdb2020-01-21 12:34:55 -0500427void
428vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id)
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200429{
430 const char *sys_cpu_path = "/sys/devices/system/cpu/cpu";
Lijian.Zhang4fbb9da2020-02-14 15:16:49 +0800431 const char *sys_node_path = "/sys/devices/system/node/node";
432 clib_bitmap_t *nbmp = 0, *cbmp = 0;
433 u32 node;
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200434 u8 *p = 0;
Dave Baracha690fdb2020-01-21 12:34:55 -0500435 int core_id = -1, numa_id = -1;
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200436
437 p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, cpu_id, 0);
438 clib_sysfs_read ((char *) p, "%d", &core_id);
439 vec_reset_length (p);
Lijian.Zhang4fbb9da2020-02-14 15:16:49 +0800440
Damjan Marion4b661402024-02-29 16:14:27 +0100441 nbmp = os_get_online_cpu_node_bitmap ();
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100442 clib_bitmap_foreach (node, nbmp) {
Lijian.Zhang4fbb9da2020-02-14 15:16:49 +0800443 p = format (p, "%s%u/cpulist%c", sys_node_path, node, 0);
444 clib_sysfs_read ((char *) p, "%U", unformat_bitmap_list, &cbmp);
445 if (clib_bitmap_get (cbmp, cpu_id))
446 numa_id = node;
447 vec_reset_length (cbmp);
448 vec_reset_length (p);
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100449 }
Damjan Marion4b661402024-02-29 16:14:27 +0100450
Lijian.Zhang4fbb9da2020-02-14 15:16:49 +0800451 vec_free (nbmp);
452 vec_free (cbmp);
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200453 vec_free (p);
454
455 w->core_id = core_id;
Dave Baracha690fdb2020-01-21 12:34:55 -0500456 w->numa_id = numa_id;
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200457}
458
Damjan Marion878c6092017-01-04 13:19:27 +0100459static clib_error_t *
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200460vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461{
Damjan Marion57d1ec02020-09-16 21:15:44 +0200462 clib_mem_main_t *mm = &clib_mem_main;
Damjan Marion878c6092017-01-04 13:19:27 +0100463 vlib_thread_main_t *tm = &vlib_thread_main;
Damjan Mariona2b7a022021-12-28 20:32:20 +0100464 pthread_t worker;
Damjan Marion7bf23172022-03-28 01:47:33 +0200465 pthread_attr_t attr;
Damjan Mariona2b7a022021-12-28 20:32:20 +0100466 cpu_set_t cpuset;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400467 void *(*fp_arg) (void *) = fp;
Dave Baracha690fdb2020-01-21 12:34:55 -0500468 void *numa_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200470 w->cpu_id = cpu_id;
Dave Baracha690fdb2020-01-21 12:34:55 -0500471 vlib_get_thread_core_numa (w, cpu_id);
Dave Baracha690fdb2020-01-21 12:34:55 -0500472
473 /* Set up NUMA-bound heap if indicated */
Damjan Marion57d1ec02020-09-16 21:15:44 +0200474 if (mm->per_numa_mheaps[w->numa_id] == 0)
Dave Baracha690fdb2020-01-21 12:34:55 -0500475 {
476 /* If the user requested a NUMA heap, create it... */
477 if (tm->numa_heap_size)
478 {
Damjan Marion2bc1af52020-10-02 15:01:12 +0200479 clib_mem_set_numa_affinity (w->numa_id, 1 /* force */ );
480 numa_heap = clib_mem_create_heap (0 /* DIY */ , tm->numa_heap_size,
481 1 /* is_locked */ ,
482 "numa %u heap", w->numa_id);
483 clib_mem_set_default_numa_affinity ();
Damjan Marion57d1ec02020-09-16 21:15:44 +0200484 mm->per_numa_mheaps[w->numa_id] = numa_heap;
Dave Baracha690fdb2020-01-21 12:34:55 -0500485 }
486 else
487 {
488 /* Or, use the main heap */
Damjan Marion57d1ec02020-09-16 21:15:44 +0200489 mm->per_numa_mheaps[w->numa_id] = w->thread_mheap;
Dave Baracha690fdb2020-01-21 12:34:55 -0500490 }
491 }
492
Dave Barach9b8ffd92016-07-08 08:13:45 -0400493 CPU_ZERO (&cpuset);
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200494 CPU_SET (cpu_id, &cpuset);
Christophe Fontainefef15b42016-04-09 12:38:49 +0900495
Damjan Marion7bf23172022-03-28 01:47:33 +0200496 if (pthread_attr_init (&attr))
497 return clib_error_return_unix (0, "pthread_attr_init");
498
499 if (pthread_attr_setstack (&attr, w->thread_stack,
500 VLIB_THREAD_STACK_SIZE))
501 return clib_error_return_unix (0, "pthread_attr_setstack");
502
503 if (pthread_create (&worker, &attr, fp_arg, (void *) w))
Damjan Marion878c6092017-01-04 13:19:27 +0100504 return clib_error_return_unix (0, "pthread_create");
505
506 if (pthread_setaffinity_np (worker, sizeof (cpu_set_t), &cpuset))
507 return clib_error_return_unix (0, "pthread_setaffinity_np");
508
Damjan Marion7bf23172022-03-28 01:47:33 +0200509 if (pthread_attr_destroy (&attr))
510 return clib_error_return_unix (0, "pthread_attr_destroy");
511
Damjan Marion878c6092017-01-04 13:19:27 +0100512 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700513}
514
Dave Barach9b8ffd92016-07-08 08:13:45 -0400515static clib_error_t *
516start_workers (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517{
Damjan Marionfd8deb42021-03-06 12:26:28 +0100518 vlib_global_main_t *vgm = vlib_get_global_main ();
Damjan Marion66c85832022-03-14 13:04:38 +0100519 vlib_main_t *fvm = vlib_get_first_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520 int i, j;
521 vlib_worker_thread_t *w;
522 vlib_main_t *vm_clone;
523 void *oldheap;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400524 vlib_thread_main_t *tm = &vlib_thread_main;
525 vlib_thread_registration_t *tr;
526 vlib_node_runtime_t *rt;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700527 u32 n_vlib_mains = tm->n_vlib_mains;
528 u32 worker_thread_index;
Damjan Marion66c85832022-03-14 13:04:38 +0100529 u32 stats_err_entry_index = fvm->error_main.stats_err_entry_index;
Damjan Marionbfa75d62020-10-06 17:46:06 +0200530 clib_mem_heap_t *main_heap = clib_mem_get_per_cpu_heap ();
Ole Troana606d922021-05-05 09:23:17 +0200531 vlib_stats_register_mem_heap (main_heap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400532
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533 vec_reset_length (vlib_worker_threads);
534
535 /* Set up the main thread */
536 vec_add2_aligned (vlib_worker_threads, w, 1, CLIB_CACHE_LINE_BYTES);
Dave Barach3e7deb12016-02-05 16:29:53 -0500537 w->elog_track.name = "main thread";
Damjan Marionf553a2c2021-03-26 13:45:37 +0100538 elog_track_register (vlib_get_elog_main (), &w->elog_track);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539
Dave Barach9b8ffd92016-07-08 08:13:45 -0400540 if (vec_len (tm->thread_prefix))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700541 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400542 w->name = format (0, "%v_main%c", tm->thread_prefix, '\0');
543 vlib_set_thread_name ((char *) w->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544 }
545
Damjan Marionfd8deb42021-03-06 12:26:28 +0100546 vgm->elog_main.lock =
Dave Barach9b8ffd92016-07-08 08:13:45 -0400547 clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100548 vgm->elog_main.lock[0] = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400549
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000550 clib_callback_data_init (&vm->vlib_node_runtime_perf_callbacks,
551 &vm->worker_thread_main_loop_callback_lock);
552
Damjan Marionfd8deb42021-03-06 12:26:28 +0100553 vec_validate_aligned (vgm->vlib_mains, n_vlib_mains - 1,
554 CLIB_CACHE_LINE_BYTES);
Damjan Marion8bea5892022-04-04 22:40:45 +0200555 vec_set_len (vgm->vlib_mains, 0);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100556 vec_add1_aligned (vgm->vlib_mains, vm, CLIB_CACHE_LINE_BYTES);
Dave Barach1c556d12020-10-02 11:35:44 -0400557
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 if (n_vlib_mains > 1)
559 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400560 vlib_worker_threads->wait_at_barrier =
561 clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700562 vlib_worker_threads->workers_at_barrier =
Dave Barach9b8ffd92016-07-08 08:13:45 -0400563 clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100565 vlib_worker_threads->node_reforks_required =
566 clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
567
Dave Barachf6c68d72018-11-01 08:12:52 -0400568 /* We'll need the rpc vector lock... */
569 clib_spinlock_init (&vm->pending_rpc_lock);
570
Ed Warnickecb9cada2015-12-08 15:45:58 -0700571 /* Ask for an initial barrier sync */
572 *vlib_worker_threads->workers_at_barrier = 0;
573 *vlib_worker_threads->wait_at_barrier = 1;
574
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100575 /* Without update or refork */
576 *vlib_worker_threads->node_reforks_required = 0;
Damjan Marionfd8deb42021-03-06 12:26:28 +0100577 vgm->need_vlib_worker_thread_node_runtime_update = 0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100578
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100579 /* init timing */
580 vm->barrier_epoch = 0;
581 vm->barrier_no_close_before = 0;
582
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583 worker_thread_index = 1;
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000584 clib_spinlock_init (&vm->worker_thread_main_loop_callback_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700585
Dave Barach9b8ffd92016-07-08 08:13:45 -0400586 for (i = 0; i < vec_len (tm->registrations); i++)
587 {
588 vlib_node_main_t *nm, *nm_clone;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400589 int k;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590
Dave Barach9b8ffd92016-07-08 08:13:45 -0400591 tr = tm->registrations[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592
Dave Barach9b8ffd92016-07-08 08:13:45 -0400593 if (tr->count == 0)
594 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595
Dave Barach9b8ffd92016-07-08 08:13:45 -0400596 for (k = 0; k < tr->count; k++)
597 {
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100598 vlib_node_t *n;
Damjan Marion66c85832022-03-14 13:04:38 +0100599 u64 **c;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100600
Dave Barach9b8ffd92016-07-08 08:13:45 -0400601 vec_add2 (vlib_worker_threads, w, 1);
Dave Barach6a5adc32018-07-04 10:56:23 -0400602 /* Currently unused, may not really work */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400603 if (tr->mheap_size)
Damjan Marion4537c302020-09-28 19:03:37 +0200604 w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size,
605 /* unlocked */ 0,
606 "%s%d heap",
607 tr->name, k);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400608 else
609 w->thread_mheap = main_heap;
Damjan Marion586afd72017-04-05 19:18:20 +0200610
611 w->thread_stack =
612 vlib_thread_stack_init (w - vlib_worker_threads);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400613 w->thread_function = tr->function;
614 w->thread_function_arg = w;
615 w->instance_id = k;
616 w->registration = tr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700617
Dave Barach9b8ffd92016-07-08 08:13:45 -0400618 w->elog_track.name =
619 (char *) format (0, "%s %d", tr->name, k + 1);
620 vec_add1 (w->elog_track.name, 0);
Damjan Marionf553a2c2021-03-26 13:45:37 +0100621 elog_track_register (vlib_get_elog_main (), &w->elog_track);
Bud Grise68adab92016-02-12 10:36:11 -0500622
Dave Barach9b8ffd92016-07-08 08:13:45 -0400623 if (tr->no_data_structure_clone)
624 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700625
Dave Barach9b8ffd92016-07-08 08:13:45 -0400626 /* Fork vlib_global_main et al. Look for bugs here */
627 oldheap = clib_mem_set_heap (w->thread_mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200629 vm_clone = clib_mem_alloc_aligned (sizeof (*vm_clone),
630 CLIB_CACHE_LINE_BYTES);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100631 clib_memcpy (vm_clone, vlib_get_first_main (),
632 sizeof (*vm_clone));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633
Damjan Marion586afd72017-04-05 19:18:20 +0200634 vm_clone->thread_index = worker_thread_index;
Dave Barach2877eee2017-12-15 12:22:57 -0500635 vm_clone->pending_rpc_requests = 0;
636 vec_validate (vm_clone->pending_rpc_requests, 0);
Damjan Marion8bea5892022-04-04 22:40:45 +0200637 vec_set_len (vm_clone->pending_rpc_requests, 0);
Dave Barachb7b92992018-10-17 10:38:51 -0400638 clib_memset (&vm_clone->random_buffer, 0,
639 sizeof (vm_clone->random_buffer));
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000640 clib_spinlock_init
641 (&vm_clone->worker_thread_main_loop_callback_lock);
642 clib_callback_data_init
643 (&vm_clone->vlib_node_runtime_perf_callbacks,
644 &vm_clone->worker_thread_main_loop_callback_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700645
Damjan Marionfd8deb42021-03-06 12:26:28 +0100646 nm = &vlib_get_first_main ()->node_main;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400647 nm_clone = &vm_clone->node_main;
648 /* fork next frames array, preserving node runtime indices */
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200649 nm_clone->next_frames = vec_dup_aligned (nm->next_frames,
650 CLIB_CACHE_LINE_BYTES);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400651 for (j = 0; j < vec_len (nm_clone->next_frames); j++)
652 {
653 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
654 u32 save_node_runtime_index;
655 u32 save_flags;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656
Dave Barach9b8ffd92016-07-08 08:13:45 -0400657 save_node_runtime_index = nf->node_runtime_index;
658 save_flags = nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
659 vlib_next_frame_init (nf);
660 nf->node_runtime_index = save_node_runtime_index;
661 nf->flags = save_flags;
662 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663
Dave Barach9b8ffd92016-07-08 08:13:45 -0400664 /* fork the frame dispatch queue */
665 nm_clone->pending_frames = 0;
Dave Barach53fe4a72019-01-26 09:50:26 -0500666 vec_validate (nm_clone->pending_frames, 10);
Damjan Marion8bea5892022-04-04 22:40:45 +0200667 vec_set_len (nm_clone->pending_frames, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700668
Dave Barach9b8ffd92016-07-08 08:13:45 -0400669 /* fork nodes */
670 nm_clone->nodes = 0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100671
672 /* Allocate all nodes in single block for speed */
673 n = clib_mem_alloc_no_fail (vec_len (nm->nodes) * sizeof (*n));
674
Dave Barach9b8ffd92016-07-08 08:13:45 -0400675 for (j = 0; j < vec_len (nm->nodes); j++)
676 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400677 clib_memcpy (n, nm->nodes[j], sizeof (*n));
678 /* none of the copied nodes have enqueue rights given out */
679 n->owner_node_index = VLIB_INVALID_NODE_INDEX;
Dave Barachb7b92992018-10-17 10:38:51 -0400680 clib_memset (&n->stats_total, 0, sizeof (n->stats_total));
681 clib_memset (&n->stats_last_clear, 0,
682 sizeof (n->stats_last_clear));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400683 vec_add1 (nm_clone->nodes, n);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100684 n++;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400685 }
686 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200687 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
688 CLIB_CACHE_LINE_BYTES);
JingLiuZTE30af5da2017-07-24 10:53:31 +0800689 vec_foreach (rt,
690 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL])
Damjan Marione9f929b2017-03-16 11:32:09 +0100691 {
692 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Damjan Marione9f929b2017-03-16 11:32:09 +0100693 /* copy initial runtime_data from node */
Damjan Marionb6f93a12017-03-16 17:46:41 +0100694 if (n->runtime_data && n->runtime_data_bytes > 0)
Damjan Marione9f929b2017-03-16 11:32:09 +0100695 clib_memcpy (rt->runtime_data, n->runtime_data,
Damjan Marionb6f93a12017-03-16 17:46:41 +0100696 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
697 n->runtime_data_bytes));
Damjan Marione9f929b2017-03-16 11:32:09 +0100698 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700699
Dave Barach9b8ffd92016-07-08 08:13:45 -0400700 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200701 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
702 CLIB_CACHE_LINE_BYTES);
Damjan Marion94100532020-11-06 23:25:57 +0100703 clib_interrupt_init (
Damjan Marioncc8249c2023-07-23 14:24:22 +0200704 &nm_clone->input_node_interrupts,
Damjan Marion94100532020-11-06 23:25:57 +0100705 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]));
Damjan Marioncc8249c2023-07-23 14:24:22 +0200706 clib_interrupt_init (
707 &nm_clone->pre_input_node_interrupts,
708 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT]));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400709 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])
Damjan Marione9f929b2017-03-16 11:32:09 +0100710 {
711 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Damjan Marione9f929b2017-03-16 11:32:09 +0100712 /* copy initial runtime_data from node */
Damjan Marionb6f93a12017-03-16 17:46:41 +0100713 if (n->runtime_data && n->runtime_data_bytes > 0)
Damjan Marione9f929b2017-03-16 11:32:09 +0100714 clib_memcpy (rt->runtime_data, n->runtime_data,
Damjan Marionb6f93a12017-03-16 17:46:41 +0100715 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
716 n->runtime_data_bytes));
Damjan Marione9f929b2017-03-16 11:32:09 +0100717 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718
Dave Barach53fe4a72019-01-26 09:50:26 -0500719 nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT] =
720 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT],
721 CLIB_CACHE_LINE_BYTES);
722 vec_foreach (rt,
723 nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT])
724 {
725 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Dave Barach53fe4a72019-01-26 09:50:26 -0500726 /* copy initial runtime_data from node */
727 if (n->runtime_data && n->runtime_data_bytes > 0)
728 clib_memcpy (rt->runtime_data, n->runtime_data,
729 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
730 n->runtime_data_bytes));
731 }
732
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200733 nm_clone->processes = vec_dup_aligned (nm->processes,
734 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735
Dave Barach593eedf2019-03-10 09:44:51 -0400736 /* Create per-thread frame freelist */
Damjan Marionb32bd702021-12-23 17:05:02 +0100737 nm_clone->frame_sizes = 0;
Dave Barach687c9022019-07-23 10:22:31 -0400738 nm_clone->node_by_error = nm->node_by_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739
Dave Barach9b8ffd92016-07-08 08:13:45 -0400740 /* Packet trace buffers are guaranteed to be empty, nothing to do here */
Damjan Marionbc20bdf2015-12-17 14:28:18 +0100741
Dave Barach9b8ffd92016-07-08 08:13:45 -0400742 clib_mem_set_heap (oldheap);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100743 vec_add1_aligned (vgm->vlib_mains, vm_clone,
744 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745
Ole Troan233e4682019-05-16 15:01:34 +0200746 /* Switch to the stats segment ... */
Damjan Marion66c85832022-03-14 13:04:38 +0100747 vlib_stats_validate (stats_err_entry_index, worker_thread_index,
748 vec_len (fvm->error_main.counters) - 1);
749 c = vlib_stats_get_entry_data_pointer (stats_err_entry_index);
750 vm_clone->error_main.counters = c[worker_thread_index];
Ole Troan233e4682019-05-16 15:01:34 +0200751
Damjan Marionfd8deb42021-03-06 12:26:28 +0100752 vm_clone->error_main.counters_last_clear = vec_dup_aligned (
753 vlib_get_first_main ()->error_main.counters_last_clear,
754 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755
Dave Barach9b8ffd92016-07-08 08:13:45 -0400756 worker_thread_index++;
757 }
758 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700759 }
760 else
761 {
762 /* only have non-data-structure copy threads to create... */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400763 for (i = 0; i < vec_len (tm->registrations); i++)
764 {
765 tr = tm->registrations[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700766
Dave Barach9b8ffd92016-07-08 08:13:45 -0400767 for (j = 0; j < tr->count; j++)
768 {
769 vec_add2 (vlib_worker_threads, w, 1);
770 if (tr->mheap_size)
Dave Barach6a5adc32018-07-04 10:56:23 -0400771 {
Damjan Marion4537c302020-09-28 19:03:37 +0200772 w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size,
773 /* locked */ 0,
774 "%s%d heap",
775 tr->name, j);
Dave Barach6a5adc32018-07-04 10:56:23 -0400776 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400777 else
778 w->thread_mheap = main_heap;
Damjan Marion586afd72017-04-05 19:18:20 +0200779 w->thread_stack =
780 vlib_thread_stack_init (w - vlib_worker_threads);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400781 w->thread_function = tr->function;
782 w->thread_function_arg = w;
783 w->instance_id = j;
784 w->elog_track.name =
785 (char *) format (0, "%s %d", tr->name, j + 1);
786 w->registration = tr;
787 vec_add1 (w->elog_track.name, 0);
Damjan Marionf553a2c2021-03-26 13:45:37 +0100788 elog_track_register (vlib_get_elog_main (), &w->elog_track);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400789 }
790 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700791 }
792
793 worker_thread_index = 1;
794
795 for (i = 0; i < vec_len (tm->registrations); i++)
796 {
Damjan Marion878c6092017-01-04 13:19:27 +0100797 clib_error_t *err;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798 int j;
799
800 tr = tm->registrations[i];
801
802 if (tr->use_pthreads || tm->use_pthreads)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400803 {
804 for (j = 0; j < tr->count; j++)
805 {
hsandid832342e2023-12-20 15:41:54 +0100806
Dave Barach9b8ffd92016-07-08 08:13:45 -0400807 w = vlib_worker_threads + worker_thread_index++;
Damjan Marion878c6092017-01-04 13:19:27 +0100808 err = vlib_launch_thread_int (vlib_worker_thread_bootstrap_fn,
809 w, 0);
810 if (err)
hsandid832342e2023-12-20 15:41:54 +0100811 clib_unix_error ("%U, thread %s init on cpu %d failed",
812 format_clib_error, err, tr->name, 0);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400813 }
814 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400816 {
817 uword c;
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100818 clib_bitmap_foreach (c, tr->coremask) {
Damjan Marion878c6092017-01-04 13:19:27 +0100819 w = vlib_worker_threads + worker_thread_index++;
820 err = vlib_launch_thread_int (vlib_worker_thread_bootstrap_fn,
821 w, c);
822 if (err)
hsandid832342e2023-12-20 15:41:54 +0100823 clib_unix_error ("%U, thread %s init on cpu %d failed",
824 format_clib_error, err, tr->name, c);
825 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400826 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700827 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400828 vlib_worker_thread_barrier_sync (vm);
Damjan Marion321bd102022-06-01 00:45:18 +0200829 {
830 clib_error_t *err;
831 err = vlib_call_init_exit_functions (
832 vm, &vgm->num_workers_change_function_registrations, 1 /* call_once */,
833 1 /* is_global */);
834 if (err)
835 clib_error_report (err);
836 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400837 vlib_worker_thread_barrier_release (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838 return 0;
839}
840
841VLIB_MAIN_LOOP_ENTER_FUNCTION (start_workers);
842
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100843
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100844static inline void
845worker_thread_node_runtime_update_internal (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700846{
847 int i, j;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700848 vlib_main_t *vm;
849 vlib_node_main_t *nm, *nm_clone;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700850 vlib_main_t *vm_clone;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100851 vlib_node_runtime_t *rt;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400852
Damjan Marion586afd72017-04-05 19:18:20 +0200853 ASSERT (vlib_get_thread_index () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700854
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100855 vm = vlib_get_first_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856 nm = &vm->node_main;
857
Ed Warnickecb9cada2015-12-08 15:45:58 -0700858 ASSERT (*vlib_worker_threads->wait_at_barrier == 1);
859
Dave Barach9b8ffd92016-07-08 08:13:45 -0400860 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700861 * Scrape all runtime stats, so we don't lose node runtime(s) with
862 * pending counts, or throw away worker / io thread counts.
863 */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400864 for (j = 0; j < vec_len (nm->nodes); j++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400866 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700867 n = nm->nodes[j];
868 vlib_node_sync_stats (vm, n);
869 }
870
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100871 for (i = 1; i < vlib_get_n_threads (); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400873 vlib_node_t *n;
874
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100875 vm_clone = vlib_get_main_by_index (i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700876 nm_clone = &vm_clone->node_main;
877
Dave Barach9b8ffd92016-07-08 08:13:45 -0400878 for (j = 0; j < vec_len (nm_clone->nodes); j++)
879 {
880 n = nm_clone->nodes[j];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881
Dave Barach9b8ffd92016-07-08 08:13:45 -0400882 rt = vlib_node_get_runtime (vm_clone, n->index);
883 vlib_node_runtime_sync_stats (vm_clone, rt, 0, 0, 0);
884 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885 }
886
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100887 /* Per-worker clone rebuilds are now done on each thread */
888}
889
890
891void
892vlib_worker_thread_node_refork (void)
893{
894 vlib_main_t *vm, *vm_clone;
895 vlib_node_main_t *nm, *nm_clone;
896 vlib_node_t **old_nodes_clone;
897 vlib_node_runtime_t *rt, *old_rt;
Damjan Marion66c85832022-03-14 13:04:38 +0100898 u64 **c;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100899
900 vlib_node_t *new_n_clone;
901
902 int j;
903
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100904 vm = vlib_get_first_main ();
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100905 nm = &vm->node_main;
906 vm_clone = vlib_get_main ();
907 nm_clone = &vm_clone->node_main;
908
909 /* Re-clone error heap */
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100910 u64 *old_counters_all_clear = vm_clone->error_main.counters_last_clear;
911
Dave Barach178cf492018-11-13 16:34:13 -0500912 clib_memcpy_fast (&vm_clone->error_main, &vm->error_main,
913 sizeof (vm->error_main));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100914 j = vec_len (vm->error_main.counters) - 1;
Ole Troan233e4682019-05-16 15:01:34 +0200915
Damjan Marion66c85832022-03-14 13:04:38 +0100916 c = vlib_stats_get_entry_data_pointer (vm->error_main.stats_err_entry_index);
917 vm_clone->error_main.counters = c[vm_clone->thread_index];
Ole Troan233e4682019-05-16 15:01:34 +0200918
919 vec_validate_aligned (old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100920 vm_clone->error_main.counters_last_clear = old_counters_all_clear;
921
Dmitry Valter9f5b3692022-09-05 15:30:18 +0000922 for (j = 0; j < vec_len (nm_clone->next_frames); j++)
923 {
924 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
925 if ((nf->flags & VLIB_FRAME_IS_ALLOCATED) && nf->frame != NULL)
926 {
927 vlib_frame_t *f = nf->frame;
928 nf->frame = NULL;
929 vlib_frame_free (vm_clone, f);
930 }
931 }
932
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100933 vec_free (nm_clone->next_frames);
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200934 nm_clone->next_frames = vec_dup_aligned (nm->next_frames,
935 CLIB_CACHE_LINE_BYTES);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100936
937 for (j = 0; j < vec_len (nm_clone->next_frames); j++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938 {
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100939 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
940 u32 save_node_runtime_index;
941 u32 save_flags;
Damjan Marionbc20bdf2015-12-17 14:28:18 +0100942
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100943 save_node_runtime_index = nf->node_runtime_index;
944 save_flags = nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
945 vlib_next_frame_init (nf);
946 nf->node_runtime_index = save_node_runtime_index;
947 nf->flags = save_flags;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948 }
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100949
950 old_nodes_clone = nm_clone->nodes;
951 nm_clone->nodes = 0;
952
953 /* re-fork nodes */
954
955 /* Allocate all nodes in single block for speed */
956 new_n_clone =
957 clib_mem_alloc_no_fail (vec_len (nm->nodes) * sizeof (*new_n_clone));
958 for (j = 0; j < vec_len (nm->nodes); j++)
959 {
Benoît Ganne5517bd32019-08-30 16:20:12 +0200960 vlib_node_t *new_n = nm->nodes[j];
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100961
Dave Barach178cf492018-11-13 16:34:13 -0500962 clib_memcpy_fast (new_n_clone, new_n, sizeof (*new_n));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100963 /* none of the copied nodes have enqueue rights given out */
964 new_n_clone->owner_node_index = VLIB_INVALID_NODE_INDEX;
965
966 if (j >= vec_len (old_nodes_clone))
967 {
968 /* new node, set to zero */
Dave Barachb7b92992018-10-17 10:38:51 -0400969 clib_memset (&new_n_clone->stats_total, 0,
970 sizeof (new_n_clone->stats_total));
971 clib_memset (&new_n_clone->stats_last_clear, 0,
972 sizeof (new_n_clone->stats_last_clear));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100973 }
974 else
975 {
Benoît Ganne5517bd32019-08-30 16:20:12 +0200976 vlib_node_t *old_n_clone = old_nodes_clone[j];
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100977 /* Copy stats if the old data is valid */
Dave Barach178cf492018-11-13 16:34:13 -0500978 clib_memcpy_fast (&new_n_clone->stats_total,
979 &old_n_clone->stats_total,
980 sizeof (new_n_clone->stats_total));
981 clib_memcpy_fast (&new_n_clone->stats_last_clear,
982 &old_n_clone->stats_last_clear,
983 sizeof (new_n_clone->stats_last_clear));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100984
985 /* keep previous node state */
986 new_n_clone->state = old_n_clone->state;
Maxime Peimdde163d2021-04-15 13:52:12 +0200987 new_n_clone->flags = old_n_clone->flags;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100988 }
989 vec_add1 (nm_clone->nodes, new_n_clone);
990 new_n_clone++;
991 }
992 /* Free the old node clones */
993 clib_mem_free (old_nodes_clone[0]);
994
995 vec_free (old_nodes_clone);
996
997
998 /* re-clone internal nodes */
999 old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL];
1000 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +02001001 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
1002 CLIB_CACHE_LINE_BYTES);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001003
1004 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL])
1005 {
1006 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001007 /* copy runtime_data, will be overwritten later for existing rt */
1008 if (n->runtime_data && n->runtime_data_bytes > 0)
Dave Barach178cf492018-11-13 16:34:13 -05001009 clib_memcpy_fast (rt->runtime_data, n->runtime_data,
1010 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
1011 n->runtime_data_bytes));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001012 }
1013
1014 for (j = 0; j < vec_len (old_rt); j++)
1015 {
1016 rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index);
1017 rt->state = old_rt[j].state;
Maxime Peimdde163d2021-04-15 13:52:12 +02001018 rt->flags = old_rt[j].flags;
Dave Barach178cf492018-11-13 16:34:13 -05001019 clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data,
1020 VLIB_NODE_RUNTIME_DATA_SIZE);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001021 }
1022
1023 vec_free (old_rt);
1024
1025 /* re-clone input nodes */
1026 old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT];
1027 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +02001028 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
1029 CLIB_CACHE_LINE_BYTES);
Damjan Marion94100532020-11-06 23:25:57 +01001030 clib_interrupt_resize (
Damjan Marioncc8249c2023-07-23 14:24:22 +02001031 &nm_clone->input_node_interrupts,
Damjan Marion94100532020-11-06 23:25:57 +01001032 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]));
Damjan Marioncc8249c2023-07-23 14:24:22 +02001033 clib_interrupt_resize (
1034 &nm_clone->pre_input_node_interrupts,
1035 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT]));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001036
1037 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])
1038 {
1039 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001040 /* copy runtime_data, will be overwritten later for existing rt */
1041 if (n->runtime_data && n->runtime_data_bytes > 0)
Dave Barach178cf492018-11-13 16:34:13 -05001042 clib_memcpy_fast (rt->runtime_data, n->runtime_data,
1043 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
1044 n->runtime_data_bytes));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001045 }
1046
1047 for (j = 0; j < vec_len (old_rt); j++)
1048 {
1049 rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index);
1050 rt->state = old_rt[j].state;
Maxime Peimdde163d2021-04-15 13:52:12 +02001051 rt->flags = old_rt[j].flags;
Dave Barach178cf492018-11-13 16:34:13 -05001052 clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data,
1053 VLIB_NODE_RUNTIME_DATA_SIZE);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001054 }
1055
1056 vec_free (old_rt);
1057
Dave Barach53fe4a72019-01-26 09:50:26 -05001058 /* re-clone pre-input nodes */
1059 old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT];
1060 nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT] =
1061 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT],
1062 CLIB_CACHE_LINE_BYTES);
1063
1064 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT])
1065 {
1066 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Dave Barach53fe4a72019-01-26 09:50:26 -05001067 /* copy runtime_data, will be overwritten later for existing rt */
1068 if (n->runtime_data && n->runtime_data_bytes > 0)
1069 clib_memcpy_fast (rt->runtime_data, n->runtime_data,
1070 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
1071 n->runtime_data_bytes));
1072 }
1073
1074 for (j = 0; j < vec_len (old_rt); j++)
1075 {
1076 rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index);
1077 rt->state = old_rt[j].state;
Maxime Peimdde163d2021-04-15 13:52:12 +02001078 rt->flags = old_rt[j].flags;
Dave Barach53fe4a72019-01-26 09:50:26 -05001079 clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data,
1080 VLIB_NODE_RUNTIME_DATA_SIZE);
1081 }
1082
1083 vec_free (old_rt);
1084
Vladislav Grishenko29733502021-09-25 21:00:59 +05001085 vec_free (nm_clone->processes);
Damjan Marionbe3f4d52018-03-27 21:06:10 +02001086 nm_clone->processes = vec_dup_aligned (nm->processes,
1087 CLIB_CACHE_LINE_BYTES);
Dave Barach687c9022019-07-23 10:22:31 -04001088 nm_clone->node_by_error = nm->node_by_error;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001089}
1090
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001091void
1092vlib_worker_thread_node_runtime_update (void)
1093{
1094 /*
1095 * Make a note that we need to do a node runtime update
1096 * prior to releasing the barrier.
1097 */
1098 vlib_global_main.need_vlib_worker_thread_node_runtime_update = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099}
1100
Pavel Kotucek1e765832016-09-23 08:54:14 +02001101u32
1102unformat_sched_policy (unformat_input_t * input, va_list * args)
1103{
1104 u32 *r = va_arg (*args, u32 *);
1105
1106 if (0);
1107#define _(v,f,s) else if (unformat (input, s)) *r = SCHED_POLICY_##f;
1108 foreach_sched_policy
1109#undef _
1110 else
1111 return 0;
1112 return 1;
1113}
1114
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115static clib_error_t *
1116cpu_config (vlib_main_t * vm, unformat_input_t * input)
1117{
1118 vlib_thread_registration_t *tr;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001119 uword *p;
1120 vlib_thread_main_t *tm = &vlib_thread_main;
1121 u8 *name;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001122 uword *bitmap;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001123 u32 count;
1124
1125 tm->thread_registrations_by_name = hash_create_string (0, sizeof (uword));
Pavel Kotucek1e765832016-09-23 08:54:14 +02001126
Dave Barach9b8ffd92016-07-08 08:13:45 -04001127 tm->n_thread_stacks = 1; /* account for main thread */
Pavel Kotucek1e765832016-09-23 08:54:14 +02001128 tm->sched_policy = ~0;
1129 tm->sched_priority = ~0;
Damjan Marion858151f2018-07-11 10:51:00 +02001130 tm->main_lcore = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001131
1132 tr = tm->next;
1133
1134 while (tr)
1135 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001136 hash_set_mem (tm->thread_registrations_by_name, tr->name, (uword) tr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001137 tr = tr->next;
1138 }
1139
Dave Barach9b8ffd92016-07-08 08:13:45 -04001140 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141 {
Damjan Marionbf741472016-06-13 22:49:44 +02001142 if (unformat (input, "use-pthreads"))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001143 tm->use_pthreads = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144 else if (unformat (input, "thread-prefix %v", &tm->thread_prefix))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001145 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001146 else if (unformat (input, "main-core %u", &tm->main_lcore))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001147 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001148 else if (unformat (input, "skip-cores %u", &tm->skip_cores))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001149 ;
Dave Baracha690fdb2020-01-21 12:34:55 -05001150 else if (unformat (input, "numa-heap-size %U",
1151 unformat_memory_size, &tm->numa_heap_size))
1152 ;
Yi Hee4a9eb72018-07-17 14:18:41 +08001153 else if (unformat (input, "coremask-%s %U", &name,
1154 unformat_bitmap_mask, &bitmap) ||
1155 unformat (input, "corelist-%s %U", &name,
1156 unformat_bitmap_list, &bitmap))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001157 {
1158 p = hash_get_mem (tm->thread_registrations_by_name, name);
1159 if (p == 0)
1160 return clib_error_return (0, "no such thread type '%s'", name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001161
Dave Barach9b8ffd92016-07-08 08:13:45 -04001162 tr = (vlib_thread_registration_t *) p[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001163
Dave Barach9b8ffd92016-07-08 08:13:45 -04001164 if (tr->use_pthreads)
1165 return clib_error_return (0,
1166 "corelist cannot be set for '%s' threads",
1167 name);
Vladimir Isaev18a4a372020-03-17 12:30:11 +03001168 if (tr->count)
1169 return clib_error_return
1170 (0, "core placement of '%s' threads is already configured",
1171 name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001172
Dave Barach9b8ffd92016-07-08 08:13:45 -04001173 tr->coremask = bitmap;
1174 tr->count = clib_bitmap_count_set_bits (tr->coremask);
1175 }
Pavel Kotucek1e765832016-09-23 08:54:14 +02001176 else
1177 if (unformat
1178 (input, "scheduler-policy %U", unformat_sched_policy,
1179 &tm->sched_policy))
1180 ;
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001181 else if (unformat (input, "scheduler-priority %u", &tm->sched_priority))
Pavel Kotucek1e765832016-09-23 08:54:14 +02001182 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001183 else if (unformat (input, "%s %u", &name, &count))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001184 {
1185 p = hash_get_mem (tm->thread_registrations_by_name, name);
1186 if (p == 0)
Pavel Kotucek1e765832016-09-23 08:54:14 +02001187 return clib_error_return (0, "no such thread type 3 '%s'", name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001188
1189 tr = (vlib_thread_registration_t *) p[0];
Vladimir Isaev18a4a372020-03-17 12:30:11 +03001190
Dave Barach9b8ffd92016-07-08 08:13:45 -04001191 if (tr->fixed_count)
1192 return clib_error_return
Vladimir Isaev18a4a372020-03-17 12:30:11 +03001193 (0, "number of '%s' threads not configurable", name);
1194 if (tr->count)
1195 return clib_error_return
1196 (0, "number of '%s' threads is already configured", name);
1197
Dave Barach9b8ffd92016-07-08 08:13:45 -04001198 tr->count = count;
1199 }
1200 else
1201 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001202 }
1203
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001204 if (tm->sched_priority != ~0)
Pavel Kotucek1e765832016-09-23 08:54:14 +02001205 {
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001206 if (tm->sched_policy == SCHED_FIFO || tm->sched_policy == SCHED_RR)
Pavel Kotucek1e765832016-09-23 08:54:14 +02001207 {
1208 u32 prio_max = sched_get_priority_max (tm->sched_policy);
1209 u32 prio_min = sched_get_priority_min (tm->sched_policy);
1210 if (tm->sched_priority > prio_max)
1211 tm->sched_priority = prio_max;
1212 if (tm->sched_priority < prio_min)
1213 tm->sched_priority = prio_min;
1214 }
1215 else
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001216 {
1217 return clib_error_return
1218 (0,
1219 "scheduling priority (%d) is not allowed for `normal` scheduling policy",
1220 tm->sched_priority);
1221 }
Pavel Kotucek1e765832016-09-23 08:54:14 +02001222 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001223 tr = tm->next;
1224
1225 if (!tm->thread_prefix)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001226 tm->thread_prefix = format (0, "vpp");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227
1228 while (tr)
1229 {
1230 tm->n_thread_stacks += tr->count;
1231 tm->n_pthreads += tr->count * tr->use_pthreads;
Damjan Marion878c6092017-01-04 13:19:27 +01001232 tm->n_threads += tr->count * (tr->use_pthreads == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001233 tr = tr->next;
1234 }
1235
1236 return 0;
1237}
1238
1239VLIB_EARLY_CONFIG_FUNCTION (cpu_config, "cpu");
1240
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001241 /*
1242 * Enforce minimum open time to minimize packet loss due to Rx overflow,
1243 * based on a test based heuristic that barrier should be open for at least
1244 * 3 time as long as it is closed (with an upper bound of 1ms because by that
1245 * point it is probably too late to make a difference)
1246 */
1247
1248#ifndef BARRIER_MINIMUM_OPEN_LIMIT
1249#define BARRIER_MINIMUM_OPEN_LIMIT 0.001
1250#endif
1251
1252#ifndef BARRIER_MINIMUM_OPEN_FACTOR
1253#define BARRIER_MINIMUM_OPEN_FACTOR 3
1254#endif
1255
Dave Barach9b8ffd92016-07-08 08:13:45 -04001256void
Dave Barachc602b382019-06-03 19:48:22 -04001257vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm)
1258{
1259 f64 deadline;
1260 f64 now = vlib_time_now (vm);
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001261 u32 count = vlib_get_n_threads () - 1;
Dave Barachc602b382019-06-03 19:48:22 -04001262
1263 /* No worker threads? */
1264 if (count == 0)
1265 return;
1266
1267 deadline = now + BARRIER_SYNC_TIMEOUT;
1268 *vlib_worker_threads->wait_at_barrier = 1;
1269 while (*vlib_worker_threads->workers_at_barrier != count)
1270 {
1271 if ((now = vlib_time_now (vm)) > deadline)
1272 {
1273 fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
1274 os_panic ();
1275 }
1276 CLIB_PAUSE ();
1277 }
1278 *vlib_worker_threads->wait_at_barrier = 0;
1279}
1280
Neale Ranns42845dd2020-05-26 13:12:17 +00001281/**
1282 * Return true if the wroker thread barrier is held
1283 */
1284u8
1285vlib_worker_thread_barrier_held (void)
1286{
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001287 if (vlib_get_n_threads () < 2)
Neale Ranns42845dd2020-05-26 13:12:17 +00001288 return (1);
1289
1290 return (*vlib_worker_threads->wait_at_barrier == 1);
1291}
1292
Dave Barachc602b382019-06-03 19:48:22 -04001293void
Damjan Marion8343ee52019-02-26 17:15:48 +01001294vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001295{
1296 f64 deadline;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001297 f64 now;
1298 f64 t_entry;
1299 f64 t_open;
1300 f64 t_closed;
Dave Barach9ae190e2019-04-23 10:07:24 -04001301 f64 max_vector_rate;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302 u32 count;
Dave Barach9ae190e2019-04-23 10:07:24 -04001303 int i;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001304
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001305 if (vlib_get_n_threads () < 2)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001306 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001307
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001308 ASSERT (vlib_get_thread_index () == 0);
1309
Damjan Marion8343ee52019-02-26 17:15:48 +01001310 vlib_worker_threads[0].barrier_caller = func_name;
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001311 count = vlib_get_n_threads () - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001312
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001313 /* Record entry relative to last close */
1314 now = vlib_time_now (vm);
1315 t_entry = now - vm->barrier_epoch;
1316
Ed Warnickecb9cada2015-12-08 15:45:58 -07001317 /* Tolerate recursive calls */
1318 if (++vlib_worker_threads[0].recursion_level > 1)
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001319 {
1320 barrier_trace_sync_rec (t_entry);
1321 return;
1322 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001323
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +00001324 if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0))
1325 clib_call_callbacks (vm->barrier_perf_callbacks, vm,
1326 vm->clib_time.last_cpu_time, 0 /* enter */ );
1327
Dave Barach9ae190e2019-04-23 10:07:24 -04001328 /*
1329 * Need data to decide if we're working hard enough to honor
1330 * the barrier hold-down timer.
1331 */
1332 max_vector_rate = 0.0;
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001333 for (i = 1; i < vlib_get_n_threads (); i++)
1334 {
1335 vlib_main_t *ovm = vlib_get_main_by_index (i);
1336 max_vector_rate = clib_max (max_vector_rate,
1337 (f64) vlib_last_vectors_per_main_loop (ovm));
1338 }
Dave Barach9ae190e2019-04-23 10:07:24 -04001339
Bud Grise42f20062016-03-16 13:09:46 -04001340 vlib_worker_threads[0].barrier_sync_count++;
1341
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001342 /* Enforce minimum barrier open time to minimize packet loss */
1343 ASSERT (vm->barrier_no_close_before <= (now + BARRIER_MINIMUM_OPEN_LIMIT));
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001344
Dave Barach9ae190e2019-04-23 10:07:24 -04001345 /*
1346 * If any worker thread seems busy, which we define
1347 * as a vector rate above 10, we enforce the barrier hold-down timer
1348 */
1349 if (max_vector_rate > 10.0)
Dave Barach36feebb2018-09-07 11:12:27 -04001350 {
Dave Barach9ae190e2019-04-23 10:07:24 -04001351 while (1)
Dave Barach36feebb2018-09-07 11:12:27 -04001352 {
Dave Barach9ae190e2019-04-23 10:07:24 -04001353 now = vlib_time_now (vm);
1354 /* Barrier hold-down timer expired? */
1355 if (now >= vm->barrier_no_close_before)
1356 break;
1357 if ((vm->barrier_no_close_before - now)
1358 > (2.0 * BARRIER_MINIMUM_OPEN_LIMIT))
1359 {
1360 clib_warning
1361 ("clock change: would have waited for %.4f seconds",
1362 (vm->barrier_no_close_before - now));
1363 break;
1364 }
Dave Barach36feebb2018-09-07 11:12:27 -04001365 }
1366 }
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001367 /* Record time of closure */
1368 t_open = now - vm->barrier_epoch;
1369 vm->barrier_epoch = now;
1370
1371 deadline = now + BARRIER_SYNC_TIMEOUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372
1373 *vlib_worker_threads->wait_at_barrier = 1;
1374 while (*vlib_worker_threads->workers_at_barrier != count)
1375 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001376 if ((now = vlib_time_now (vm)) > deadline)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001377 {
1378 fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
1379 os_panic ();
1380 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001381 }
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001382
1383 t_closed = now - vm->barrier_epoch;
1384
1385 barrier_trace_sync (t_entry, t_open, t_closed);
1386
Ed Warnickecb9cada2015-12-08 15:45:58 -07001387}
1388
Dave Barach9b8ffd92016-07-08 08:13:45 -04001389void
1390vlib_worker_thread_barrier_release (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001391{
Damjan Marionfd8deb42021-03-06 12:26:28 +01001392 vlib_global_main_t *vgm = vlib_get_global_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001393 f64 deadline;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001394 f64 now;
1395 f64 minimum_open;
1396 f64 t_entry;
1397 f64 t_closed_total;
1398 f64 t_update_main = 0.0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001399 int refork_needed = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001400
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001401 if (vlib_get_n_threads () < 2)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001402 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001403
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001404 ASSERT (vlib_get_thread_index () == 0);
1405
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001406
1407 now = vlib_time_now (vm);
1408 t_entry = now - vm->barrier_epoch;
1409
Ed Warnickecb9cada2015-12-08 15:45:58 -07001410 if (--vlib_worker_threads[0].recursion_level > 0)
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001411 {
1412 barrier_trace_release_rec (t_entry);
1413 return;
1414 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001415
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001416 /* Update (all) node runtimes before releasing the barrier, if needed */
Damjan Marionfd8deb42021-03-06 12:26:28 +01001417 if (vgm->need_vlib_worker_thread_node_runtime_update)
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001418 {
Dave Barach1ddbc012018-06-13 09:26:05 -04001419 /*
1420 * Lock stat segment here, so we's safe when
1421 * rebuilding the stat segment node clones from the
1422 * stat thread...
1423 */
Damjan Marion8973b072022-03-01 15:51:18 +01001424 vlib_stats_segment_lock ();
Dave Barach1ddbc012018-06-13 09:26:05 -04001425
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001426 /* Do stats elements on main thread */
1427 worker_thread_node_runtime_update_internal ();
Damjan Marionfd8deb42021-03-06 12:26:28 +01001428 vgm->need_vlib_worker_thread_node_runtime_update = 0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001429
1430 /* Do per thread rebuilds in parallel */
1431 refork_needed = 1;
Sirshak Das2f6d7bb2018-10-03 22:53:51 +00001432 clib_atomic_fetch_add (vlib_worker_threads->node_reforks_required,
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001433 (vlib_get_n_threads () - 1));
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001434 now = vlib_time_now (vm);
1435 t_update_main = now - vm->barrier_epoch;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001436 }
1437
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001438 deadline = now + BARRIER_SYNC_TIMEOUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001439
Dave Baracha4324a92019-02-19 17:05:30 -05001440 /*
1441 * Note when we let go of the barrier.
1442 * Workers can use this to derive a reasonably accurate
1443 * time offset. See vlib_time_now(...)
1444 */
1445 vm->time_last_barrier_release = vlib_time_now (vm);
1446 CLIB_MEMORY_STORE_BARRIER ();
1447
Ed Warnickecb9cada2015-12-08 15:45:58 -07001448 *vlib_worker_threads->wait_at_barrier = 0;
1449
1450 while (*vlib_worker_threads->workers_at_barrier > 0)
1451 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001452 if ((now = vlib_time_now (vm)) > deadline)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001453 {
1454 fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
1455 os_panic ();
1456 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001457 }
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001458
1459 /* Wait for reforks before continuing */
1460 if (refork_needed)
1461 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001462 now = vlib_time_now (vm);
1463
1464 deadline = now + BARRIER_SYNC_TIMEOUT;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001465
1466 while (*vlib_worker_threads->node_reforks_required > 0)
1467 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001468 if ((now = vlib_time_now (vm)) > deadline)
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001469 {
1470 fformat (stderr, "%s: worker thread refork deadlock\n",
1471 __FUNCTION__);
1472 os_panic ();
1473 }
1474 }
Damjan Marion8973b072022-03-01 15:51:18 +01001475 vlib_stats_segment_unlock ();
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001476 }
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001477
1478 t_closed_total = now - vm->barrier_epoch;
1479
1480 minimum_open = t_closed_total * BARRIER_MINIMUM_OPEN_FACTOR;
1481
1482 if (minimum_open > BARRIER_MINIMUM_OPEN_LIMIT)
1483 {
1484 minimum_open = BARRIER_MINIMUM_OPEN_LIMIT;
1485 }
1486
1487 vm->barrier_no_close_before = now + minimum_open;
1488
1489 /* Record barrier epoch (used to enforce minimum open time) */
1490 vm->barrier_epoch = now;
1491
1492 barrier_trace_release (t_entry, t_closed_total, t_update_main);
1493
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +00001494 if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0))
1495 clib_call_callbacks (vm->barrier_perf_callbacks, vm,
1496 vm->clib_time.last_cpu_time, 1 /* leave */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001497}
1498
Florin Coras4b208302022-03-30 13:50:19 -07001499static void
1500vlib_worker_sync_rpc (void *args)
1501{
1502 ASSERT (vlib_thread_is_main_w_barrier ());
1503 vlib_worker_threads->wait_before_barrier = 0;
1504}
1505
1506void
1507vlib_workers_sync (void)
1508{
1509 if (PREDICT_FALSE (!vlib_num_workers ()))
1510 return;
1511
1512 if (!(*vlib_worker_threads->wait_at_barrier) &&
1513 !clib_atomic_swap_rel_n (&vlib_worker_threads->wait_before_barrier, 1))
1514 {
1515 u32 thread_index = vlib_get_thread_index ();
1516 vlib_rpc_call_main_thread (vlib_worker_sync_rpc, (u8 *) &thread_index,
1517 sizeof (thread_index));
Florin Corase060b0a2024-02-01 21:13:10 -08001518 vlib_worker_flush_pending_rpc_requests (vlib_get_main ());
Florin Coras4b208302022-03-30 13:50:19 -07001519 }
1520
1521 /* Wait until main thread asks for barrier */
1522 while (!(*vlib_worker_threads->wait_at_barrier))
1523 ;
1524
1525 /* Stop before barrier and make sure all threads are either
1526 * at worker barrier or the barrier before it */
1527 clib_atomic_fetch_add (&vlib_worker_threads->workers_before_barrier, 1);
1528 while (vlib_num_workers () > (*vlib_worker_threads->workers_at_barrier +
1529 vlib_worker_threads->workers_before_barrier))
1530 ;
1531}
1532
1533void
1534vlib_workers_continue (void)
1535{
1536 if (PREDICT_FALSE (!vlib_num_workers ()))
1537 return;
1538
1539 clib_atomic_fetch_add (&vlib_worker_threads->done_work_before_barrier, 1);
1540
1541 /* Wait until all workers are done with work before barrier */
1542 while (vlib_worker_threads->done_work_before_barrier <
1543 vlib_worker_threads->workers_before_barrier)
1544 ;
1545
1546 clib_atomic_fetch_add (&vlib_worker_threads->done_work_before_barrier, -1);
1547 clib_atomic_fetch_add (&vlib_worker_threads->workers_before_barrier, -1);
1548}
1549
Neale Ranns42845dd2020-05-26 13:12:17 +00001550/**
1551 * Wait until each of the workers has been once around the track
1552 */
1553void
1554vlib_worker_wait_one_loop (void)
1555{
Damjan Marionfd8deb42021-03-06 12:26:28 +01001556 vlib_global_main_t *vgm = vlib_get_global_main ();
Neale Ranns42845dd2020-05-26 13:12:17 +00001557 ASSERT (vlib_get_thread_index () == 0);
1558
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001559 if (vlib_get_n_threads () < 2)
Neale Ranns42845dd2020-05-26 13:12:17 +00001560 return;
1561
1562 if (vlib_worker_thread_barrier_held ())
1563 return;
1564
1565 u32 *counts = 0;
1566 u32 ii;
1567
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001568 vec_validate (counts, vlib_get_n_threads () - 1);
Neale Ranns42845dd2020-05-26 13:12:17 +00001569
1570 /* record the current loop counts */
Damjan Marionfd8deb42021-03-06 12:26:28 +01001571 vec_foreach_index (ii, vgm->vlib_mains)
1572 counts[ii] = vgm->vlib_mains[ii]->main_loop_count;
Neale Ranns42845dd2020-05-26 13:12:17 +00001573
1574 /* spin until each changes, apart from the main thread, or we'd be
1575 * a while */
1576 for (ii = 1; ii < vec_len (counts); ii++)
1577 {
Damjan Marionfd8deb42021-03-06 12:26:28 +01001578 while (counts[ii] == vgm->vlib_mains[ii]->main_loop_count)
Neale Ranns42845dd2020-05-26 13:12:17 +00001579 CLIB_PAUSE ();
1580 }
1581
1582 vec_free (counts);
1583 return;
1584}
1585
Dave Barach9b8ffd92016-07-08 08:13:45 -04001586void
Florin Coras4cadd3b2024-02-01 20:46:15 -08001587vlib_worker_flush_pending_rpc_requests (vlib_main_t *vm)
1588{
1589 vlib_main_t *vm_global = vlib_get_first_main ();
1590
1591 ASSERT (vm != vm_global);
1592
1593 clib_spinlock_lock_if_init (&vm_global->pending_rpc_lock);
1594 vec_append (vm_global->pending_rpc_requests, vm->pending_rpc_requests);
1595 vec_reset_length (vm->pending_rpc_requests);
1596 clib_spinlock_unlock_if_init (&vm_global->pending_rpc_lock);
1597}
1598
1599void
Dave Barach9b8ffd92016-07-08 08:13:45 -04001600vlib_worker_thread_fn (void *arg)
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001601{
Damjan Marionfd8deb42021-03-06 12:26:28 +01001602 vlib_global_main_t *vgm = vlib_get_global_main ();
Dave Barach9b8ffd92016-07-08 08:13:45 -04001603 vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001604 vlib_main_t *vm = vlib_get_main ();
Damjan Marione9f929b2017-03-16 11:32:09 +01001605 clib_error_t *e;
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001606
Damjan Marion586afd72017-04-05 19:18:20 +02001607 ASSERT (vm->thread_index == vlib_get_thread_index ());
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001608
1609 vlib_worker_thread_init (w);
1610 clib_time_init (&vm->clib_time);
1611 clib_mem_set_heap (w->thread_mheap);
1612
Damjan Marionfd8deb42021-03-06 12:26:28 +01001613 vm->worker_init_functions_called = hash_create (0, 0);
1614
1615 e = vlib_call_init_exit_functions_no_sort (
1616 vm, &vgm->worker_init_function_registrations, 1 /* call_once */,
1617 0 /* is_global */);
Damjan Marione9f929b2017-03-16 11:32:09 +01001618 if (e)
1619 clib_error_report (e);
1620
Damjan Marione9d52d52017-03-09 15:42:26 +01001621 vlib_worker_loop (vm);
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001622}
1623
1624VLIB_REGISTER_THREAD (worker_thread_reg, static) = {
1625 .name = "workers",
1626 .short_name = "wk",
1627 .function = vlib_worker_thread_fn,
1628};
1629
Mohammed Hawarie7149262022-05-18 10:08:47 +02001630extern clib_march_fn_registration
1631 *vlib_frame_queue_dequeue_with_aux_fn_march_fn_registrations;
1632extern clib_march_fn_registration
1633 *vlib_frame_queue_dequeue_fn_march_fn_registrations;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001634u32
1635vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts)
1636{
1637 vlib_thread_main_t *tm = vlib_get_thread_main ();
Mohammed Hawarie7149262022-05-18 10:08:47 +02001638 vlib_main_t *vm = vlib_get_main ();
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001639 vlib_frame_queue_main_t *fqm;
1640 vlib_frame_queue_t *fq;
Mohammed Hawarie7149262022-05-18 10:08:47 +02001641 vlib_node_t *node;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001642 int i;
Elias Rudberg368104d2020-04-16 16:01:52 +02001643 u32 num_threads;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001644
1645 if (frame_queue_nelts == 0)
dongjuan88752482019-06-04 10:59:02 +08001646 frame_queue_nelts = FRAME_QUEUE_MAX_NELTS;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001647
Elias Rudberg368104d2020-04-16 16:01:52 +02001648 num_threads = 1 /* main thread */ + tm->n_threads;
1649 ASSERT (frame_queue_nelts >= 8 + num_threads);
Damjan Marion78fd7e82018-07-20 18:47:05 +02001650
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001651 vec_add2 (tm->frame_queue_mains, fqm, 1);
1652
Mohammed Hawarie7149262022-05-18 10:08:47 +02001653 node = vlib_get_node (vm, fqm->node_index);
1654 ASSERT (node);
1655 if (node->aux_offset)
1656 {
1657 fqm->frame_queue_dequeue_fn =
1658 CLIB_MARCH_FN_VOID_POINTER (vlib_frame_queue_dequeue_with_aux_fn);
1659 }
1660 else
1661 {
1662 fqm->frame_queue_dequeue_fn =
1663 CLIB_MARCH_FN_VOID_POINTER (vlib_frame_queue_dequeue_fn);
1664 }
1665
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001666 fqm->node_index = node_index;
Damjan Marion78fd7e82018-07-20 18:47:05 +02001667 fqm->frame_queue_nelts = frame_queue_nelts;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001668
1669 vec_validate (fqm->vlib_frame_queues, tm->n_vlib_mains - 1);
Damjan Marion8bea5892022-04-04 22:40:45 +02001670 vec_set_len (fqm->vlib_frame_queues, 0);
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001671 for (i = 0; i < tm->n_vlib_mains; i++)
1672 {
1673 fq = vlib_frame_queue_alloc (frame_queue_nelts);
1674 vec_add1 (fqm->vlib_frame_queues, fq);
1675 }
1676
1677 return (fqm - tm->frame_queue_mains);
1678}
1679
Dave Barach69128d02017-09-26 10:54:34 -04001680void
1681vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
1682 args)
1683{
1684 ASSERT (vlib_get_thread_index () == 0);
1685 vlib_process_signal_event (vlib_get_main (), args->node_index,
1686 args->type_opaque, args->data);
1687}
1688
1689void *rpc_call_main_thread_cb_fn;
1690
1691void
1692vlib_rpc_call_main_thread (void *callback, u8 * args, u32 arg_size)
1693{
1694 if (rpc_call_main_thread_cb_fn)
1695 {
1696 void (*fp) (void *, u8 *, u32) = rpc_call_main_thread_cb_fn;
1697 (*fp) (callback, args, arg_size);
1698 }
1699 else
1700 clib_warning ("BUG: rpc_call_main_thread_cb_fn NULL!");
1701}
1702
Dave Barach9b8ffd92016-07-08 08:13:45 -04001703clib_error_t *
1704threads_init (vlib_main_t * vm)
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001705{
Benoît Ganne8b153de2021-12-09 18:24:21 +01001706 const vlib_thread_main_t *tm = vlib_get_thread_main ();
1707
1708 if (tm->main_lcore == ~0 && tm->n_vlib_mains > 1)
1709 return clib_error_return (0, "Configuration error, a main core must "
1710 "be specified when using worker threads");
1711
Ed Warnickecb9cada2015-12-08 15:45:58 -07001712 return 0;
1713}
1714
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001715VLIB_INIT_FUNCTION (threads_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001716
Dave Baracha4324a92019-02-19 17:05:30 -05001717static clib_error_t *
1718show_clock_command_fn (vlib_main_t * vm,
1719 unformat_input_t * input, vlib_cli_command_t * cmd)
1720{
Dave Barachc25048b2020-01-29 18:05:24 -05001721 int verbose = 0;
Dave Barach19718002020-03-11 10:31:36 -04001722 clib_timebase_t _tb, *tb = &_tb;
Dave Baracha4324a92019-02-19 17:05:30 -05001723
Dave Barachc25048b2020-01-29 18:05:24 -05001724 (void) unformat (input, "verbose %=", &verbose, 1);
Dave Baracha4324a92019-02-19 17:05:30 -05001725
Dave Barach19718002020-03-11 10:31:36 -04001726 clib_timebase_init (tb, 0 /* GMT */ , CLIB_TIMEBASE_DAYLIGHT_NONE,
1727 &vm->clib_time);
1728
1729 vlib_cli_output (vm, "%U, %U GMT", format_clib_time, &vm->clib_time,
1730 verbose, format_clib_timebase_time,
1731 clib_timebase_now (tb));
Dave Baracha4324a92019-02-19 17:05:30 -05001732
Dave Baracha4324a92019-02-19 17:05:30 -05001733 vlib_cli_output (vm, "Time last barrier release %.9f",
1734 vm->time_last_barrier_release);
1735
Benoît Ganne56eccdb2021-08-20 09:18:31 +02001736 foreach_vlib_main ()
Dave Baracha4324a92019-02-19 17:05:30 -05001737 {
Benoît Ganne56eccdb2021-08-20 09:18:31 +02001738 vlib_cli_output (vm, "%d: %U", this_vlib_main->thread_index,
1739 format_clib_time, &this_vlib_main->clib_time, verbose);
Dave Barachc25048b2020-01-29 18:05:24 -05001740
Benoît Ganne56eccdb2021-08-20 09:18:31 +02001741 vlib_cli_output (vm, "Thread %d offset %.9f error %.9f",
1742 this_vlib_main->thread_index,
1743 this_vlib_main->time_offset,
1744 vm->time_last_barrier_release -
1745 this_vlib_main->time_last_barrier_release);
Dave Baracha4324a92019-02-19 17:05:30 -05001746 }
1747 return 0;
1748}
1749
Dave Baracha4324a92019-02-19 17:05:30 -05001750VLIB_CLI_COMMAND (f_command, static) =
1751{
1752 .path = "show clock",
1753 .short_help = "show clock",
1754 .function = show_clock_command_fn,
1755};
Dave Baracha4324a92019-02-19 17:05:30 -05001756
Dave Barachab1a50c2020-10-06 14:08:16 -04001757vlib_thread_main_t *
1758vlib_get_thread_main_not_inline (void)
1759{
1760 return vlib_get_thread_main ();
1761}
1762
Dave Barach9b8ffd92016-07-08 08:13:45 -04001763/*
1764 * fd.io coding-style-patch-verification: ON
1765 *
1766 * Local Variables:
1767 * eval: (c-set-style "gnu")
1768 * End:
1769 */