blob: 87b71adc2bcbc1d253562205ea1fdb8f814bf558 [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>
Tom Jonesd346b882024-01-29 10:55:09 +000019#ifdef __FreeBSD__
20#include <pthread_np.h>
21#endif /* __FreeBSD__ */
Ed Warnickecb9cada2015-12-08 15:45:58 -070022#include <vppinfra/format.h>
Dave Barach19718002020-03-11 10:31:36 -040023#include <vppinfra/time_range.h>
Damjan Marion94100532020-11-06 23:25:57 +010024#include <vppinfra/interrupt.h>
Damjan Marion4b661402024-02-29 16:14:27 +010025#include <vppinfra/bitmap.h>
26#include <vppinfra/unix.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070027#include <vlib/vlib.h>
28
29#include <vlib/threads.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070030
Damjan Marion8973b072022-03-01 15:51:18 +010031#include <vlib/stats/stats.h>
Ole Troan233e4682019-05-16 15:01:34 +020032
Dave Barach9b8ffd92016-07-08 08:13:45 -040033u32
34vl (void *p)
Ed Warnickecb9cada2015-12-08 15:45:58 -070035{
36 return vec_len (p);
37}
38
Damjan Marion6a7acc22016-12-19 16:28:36 +010039vlib_worker_thread_t *vlib_worker_threads;
Ed Warnickecb9cada2015-12-08 15:45:58 -070040vlib_thread_main_t vlib_thread_main;
41
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010042/*
43 * Barrier tracing can be enabled on a normal build to collect information
44 * on barrier use, including timings and call stacks. Deliberately not
45 * keyed off CLIB_DEBUG, because that can add significant overhead which
46 * imapacts observed timings.
47 */
48
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010049static inline void
50barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed)
51{
Dave Barach88c6e002018-09-30 15:54:06 -040052 if (!vlib_worker_threads->barrier_elog_enabled)
53 return;
54
Damjan Marion14361002021-03-11 12:17:33 +010055 ELOG_TYPE_DECLARE (e) = {
56 .format = "bar-trace-%s-#%d",
57 .format_args = "T4i4",
58 };
59
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010060 struct
61 {
Dave Barach88c6e002018-09-30 15:54:06 -040062 u32 caller, count, t_entry, t_open, t_closed;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010063 } *ed = 0;
64
65 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
66 ed->count = (int) vlib_worker_threads[0].barrier_sync_count;
Dave Barachb09f4d02019-07-15 16:00:03 -040067 ed->caller = elog_string (&vlib_global_main.elog_main,
68 (char *) vlib_worker_threads[0].barrier_caller);
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010069 ed->t_entry = (int) (1000000.0 * t_entry);
70 ed->t_open = (int) (1000000.0 * t_open);
71 ed->t_closed = (int) (1000000.0 * t_closed);
72}
73
74static inline void
75barrier_trace_sync_rec (f64 t_entry)
76{
Dave Barach88c6e002018-09-30 15:54:06 -040077 if (!vlib_worker_threads->barrier_elog_enabled)
78 return;
79
Damjan Marion14361002021-03-11 12:17:33 +010080 ELOG_TYPE_DECLARE (e) = {
81 .format = "bar-syncrec-%s-#%d",
82 .format_args = "T4i4",
83 };
84
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010085 struct
86 {
Dave Barach88c6e002018-09-30 15:54:06 -040087 u32 caller, depth;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010088 } *ed = 0;
89
90 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
91 ed->depth = (int) vlib_worker_threads[0].recursion_level - 1;
Dave Barachb09f4d02019-07-15 16:00:03 -040092 ed->caller = elog_string (&vlib_global_main.elog_main,
93 (char *) vlib_worker_threads[0].barrier_caller);
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +010094}
95
96static inline void
97barrier_trace_release_rec (f64 t_entry)
98{
Dave Barach88c6e002018-09-30 15:54:06 -040099 if (!vlib_worker_threads->barrier_elog_enabled)
100 return;
101
Damjan Marion14361002021-03-11 12:17:33 +0100102 ELOG_TYPE_DECLARE (e) = {
103 .format = "bar-relrrec-#%d",
104 .format_args = "i4",
105 };
106
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100107 struct
108 {
Dave Barach88c6e002018-09-30 15:54:06 -0400109 u32 depth;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100110 } *ed = 0;
111
112 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100113 ed->depth = (int) vlib_worker_threads[0].recursion_level;
114}
115
116static inline void
117barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main)
118{
Dave Barach88c6e002018-09-30 15:54:06 -0400119 if (!vlib_worker_threads->barrier_elog_enabled)
120 return;
121
Damjan Marion14361002021-03-11 12:17:33 +0100122 ELOG_TYPE_DECLARE (e) = {
123 .format = "bar-rel-#%d-e%d-u%d-t%d",
124 .format_args = "i4i4i4i4",
125 };
126
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100127 struct
128 {
Dave Barach88c6e002018-09-30 15:54:06 -0400129 u32 count, t_entry, t_update_main, t_closed_total;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100130 } *ed = 0;
131
132 ed = ELOG_DATA (&vlib_global_main.elog_main, e);
133 ed->t_entry = (int) (1000000.0 * t_entry);
134 ed->t_update_main = (int) (1000000.0 * t_update_main);
135 ed->t_closed_total = (int) (1000000.0 * t_closed_total);
136 ed->count = (int) vlib_worker_threads[0].barrier_sync_count;
137
138 /* Reset context for next trace */
139 vlib_worker_threads[0].barrier_context = NULL;
140}
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100141
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142uword
Damjan Marionf55f9b82017-05-10 21:06:28 +0200143os_get_nthreads (void)
Dave Barach01d86c72016-08-08 15:13:42 -0400144{
Dave Barach2180bac2019-05-10 15:25:10 -0400145 return vec_len (vlib_thread_stacks);
Dave Barach01d86c72016-08-08 15:13:42 -0400146}
147
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148void
149vlib_set_thread_name (char *name)
150{
151 int pthread_setname_np (pthread_t __target_thread, const char *__name);
Dave Barachb2a6e252016-07-27 10:00:58 -0400152 int rv;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400153 pthread_t thread = pthread_self ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154
Dave Barach9b8ffd92016-07-08 08:13:45 -0400155 if (thread)
Dave Barachb2a6e252016-07-27 10:00:58 -0400156 {
157 rv = pthread_setname_np (thread, name);
158 if (rv)
Ed Warnicke853e7202016-08-12 11:42:26 -0700159 clib_warning ("pthread_setname_np returned %d", rv);
Dave Barachb2a6e252016-07-27 10:00:58 -0400160 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161}
162
Dave Barach9b8ffd92016-07-08 08:13:45 -0400163static int
164sort_registrations_by_no_clone (void *a0, void *a1)
165{
166 vlib_thread_registration_t **tr0 = a0;
167 vlib_thread_registration_t **tr1 = a1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700168
Dave Barach9b8ffd92016-07-08 08:13:45 -0400169 return ((i32) ((*tr0)->no_data_structure_clone)
170 - ((i32) ((*tr1)->no_data_structure_clone)));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171}
172
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173
174/* Called early in the init sequence */
175
176clib_error_t *
177vlib_thread_init (vlib_main_t * vm)
178{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400179 vlib_thread_main_t *tm = &vlib_thread_main;
180 vlib_worker_thread_t *w;
181 vlib_thread_registration_t *tr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 u32 n_vlib_mains = 1;
183 u32 first_index = 1;
184 u32 i;
Hadi Rayan Al-Sandid4aecd482024-04-30 14:17:45 +0000185 uword *avail_cpu;
Damjan Marion8973b072022-03-01 15:51:18 +0100186 u32 stats_num_worker_threads_dir_index;
187
188 stats_num_worker_threads_dir_index =
189 vlib_stats_add_gauge ("/sys/num_worker_threads");
190 ASSERT (stats_num_worker_threads_dir_index != ~0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
192 /* get bitmaps of active cpu cores and sockets */
Damjan Marion4b661402024-02-29 16:14:27 +0100193 tm->cpu_core_bitmap = os_get_online_cpu_core_bitmap ();
194 tm->cpu_socket_bitmap = os_get_online_cpu_node_bitmap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barach9b8ffd92016-07-08 08:13:45 -0400196 avail_cpu = clib_bitmap_dup (tm->cpu_core_bitmap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197
198 /* skip cores */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400199 for (i = 0; i < tm->skip_cores; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200 {
Hadi Rayan Al-Sandid4aecd482024-04-30 14:17:45 +0000201 uword c = clib_bitmap_first_set (avail_cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 if (c == ~0)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400203 return clib_error_return (0, "no available cpus to skip");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204
Dave Barach9b8ffd92016-07-08 08:13:45 -0400205 avail_cpu = clib_bitmap_set (avail_cpu, c, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206 }
207
208 /* grab cpu for main thread */
Benoît Ganne8b153de2021-12-09 18:24:21 +0100209 if (tm->main_lcore != ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400211 if (clib_bitmap_get (avail_cpu, tm->main_lcore) == 0)
212 return clib_error_return (0, "cpu %u is not available to be used"
213 " for the main thread", tm->main_lcore);
Benoît Ganne8b153de2021-12-09 18:24:21 +0100214 avail_cpu = clib_bitmap_set (avail_cpu, tm->main_lcore, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216
217 /* assume that there is socket 0 only if there is no data from sysfs */
218 if (!tm->cpu_socket_bitmap)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400219 tm->cpu_socket_bitmap = clib_bitmap_set (0, 0, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220
Christophe Fontainefef15b42016-04-09 12:38:49 +0900221 /* pin main thread to main_lcore */
Benoît Ganne8b153de2021-12-09 18:24:21 +0100222 if (tm->main_lcore != ~0)
223 {
224 cpu_set_t cpuset;
225 CPU_ZERO (&cpuset);
226 CPU_SET (tm->main_lcore, &cpuset);
hsandid832342e2023-12-20 15:41:54 +0100227 if (pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t),
228 &cpuset))
229 {
230 return clib_error_return (0, "could not pin main thread to cpu %u",
231 tm->main_lcore);
232 }
Benoît Ganne8b153de2021-12-09 18:24:21 +0100233 }
Christophe Fontainefef15b42016-04-09 12:38:49 +0900234
Dave Barach2180bac2019-05-10 15:25:10 -0400235 /* Set up thread 0 */
236 vec_validate_aligned (vlib_worker_threads, 0, CLIB_CACHE_LINE_BYTES);
Damjan Marion8bea5892022-04-04 22:40:45 +0200237 vec_set_len (vlib_worker_threads, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700238 w = vlib_worker_threads;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400239 w->thread_mheap = clib_mem_get_heap ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240 w->thread_stack = vlib_thread_stacks[0];
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200241 w->cpu_id = tm->main_lcore;
Tom Jonesd346b882024-01-29 10:55:09 +0000242#ifdef __FreeBSD__
243 w->lwp = pthread_getthreadid_np ();
244#else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400245 w->lwp = syscall (SYS_gettid);
Tom Jonesd346b882024-01-29 10:55:09 +0000246#endif /* __FreeBSD__ */
Pavel Kotucek98765202016-10-07 08:37:28 +0200247 w->thread_id = pthread_self ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248 tm->n_vlib_mains = 1;
249
Jon Loeligerf617b142020-01-30 18:37:47 -0600250 vlib_get_thread_core_numa (w, w->cpu_id);
251
Pavel Kotucek1e765832016-09-23 08:54:14 +0200252 if (tm->sched_policy != ~0)
253 {
254 struct sched_param sched_param;
255 if (!sched_getparam (w->lwp, &sched_param))
256 {
257 if (tm->sched_priority != ~0)
258 sched_param.sched_priority = tm->sched_priority;
259 sched_setscheduler (w->lwp, tm->sched_policy, &sched_param);
260 }
261 }
262
Ed Warnickecb9cada2015-12-08 15:45:58 -0700263 /* assign threads to cores and set n_vlib_mains */
264 tr = tm->next;
265
266 while (tr)
267 {
268 vec_add1 (tm->registrations, tr);
269 tr = tr->next;
270 }
271
Dave Barach9b8ffd92016-07-08 08:13:45 -0400272 vec_sort_with_function (tm->registrations, sort_registrations_by_no_clone);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273
274 for (i = 0; i < vec_len (tm->registrations); i++)
275 {
276 int j;
277 tr = tm->registrations[i];
278 tr->first_index = first_index;
279 first_index += tr->count;
280 n_vlib_mains += (tr->no_data_structure_clone == 0) ? tr->count : 0;
281
282 /* construct coremask */
283 if (tr->use_pthreads || !tr->count)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400284 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285
286 if (tr->coremask)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400287 {
288 uword c;
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100289 clib_bitmap_foreach (c, tr->coremask) {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 if (clib_bitmap_get(avail_cpu, c) == 0)
291 return clib_error_return (0, "cpu %u is not available to be used"
292 " for the '%s' thread",c, tr->name);
293
294 avail_cpu = clib_bitmap_set(avail_cpu, c, 0);
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100295 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400296 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400298 {
299 for (j = 0; j < tr->count; j++)
300 {
Vladimir Isaev2ed42042020-03-17 12:56:31 +0300301 /* Do not use CPU 0 by default - leave it to the host and IRQs */
Hadi Rayan Al-Sandid4aecd482024-04-30 14:17:45 +0000302 uword avail_c0 = clib_bitmap_get (avail_cpu, 0);
303 avail_cpu = clib_bitmap_set (avail_cpu, 0, 0);
Vladimir Isaev2ed42042020-03-17 12:56:31 +0300304
Hadi Rayan Al-Sandid4aecd482024-04-30 14:17:45 +0000305 uword c = clib_bitmap_first_set (avail_cpu);
Vladimir Isaev2ed42042020-03-17 12:56:31 +0300306 /* Use CPU 0 as a last resort */
307 if (c == ~0 && avail_c0)
308 {
309 c = 0;
310 avail_c0 = 0;
311 }
312
Dave Barach9b8ffd92016-07-08 08:13:45 -0400313 if (c == ~0)
314 return clib_error_return (0,
315 "no available cpus to be used for"
hsandid832342e2023-12-20 15:41:54 +0100316 " the '%s' thread #%u",
317 tr->name, tr->count);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318
Hadi Rayan Al-Sandid4aecd482024-04-30 14:17:45 +0000319 avail_cpu = clib_bitmap_set (avail_cpu, 0, avail_c0);
320 avail_cpu = clib_bitmap_set (avail_cpu, c, 0);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400321 tr->coremask = clib_bitmap_set (tr->coremask, c, 1);
322 }
323 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 }
325
Dave Barach9b8ffd92016-07-08 08:13:45 -0400326 clib_bitmap_free (avail_cpu);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700327
328 tm->n_vlib_mains = n_vlib_mains;
Damjan Marion8973b072022-03-01 15:51:18 +0100329 vlib_stats_set_gauge (stats_num_worker_threads_dir_index, n_vlib_mains - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330
Dave Barach2180bac2019-05-10 15:25:10 -0400331 /*
332 * Allocate the remaining worker threads, and thread stack vector slots
333 * from now on, calls to os_get_nthreads() will return the correct
334 * answer.
335 */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400336 vec_validate_aligned (vlib_worker_threads, first_index - 1,
337 CLIB_CACHE_LINE_BYTES);
Dave Barach2180bac2019-05-10 15:25:10 -0400338 vec_validate (vlib_thread_stacks, vec_len (vlib_worker_threads) - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 return 0;
340}
341
Dave Barach9b8ffd92016-07-08 08:13:45 -0400342vlib_frame_queue_t *
343vlib_frame_queue_alloc (int nelts)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400345 vlib_frame_queue_t *fq;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700346
Dave Barach9b8ffd92016-07-08 08:13:45 -0400347 fq = clib_mem_alloc_aligned (sizeof (*fq), CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400348 clib_memset (fq, 0, sizeof (*fq));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 fq->nelts = nelts;
Damjan Marionc0d9ca72021-05-11 09:39:24 +0200350 fq->vector_threshold = 2 * VLIB_FRAME_SIZE;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400351 vec_validate_aligned (fq->elts, nelts - 1, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352
Damjan Marionc0d9ca72021-05-11 09:39:24 +0200353 if (nelts & (nelts - 1))
Dave Barach9b8ffd92016-07-08 08:13:45 -0400354 {
Damjan Marionc0d9ca72021-05-11 09:39:24 +0200355 fformat (stderr, "FATAL: nelts MUST be a power of 2\n");
356 abort ();
Dave Barach9b8ffd92016-07-08 08:13:45 -0400357 }
358
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359 return (fq);
360}
361
362void vl_msg_api_handler_no_free (void *) __attribute__ ((weak));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400363void
364vl_msg_api_handler_no_free (void *v)
365{
366}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368/* To be called by vlib worker threads upon startup */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400369void
370vlib_worker_thread_init (vlib_worker_thread_t * w)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400372 vlib_thread_main_t *tm = vlib_get_thread_main ();
373
Dave Barachfdf49442016-12-20 12:48:14 -0500374 /*
375 * Note: disabling signals in worker threads as follows
376 * prevents the api post-mortem dump scheme from working
377 * {
378 * sigset_t s;
379 * sigfillset (&s);
380 * pthread_sigmask (SIG_SETMASK, &s, 0);
381 * }
382 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383
384 clib_mem_set_heap (w->thread_mheap);
385
Dave Barach9b8ffd92016-07-08 08:13:45 -0400386 if (vec_len (tm->thread_prefix) && w->registration->short_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400388 w->name = format (0, "%v_%s_%d%c", tm->thread_prefix,
389 w->registration->short_name, w->instance_id, '\0');
390 vlib_set_thread_name ((char *) w->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 }
392
393 if (!w->registration->use_pthreads)
394 {
395
396 /* Initial barrier sync, for both worker and i/o threads */
Sirshak Das2f6d7bb2018-10-03 22:53:51 +0000397 clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398
399 while (*vlib_worker_threads->wait_at_barrier)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400400 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401
Sirshak Das2f6d7bb2018-10-03 22:53:51 +0000402 clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, -1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403 }
404}
405
Dave Barach9b8ffd92016-07-08 08:13:45 -0400406void *
407vlib_worker_thread_bootstrap_fn (void *arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 vlib_worker_thread_t *w = arg;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400410
Tom Jonesd346b882024-01-29 10:55:09 +0000411#ifdef __FreeBSD__
412 w->lwp = pthread_getthreadid_np ();
413#else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400414 w->lwp = syscall (SYS_gettid);
Tom Jonesd346b882024-01-29 10:55:09 +0000415#endif /* __FreeBSD__ */
Pavel Kotucek98765202016-10-07 08:37:28 +0200416 w->thread_id = pthread_self ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417
Damjan Marionf55f9b82017-05-10 21:06:28 +0200418 __os_thread_index = w - vlib_worker_threads;
Damjan Marion586afd72017-04-05 19:18:20 +0200419
Damjan Marion7bf23172022-03-28 01:47:33 +0200420 if (CLIB_DEBUG > 0)
421 {
422 void *frame_addr = __builtin_frame_address (0);
423 if (frame_addr < (void *) w->thread_stack ||
424 frame_addr > (void *) w->thread_stack + VLIB_THREAD_STACK_SIZE)
425 {
426 /* heap is not set yet */
427 fprintf (stderr, "thread stack is not set properly\n");
428 exit (1);
429 }
430 }
Dave Barach37579c32021-07-27 09:27:07 -0400431
Damjan Marion7bf23172022-03-28 01:47:33 +0200432 w->thread_function (arg);
433
434 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435}
436
Dave Baracha690fdb2020-01-21 12:34:55 -0500437void
438vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id)
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200439{
Lijian.Zhang4fbb9da2020-02-14 15:16:49 +0800440 clib_bitmap_t *nbmp = 0, *cbmp = 0;
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000441 int node, core_id = -1, numa_id = -1;
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200442
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000443 core_id = os_get_cpu_phys_core_id (cpu_id);
Damjan Marion4b661402024-02-29 16:14:27 +0100444 nbmp = os_get_online_cpu_node_bitmap ();
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000445
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100446 clib_bitmap_foreach (node, nbmp) {
Damjan Marion3eb6cbe2024-02-12 19:44:58 +0000447 cbmp = os_get_cpu_on_node_bitmap (node);
448 if (clib_bitmap_get (cbmp, cpu_id))
449 numa_id = node;
450 vec_reset_length (cbmp);
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100451 }
Damjan Marion4b661402024-02-29 16:14:27 +0100452
Lijian.Zhang4fbb9da2020-02-14 15:16:49 +0800453 vec_free (nbmp);
454 vec_free (cbmp);
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200455
456 w->core_id = core_id;
Dave Baracha690fdb2020-01-21 12:34:55 -0500457 w->numa_id = numa_id;
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200458}
459
Damjan Marion878c6092017-01-04 13:19:27 +0100460static clib_error_t *
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200461vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462{
Damjan Marion57d1ec02020-09-16 21:15:44 +0200463 clib_mem_main_t *mm = &clib_mem_main;
Damjan Marion878c6092017-01-04 13:19:27 +0100464 vlib_thread_main_t *tm = &vlib_thread_main;
Damjan Mariona2b7a022021-12-28 20:32:20 +0100465 pthread_t worker;
Damjan Marion7bf23172022-03-28 01:47:33 +0200466 pthread_attr_t attr;
Damjan Mariona2b7a022021-12-28 20:32:20 +0100467 cpu_set_t cpuset;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400468 void *(*fp_arg) (void *) = fp;
Dave Baracha690fdb2020-01-21 12:34:55 -0500469 void *numa_heap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200471 w->cpu_id = cpu_id;
Dave Baracha690fdb2020-01-21 12:34:55 -0500472 vlib_get_thread_core_numa (w, cpu_id);
Dave Baracha690fdb2020-01-21 12:34:55 -0500473
474 /* Set up NUMA-bound heap if indicated */
Damjan Marion57d1ec02020-09-16 21:15:44 +0200475 if (mm->per_numa_mheaps[w->numa_id] == 0)
Dave Baracha690fdb2020-01-21 12:34:55 -0500476 {
477 /* If the user requested a NUMA heap, create it... */
478 if (tm->numa_heap_size)
479 {
Damjan Marion2bc1af52020-10-02 15:01:12 +0200480 clib_mem_set_numa_affinity (w->numa_id, 1 /* force */ );
481 numa_heap = clib_mem_create_heap (0 /* DIY */ , tm->numa_heap_size,
482 1 /* is_locked */ ,
483 "numa %u heap", w->numa_id);
484 clib_mem_set_default_numa_affinity ();
Damjan Marion57d1ec02020-09-16 21:15:44 +0200485 mm->per_numa_mheaps[w->numa_id] = numa_heap;
Dave Baracha690fdb2020-01-21 12:34:55 -0500486 }
487 else
488 {
489 /* Or, use the main heap */
Damjan Marion57d1ec02020-09-16 21:15:44 +0200490 mm->per_numa_mheaps[w->numa_id] = w->thread_mheap;
Dave Baracha690fdb2020-01-21 12:34:55 -0500491 }
492 }
493
Dave Barach9b8ffd92016-07-08 08:13:45 -0400494 CPU_ZERO (&cpuset);
Mohsin Kazmi5d64c782018-09-11 20:27:09 +0200495 CPU_SET (cpu_id, &cpuset);
Christophe Fontainefef15b42016-04-09 12:38:49 +0900496
Damjan Marion7bf23172022-03-28 01:47:33 +0200497 if (pthread_attr_init (&attr))
498 return clib_error_return_unix (0, "pthread_attr_init");
499
500 if (pthread_attr_setstack (&attr, w->thread_stack,
501 VLIB_THREAD_STACK_SIZE))
502 return clib_error_return_unix (0, "pthread_attr_setstack");
503
504 if (pthread_create (&worker, &attr, fp_arg, (void *) w))
Damjan Marion878c6092017-01-04 13:19:27 +0100505 return clib_error_return_unix (0, "pthread_create");
506
507 if (pthread_setaffinity_np (worker, sizeof (cpu_set_t), &cpuset))
508 return clib_error_return_unix (0, "pthread_setaffinity_np");
509
Damjan Marion7bf23172022-03-28 01:47:33 +0200510 if (pthread_attr_destroy (&attr))
511 return clib_error_return_unix (0, "pthread_attr_destroy");
512
Damjan Marion878c6092017-01-04 13:19:27 +0100513 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700514}
515
Dave Barach9b8ffd92016-07-08 08:13:45 -0400516static clib_error_t *
517start_workers (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518{
Damjan Marionfd8deb42021-03-06 12:26:28 +0100519 vlib_global_main_t *vgm = vlib_get_global_main ();
Damjan Marion66c85832022-03-14 13:04:38 +0100520 vlib_main_t *fvm = vlib_get_first_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521 int i, j;
522 vlib_worker_thread_t *w;
523 vlib_main_t *vm_clone;
524 void *oldheap;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400525 vlib_thread_main_t *tm = &vlib_thread_main;
526 vlib_thread_registration_t *tr;
527 vlib_node_runtime_t *rt;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528 u32 n_vlib_mains = tm->n_vlib_mains;
529 u32 worker_thread_index;
Damjan Marion66c85832022-03-14 13:04:38 +0100530 u32 stats_err_entry_index = fvm->error_main.stats_err_entry_index;
Damjan Marionbfa75d62020-10-06 17:46:06 +0200531 clib_mem_heap_t *main_heap = clib_mem_get_per_cpu_heap ();
Ole Troana606d922021-05-05 09:23:17 +0200532 vlib_stats_register_mem_heap (main_heap);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400533
Ed Warnickecb9cada2015-12-08 15:45:58 -0700534 vec_reset_length (vlib_worker_threads);
535
536 /* Set up the main thread */
537 vec_add2_aligned (vlib_worker_threads, w, 1, CLIB_CACHE_LINE_BYTES);
Dave Barach3e7deb12016-02-05 16:29:53 -0500538 w->elog_track.name = "main thread";
Damjan Marionf553a2c2021-03-26 13:45:37 +0100539 elog_track_register (vlib_get_elog_main (), &w->elog_track);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540
Dave Barach9b8ffd92016-07-08 08:13:45 -0400541 if (vec_len (tm->thread_prefix))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400543 w->name = format (0, "%v_main%c", tm->thread_prefix, '\0');
544 vlib_set_thread_name ((char *) w->name);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 }
546
Damjan Marionfd8deb42021-03-06 12:26:28 +0100547 vgm->elog_main.lock =
Dave Barach9b8ffd92016-07-08 08:13:45 -0400548 clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100549 vgm->elog_main.lock[0] = 0;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400550
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000551 clib_callback_data_init (&vm->vlib_node_runtime_perf_callbacks,
552 &vm->worker_thread_main_loop_callback_lock);
553
Damjan Marionfd8deb42021-03-06 12:26:28 +0100554 vec_validate_aligned (vgm->vlib_mains, n_vlib_mains - 1,
555 CLIB_CACHE_LINE_BYTES);
Damjan Marion8bea5892022-04-04 22:40:45 +0200556 vec_set_len (vgm->vlib_mains, 0);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100557 vec_add1_aligned (vgm->vlib_mains, vm, CLIB_CACHE_LINE_BYTES);
Dave Barach1c556d12020-10-02 11:35:44 -0400558
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559 if (n_vlib_mains > 1)
560 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400561 vlib_worker_threads->wait_at_barrier =
562 clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563 vlib_worker_threads->workers_at_barrier =
Dave Barach9b8ffd92016-07-08 08:13:45 -0400564 clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700565
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100566 vlib_worker_threads->node_reforks_required =
567 clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES);
568
Dave Barachf6c68d72018-11-01 08:12:52 -0400569 /* We'll need the rpc vector lock... */
570 clib_spinlock_init (&vm->pending_rpc_lock);
571
Ed Warnickecb9cada2015-12-08 15:45:58 -0700572 /* Ask for an initial barrier sync */
573 *vlib_worker_threads->workers_at_barrier = 0;
574 *vlib_worker_threads->wait_at_barrier = 1;
575
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100576 /* Without update or refork */
577 *vlib_worker_threads->node_reforks_required = 0;
Damjan Marionfd8deb42021-03-06 12:26:28 +0100578 vgm->need_vlib_worker_thread_node_runtime_update = 0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100579
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100580 /* init timing */
581 vm->barrier_epoch = 0;
582 vm->barrier_no_close_before = 0;
583
Ed Warnickecb9cada2015-12-08 15:45:58 -0700584 worker_thread_index = 1;
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000585 clib_spinlock_init (&vm->worker_thread_main_loop_callback_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586
Dave Barach9b8ffd92016-07-08 08:13:45 -0400587 for (i = 0; i < vec_len (tm->registrations); i++)
588 {
589 vlib_node_main_t *nm, *nm_clone;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400590 int k;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700591
Dave Barach9b8ffd92016-07-08 08:13:45 -0400592 tr = tm->registrations[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700593
Dave Barach9b8ffd92016-07-08 08:13:45 -0400594 if (tr->count == 0)
595 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596
Dave Barach9b8ffd92016-07-08 08:13:45 -0400597 for (k = 0; k < tr->count; k++)
598 {
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100599 vlib_node_t *n;
Damjan Marion66c85832022-03-14 13:04:38 +0100600 u64 **c;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100601
Dave Barach9b8ffd92016-07-08 08:13:45 -0400602 vec_add2 (vlib_worker_threads, w, 1);
Dave Barach6a5adc32018-07-04 10:56:23 -0400603 /* Currently unused, may not really work */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400604 if (tr->mheap_size)
Damjan Marion4537c302020-09-28 19:03:37 +0200605 w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size,
606 /* unlocked */ 0,
607 "%s%d heap",
608 tr->name, k);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400609 else
610 w->thread_mheap = main_heap;
Damjan Marion586afd72017-04-05 19:18:20 +0200611
612 w->thread_stack =
613 vlib_thread_stack_init (w - vlib_worker_threads);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400614 w->thread_function = tr->function;
615 w->thread_function_arg = w;
616 w->instance_id = k;
617 w->registration = tr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618
Dave Barach9b8ffd92016-07-08 08:13:45 -0400619 w->elog_track.name =
620 (char *) format (0, "%s %d", tr->name, k + 1);
621 vec_add1 (w->elog_track.name, 0);
Damjan Marionf553a2c2021-03-26 13:45:37 +0100622 elog_track_register (vlib_get_elog_main (), &w->elog_track);
Bud Grise68adab92016-02-12 10:36:11 -0500623
Dave Barach9b8ffd92016-07-08 08:13:45 -0400624 if (tr->no_data_structure_clone)
625 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700626
Dave Barach9b8ffd92016-07-08 08:13:45 -0400627 /* Fork vlib_global_main et al. Look for bugs here */
628 oldheap = clib_mem_set_heap (w->thread_mheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200630 vm_clone = clib_mem_alloc_aligned (sizeof (*vm_clone),
631 CLIB_CACHE_LINE_BYTES);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100632 clib_memcpy (vm_clone, vlib_get_first_main (),
633 sizeof (*vm_clone));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
Damjan Marion586afd72017-04-05 19:18:20 +0200635 vm_clone->thread_index = worker_thread_index;
Dave Barach2877eee2017-12-15 12:22:57 -0500636 vm_clone->pending_rpc_requests = 0;
637 vec_validate (vm_clone->pending_rpc_requests, 0);
Damjan Marion8bea5892022-04-04 22:40:45 +0200638 vec_set_len (vm_clone->pending_rpc_requests, 0);
Dave Barachb7b92992018-10-17 10:38:51 -0400639 clib_memset (&vm_clone->random_buffer, 0,
640 sizeof (vm_clone->random_buffer));
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +0000641 clib_spinlock_init
642 (&vm_clone->worker_thread_main_loop_callback_lock);
643 clib_callback_data_init
644 (&vm_clone->vlib_node_runtime_perf_callbacks,
645 &vm_clone->worker_thread_main_loop_callback_lock);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646
Damjan Marionfd8deb42021-03-06 12:26:28 +0100647 nm = &vlib_get_first_main ()->node_main;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400648 nm_clone = &vm_clone->node_main;
649 /* fork next frames array, preserving node runtime indices */
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200650 nm_clone->next_frames = vec_dup_aligned (nm->next_frames,
651 CLIB_CACHE_LINE_BYTES);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400652 for (j = 0; j < vec_len (nm_clone->next_frames); j++)
653 {
654 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
655 u32 save_node_runtime_index;
656 u32 save_flags;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657
Dave Barach9b8ffd92016-07-08 08:13:45 -0400658 save_node_runtime_index = nf->node_runtime_index;
659 save_flags = nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
660 vlib_next_frame_init (nf);
661 nf->node_runtime_index = save_node_runtime_index;
662 nf->flags = save_flags;
663 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664
Dave Barach9b8ffd92016-07-08 08:13:45 -0400665 /* fork the frame dispatch queue */
666 nm_clone->pending_frames = 0;
Dave Barach53fe4a72019-01-26 09:50:26 -0500667 vec_validate (nm_clone->pending_frames, 10);
Damjan Marion8bea5892022-04-04 22:40:45 +0200668 vec_set_len (nm_clone->pending_frames, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669
Dave Barach9b8ffd92016-07-08 08:13:45 -0400670 /* fork nodes */
671 nm_clone->nodes = 0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100672
673 /* Allocate all nodes in single block for speed */
674 n = clib_mem_alloc_no_fail (vec_len (nm->nodes) * sizeof (*n));
675
Dave Barach9b8ffd92016-07-08 08:13:45 -0400676 for (j = 0; j < vec_len (nm->nodes); j++)
677 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400678 clib_memcpy (n, nm->nodes[j], sizeof (*n));
679 /* none of the copied nodes have enqueue rights given out */
680 n->owner_node_index = VLIB_INVALID_NODE_INDEX;
Dave Barachb7b92992018-10-17 10:38:51 -0400681 clib_memset (&n->stats_total, 0, sizeof (n->stats_total));
682 clib_memset (&n->stats_last_clear, 0,
683 sizeof (n->stats_last_clear));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400684 vec_add1 (nm_clone->nodes, n);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100685 n++;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400686 }
687 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200688 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
689 CLIB_CACHE_LINE_BYTES);
JingLiuZTE30af5da2017-07-24 10:53:31 +0800690 vec_foreach (rt,
691 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL])
Damjan Marione9f929b2017-03-16 11:32:09 +0100692 {
693 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Damjan Marione9f929b2017-03-16 11:32:09 +0100694 /* copy initial runtime_data from node */
Damjan Marionb6f93a12017-03-16 17:46:41 +0100695 if (n->runtime_data && n->runtime_data_bytes > 0)
Damjan Marione9f929b2017-03-16 11:32:09 +0100696 clib_memcpy (rt->runtime_data, n->runtime_data,
Damjan Marionb6f93a12017-03-16 17:46:41 +0100697 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
698 n->runtime_data_bytes));
Damjan Marione9f929b2017-03-16 11:32:09 +0100699 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700
Dave Barach9b8ffd92016-07-08 08:13:45 -0400701 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200702 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
703 CLIB_CACHE_LINE_BYTES);
Damjan Marion94100532020-11-06 23:25:57 +0100704 clib_interrupt_init (
Damjan Marioncc8249c2023-07-23 14:24:22 +0200705 &nm_clone->input_node_interrupts,
Damjan Marion94100532020-11-06 23:25:57 +0100706 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]));
Damjan Marioncc8249c2023-07-23 14:24:22 +0200707 clib_interrupt_init (
708 &nm_clone->pre_input_node_interrupts,
709 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT]));
Dave Barach9b8ffd92016-07-08 08:13:45 -0400710 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])
Damjan Marione9f929b2017-03-16 11:32:09 +0100711 {
712 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Damjan Marione9f929b2017-03-16 11:32:09 +0100713 /* copy initial runtime_data from node */
Damjan Marionb6f93a12017-03-16 17:46:41 +0100714 if (n->runtime_data && n->runtime_data_bytes > 0)
Damjan Marione9f929b2017-03-16 11:32:09 +0100715 clib_memcpy (rt->runtime_data, n->runtime_data,
Damjan Marionb6f93a12017-03-16 17:46:41 +0100716 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
717 n->runtime_data_bytes));
Damjan Marione9f929b2017-03-16 11:32:09 +0100718 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719
Dave Barach53fe4a72019-01-26 09:50:26 -0500720 nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT] =
721 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT],
722 CLIB_CACHE_LINE_BYTES);
723 vec_foreach (rt,
724 nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT])
725 {
726 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Dave Barach53fe4a72019-01-26 09:50:26 -0500727 /* copy initial runtime_data from node */
728 if (n->runtime_data && n->runtime_data_bytes > 0)
729 clib_memcpy (rt->runtime_data, n->runtime_data,
730 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
731 n->runtime_data_bytes));
732 }
733
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200734 nm_clone->processes = vec_dup_aligned (nm->processes,
735 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736
Dave Barach593eedf2019-03-10 09:44:51 -0400737 /* Create per-thread frame freelist */
Damjan Marionb32bd702021-12-23 17:05:02 +0100738 nm_clone->frame_sizes = 0;
Dave Barach687c9022019-07-23 10:22:31 -0400739 nm_clone->node_by_error = nm->node_by_error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740
Dave Barach9b8ffd92016-07-08 08:13:45 -0400741 /* Packet trace buffers are guaranteed to be empty, nothing to do here */
Damjan Marionbc20bdf2015-12-17 14:28:18 +0100742
Dave Barach9b8ffd92016-07-08 08:13:45 -0400743 clib_mem_set_heap (oldheap);
Damjan Marionfd8deb42021-03-06 12:26:28 +0100744 vec_add1_aligned (vgm->vlib_mains, vm_clone,
745 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746
Ole Troan233e4682019-05-16 15:01:34 +0200747 /* Switch to the stats segment ... */
Damjan Marion66c85832022-03-14 13:04:38 +0100748 vlib_stats_validate (stats_err_entry_index, worker_thread_index,
749 vec_len (fvm->error_main.counters) - 1);
750 c = vlib_stats_get_entry_data_pointer (stats_err_entry_index);
751 vm_clone->error_main.counters = c[worker_thread_index];
Ole Troan233e4682019-05-16 15:01:34 +0200752
Damjan Marionfd8deb42021-03-06 12:26:28 +0100753 vm_clone->error_main.counters_last_clear = vec_dup_aligned (
754 vlib_get_first_main ()->error_main.counters_last_clear,
755 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700756
Dave Barach9b8ffd92016-07-08 08:13:45 -0400757 worker_thread_index++;
758 }
759 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760 }
761 else
762 {
763 /* only have non-data-structure copy threads to create... */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400764 for (i = 0; i < vec_len (tm->registrations); i++)
765 {
766 tr = tm->registrations[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700767
Dave Barach9b8ffd92016-07-08 08:13:45 -0400768 for (j = 0; j < tr->count; j++)
769 {
770 vec_add2 (vlib_worker_threads, w, 1);
771 if (tr->mheap_size)
Dave Barach6a5adc32018-07-04 10:56:23 -0400772 {
Damjan Marion4537c302020-09-28 19:03:37 +0200773 w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size,
774 /* locked */ 0,
775 "%s%d heap",
776 tr->name, j);
Dave Barach6a5adc32018-07-04 10:56:23 -0400777 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400778 else
779 w->thread_mheap = main_heap;
Damjan Marion586afd72017-04-05 19:18:20 +0200780 w->thread_stack =
781 vlib_thread_stack_init (w - vlib_worker_threads);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400782 w->thread_function = tr->function;
783 w->thread_function_arg = w;
784 w->instance_id = j;
785 w->elog_track.name =
786 (char *) format (0, "%s %d", tr->name, j + 1);
787 w->registration = tr;
788 vec_add1 (w->elog_track.name, 0);
Damjan Marionf553a2c2021-03-26 13:45:37 +0100789 elog_track_register (vlib_get_elog_main (), &w->elog_track);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400790 }
791 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792 }
793
794 worker_thread_index = 1;
795
796 for (i = 0; i < vec_len (tm->registrations); i++)
797 {
Damjan Marion878c6092017-01-04 13:19:27 +0100798 clib_error_t *err;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799 int j;
800
801 tr = tm->registrations[i];
802
803 if (tr->use_pthreads || tm->use_pthreads)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400804 {
805 for (j = 0; j < tr->count; j++)
806 {
hsandid832342e2023-12-20 15:41:54 +0100807
Dave Barach9b8ffd92016-07-08 08:13:45 -0400808 w = vlib_worker_threads + worker_thread_index++;
Damjan Marion878c6092017-01-04 13:19:27 +0100809 err = vlib_launch_thread_int (vlib_worker_thread_bootstrap_fn,
810 w, 0);
811 if (err)
hsandid832342e2023-12-20 15:41:54 +0100812 clib_unix_error ("%U, thread %s init on cpu %d failed",
813 format_clib_error, err, tr->name, 0);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400814 }
815 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816 else
Dave Barach9b8ffd92016-07-08 08:13:45 -0400817 {
818 uword c;
Damjan Marionf0ca1e82020-12-13 23:26:56 +0100819 clib_bitmap_foreach (c, tr->coremask) {
Damjan Marion878c6092017-01-04 13:19:27 +0100820 w = vlib_worker_threads + worker_thread_index++;
821 err = vlib_launch_thread_int (vlib_worker_thread_bootstrap_fn,
822 w, c);
823 if (err)
hsandid832342e2023-12-20 15:41:54 +0100824 clib_unix_error ("%U, thread %s init on cpu %d failed",
825 format_clib_error, err, tr->name, c);
826 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400827 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400829 vlib_worker_thread_barrier_sync (vm);
Damjan Marion321bd102022-06-01 00:45:18 +0200830 {
831 clib_error_t *err;
832 err = vlib_call_init_exit_functions (
833 vm, &vgm->num_workers_change_function_registrations, 1 /* call_once */,
834 1 /* is_global */);
835 if (err)
836 clib_error_report (err);
837 }
Dave Barach9b8ffd92016-07-08 08:13:45 -0400838 vlib_worker_thread_barrier_release (vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 return 0;
840}
841
842VLIB_MAIN_LOOP_ENTER_FUNCTION (start_workers);
843
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +0100844
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100845static inline void
846worker_thread_node_runtime_update_internal (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847{
848 int i, j;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700849 vlib_main_t *vm;
850 vlib_node_main_t *nm, *nm_clone;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851 vlib_main_t *vm_clone;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100852 vlib_node_runtime_t *rt;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400853
Damjan Marion586afd72017-04-05 19:18:20 +0200854 ASSERT (vlib_get_thread_index () == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100856 vm = vlib_get_first_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857 nm = &vm->node_main;
858
Ed Warnickecb9cada2015-12-08 15:45:58 -0700859 ASSERT (*vlib_worker_threads->wait_at_barrier == 1);
860
Dave Barach9b8ffd92016-07-08 08:13:45 -0400861 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862 * Scrape all runtime stats, so we don't lose node runtime(s) with
863 * pending counts, or throw away worker / io thread counts.
864 */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400865 for (j = 0; j < vec_len (nm->nodes); j++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700866 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400867 vlib_node_t *n;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868 n = nm->nodes[j];
869 vlib_node_sync_stats (vm, n);
870 }
871
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100872 for (i = 1; i < vlib_get_n_threads (); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873 {
Dave Barach9b8ffd92016-07-08 08:13:45 -0400874 vlib_node_t *n;
875
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100876 vm_clone = vlib_get_main_by_index (i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700877 nm_clone = &vm_clone->node_main;
878
Dave Barach9b8ffd92016-07-08 08:13:45 -0400879 for (j = 0; j < vec_len (nm_clone->nodes); j++)
880 {
881 n = nm_clone->nodes[j];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700882
Dave Barach9b8ffd92016-07-08 08:13:45 -0400883 rt = vlib_node_get_runtime (vm_clone, n->index);
884 vlib_node_runtime_sync_stats (vm_clone, rt, 0, 0, 0);
885 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886 }
887
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100888 /* Per-worker clone rebuilds are now done on each thread */
889}
890
891
892void
893vlib_worker_thread_node_refork (void)
894{
895 vlib_main_t *vm, *vm_clone;
896 vlib_node_main_t *nm, *nm_clone;
897 vlib_node_t **old_nodes_clone;
898 vlib_node_runtime_t *rt, *old_rt;
Damjan Marion66c85832022-03-14 13:04:38 +0100899 u64 **c;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100900
901 vlib_node_t *new_n_clone;
902
903 int j;
904
Damjan Marion6ffb7c62021-03-26 13:06:13 +0100905 vm = vlib_get_first_main ();
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100906 nm = &vm->node_main;
907 vm_clone = vlib_get_main ();
908 nm_clone = &vm_clone->node_main;
909
910 /* Re-clone error heap */
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100911 u64 *old_counters_all_clear = vm_clone->error_main.counters_last_clear;
912
Dave Barach178cf492018-11-13 16:34:13 -0500913 clib_memcpy_fast (&vm_clone->error_main, &vm->error_main,
914 sizeof (vm->error_main));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100915 j = vec_len (vm->error_main.counters) - 1;
Ole Troan233e4682019-05-16 15:01:34 +0200916
Damjan Marion66c85832022-03-14 13:04:38 +0100917 c = vlib_stats_get_entry_data_pointer (vm->error_main.stats_err_entry_index);
918 vm_clone->error_main.counters = c[vm_clone->thread_index];
Ole Troan233e4682019-05-16 15:01:34 +0200919
920 vec_validate_aligned (old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100921 vm_clone->error_main.counters_last_clear = old_counters_all_clear;
922
Dmitry Valter9f5b3692022-09-05 15:30:18 +0000923 for (j = 0; j < vec_len (nm_clone->next_frames); j++)
924 {
925 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
926 if ((nf->flags & VLIB_FRAME_IS_ALLOCATED) && nf->frame != NULL)
927 {
928 vlib_frame_t *f = nf->frame;
929 nf->frame = NULL;
930 vlib_frame_free (vm_clone, f);
931 }
932 }
933
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100934 vec_free (nm_clone->next_frames);
Damjan Marionbe3f4d52018-03-27 21:06:10 +0200935 nm_clone->next_frames = vec_dup_aligned (nm->next_frames,
936 CLIB_CACHE_LINE_BYTES);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100937
938 for (j = 0; j < vec_len (nm_clone->next_frames); j++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700939 {
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100940 vlib_next_frame_t *nf = &nm_clone->next_frames[j];
941 u32 save_node_runtime_index;
942 u32 save_flags;
Damjan Marionbc20bdf2015-12-17 14:28:18 +0100943
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100944 save_node_runtime_index = nf->node_runtime_index;
945 save_flags = nf->flags & VLIB_FRAME_NO_FREE_AFTER_DISPATCH;
946 vlib_next_frame_init (nf);
947 nf->node_runtime_index = save_node_runtime_index;
948 nf->flags = save_flags;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700949 }
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100950
951 old_nodes_clone = nm_clone->nodes;
952 nm_clone->nodes = 0;
953
954 /* re-fork nodes */
955
956 /* Allocate all nodes in single block for speed */
957 new_n_clone =
958 clib_mem_alloc_no_fail (vec_len (nm->nodes) * sizeof (*new_n_clone));
959 for (j = 0; j < vec_len (nm->nodes); j++)
960 {
Benoît Ganne5517bd32019-08-30 16:20:12 +0200961 vlib_node_t *new_n = nm->nodes[j];
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100962
Dave Barach178cf492018-11-13 16:34:13 -0500963 clib_memcpy_fast (new_n_clone, new_n, sizeof (*new_n));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100964 /* none of the copied nodes have enqueue rights given out */
965 new_n_clone->owner_node_index = VLIB_INVALID_NODE_INDEX;
966
967 if (j >= vec_len (old_nodes_clone))
968 {
969 /* new node, set to zero */
Dave Barachb7b92992018-10-17 10:38:51 -0400970 clib_memset (&new_n_clone->stats_total, 0,
971 sizeof (new_n_clone->stats_total));
972 clib_memset (&new_n_clone->stats_last_clear, 0,
973 sizeof (new_n_clone->stats_last_clear));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100974 }
975 else
976 {
Benoît Ganne5517bd32019-08-30 16:20:12 +0200977 vlib_node_t *old_n_clone = old_nodes_clone[j];
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100978 /* Copy stats if the old data is valid */
Dave Barach178cf492018-11-13 16:34:13 -0500979 clib_memcpy_fast (&new_n_clone->stats_total,
980 &old_n_clone->stats_total,
981 sizeof (new_n_clone->stats_total));
982 clib_memcpy_fast (&new_n_clone->stats_last_clear,
983 &old_n_clone->stats_last_clear,
984 sizeof (new_n_clone->stats_last_clear));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100985
986 /* keep previous node state */
987 new_n_clone->state = old_n_clone->state;
Maxime Peimdde163d2021-04-15 13:52:12 +0200988 new_n_clone->flags = old_n_clone->flags;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +0100989 }
990 vec_add1 (nm_clone->nodes, new_n_clone);
991 new_n_clone++;
992 }
993 /* Free the old node clones */
994 clib_mem_free (old_nodes_clone[0]);
995
996 vec_free (old_nodes_clone);
997
998
999 /* re-clone internal nodes */
1000 old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL];
1001 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +02001002 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INTERNAL],
1003 CLIB_CACHE_LINE_BYTES);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001004
1005 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INTERNAL])
1006 {
1007 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001008 /* copy runtime_data, will be overwritten later for existing rt */
1009 if (n->runtime_data && n->runtime_data_bytes > 0)
Dave Barach178cf492018-11-13 16:34:13 -05001010 clib_memcpy_fast (rt->runtime_data, n->runtime_data,
1011 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
1012 n->runtime_data_bytes));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001013 }
1014
1015 for (j = 0; j < vec_len (old_rt); j++)
1016 {
1017 rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index);
1018 rt->state = old_rt[j].state;
Maxime Peimdde163d2021-04-15 13:52:12 +02001019 rt->flags = old_rt[j].flags;
Dave Barach178cf492018-11-13 16:34:13 -05001020 clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data,
1021 VLIB_NODE_RUNTIME_DATA_SIZE);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001022 }
1023
1024 vec_free (old_rt);
1025
1026 /* re-clone input nodes */
1027 old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT];
1028 nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] =
Damjan Marionbe3f4d52018-03-27 21:06:10 +02001029 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT],
1030 CLIB_CACHE_LINE_BYTES);
Damjan Marion94100532020-11-06 23:25:57 +01001031 clib_interrupt_resize (
Damjan Marioncc8249c2023-07-23 14:24:22 +02001032 &nm_clone->input_node_interrupts,
Damjan Marion94100532020-11-06 23:25:57 +01001033 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]));
Damjan Marioncc8249c2023-07-23 14:24:22 +02001034 clib_interrupt_resize (
1035 &nm_clone->pre_input_node_interrupts,
1036 vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT]));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001037
1038 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])
1039 {
1040 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001041 /* copy runtime_data, will be overwritten later for existing rt */
1042 if (n->runtime_data && n->runtime_data_bytes > 0)
Dave Barach178cf492018-11-13 16:34:13 -05001043 clib_memcpy_fast (rt->runtime_data, n->runtime_data,
1044 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
1045 n->runtime_data_bytes));
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001046 }
1047
1048 for (j = 0; j < vec_len (old_rt); j++)
1049 {
1050 rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index);
1051 rt->state = old_rt[j].state;
Maxime Peimdde163d2021-04-15 13:52:12 +02001052 rt->flags = old_rt[j].flags;
Dave Barach178cf492018-11-13 16:34:13 -05001053 clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data,
1054 VLIB_NODE_RUNTIME_DATA_SIZE);
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001055 }
1056
1057 vec_free (old_rt);
1058
Dave Barach53fe4a72019-01-26 09:50:26 -05001059 /* re-clone pre-input nodes */
1060 old_rt = nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT];
1061 nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT] =
1062 vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT],
1063 CLIB_CACHE_LINE_BYTES);
1064
1065 vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_PRE_INPUT])
1066 {
1067 vlib_node_t *n = vlib_get_node (vm, rt->node_index);
Dave Barach53fe4a72019-01-26 09:50:26 -05001068 /* copy runtime_data, will be overwritten later for existing rt */
1069 if (n->runtime_data && n->runtime_data_bytes > 0)
1070 clib_memcpy_fast (rt->runtime_data, n->runtime_data,
1071 clib_min (VLIB_NODE_RUNTIME_DATA_SIZE,
1072 n->runtime_data_bytes));
1073 }
1074
1075 for (j = 0; j < vec_len (old_rt); j++)
1076 {
1077 rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index);
1078 rt->state = old_rt[j].state;
Maxime Peimdde163d2021-04-15 13:52:12 +02001079 rt->flags = old_rt[j].flags;
Dave Barach53fe4a72019-01-26 09:50:26 -05001080 clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data,
1081 VLIB_NODE_RUNTIME_DATA_SIZE);
1082 }
1083
1084 vec_free (old_rt);
1085
Vladislav Grishenko29733502021-09-25 21:00:59 +05001086 vec_free (nm_clone->processes);
Damjan Marionbe3f4d52018-03-27 21:06:10 +02001087 nm_clone->processes = vec_dup_aligned (nm->processes,
1088 CLIB_CACHE_LINE_BYTES);
Dave Barach687c9022019-07-23 10:22:31 -04001089 nm_clone->node_by_error = nm->node_by_error;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001090}
1091
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001092void
1093vlib_worker_thread_node_runtime_update (void)
1094{
1095 /*
1096 * Make a note that we need to do a node runtime update
1097 * prior to releasing the barrier.
1098 */
1099 vlib_global_main.need_vlib_worker_thread_node_runtime_update = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001100}
1101
Pavel Kotucek1e765832016-09-23 08:54:14 +02001102u32
1103unformat_sched_policy (unformat_input_t * input, va_list * args)
1104{
1105 u32 *r = va_arg (*args, u32 *);
1106
1107 if (0);
1108#define _(v,f,s) else if (unformat (input, s)) *r = SCHED_POLICY_##f;
1109 foreach_sched_policy
1110#undef _
1111 else
1112 return 0;
1113 return 1;
1114}
1115
Ed Warnickecb9cada2015-12-08 15:45:58 -07001116static clib_error_t *
1117cpu_config (vlib_main_t * vm, unformat_input_t * input)
1118{
1119 vlib_thread_registration_t *tr;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001120 uword *p;
1121 vlib_thread_main_t *tm = &vlib_thread_main;
1122 u8 *name;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001123 uword *bitmap;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001124 u32 count;
1125
1126 tm->thread_registrations_by_name = hash_create_string (0, sizeof (uword));
Pavel Kotucek1e765832016-09-23 08:54:14 +02001127
Dave Barach9b8ffd92016-07-08 08:13:45 -04001128 tm->n_thread_stacks = 1; /* account for main thread */
Pavel Kotucek1e765832016-09-23 08:54:14 +02001129 tm->sched_policy = ~0;
1130 tm->sched_priority = ~0;
Damjan Marion858151f2018-07-11 10:51:00 +02001131 tm->main_lcore = ~0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132
1133 tr = tm->next;
1134
1135 while (tr)
1136 {
Dave Barach9b8ffd92016-07-08 08:13:45 -04001137 hash_set_mem (tm->thread_registrations_by_name, tr->name, (uword) tr);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001138 tr = tr->next;
1139 }
1140
Dave Barach9b8ffd92016-07-08 08:13:45 -04001141 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001142 {
Damjan Marionbf741472016-06-13 22:49:44 +02001143 if (unformat (input, "use-pthreads"))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001144 tm->use_pthreads = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145 else if (unformat (input, "thread-prefix %v", &tm->thread_prefix))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001146 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147 else if (unformat (input, "main-core %u", &tm->main_lcore))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001148 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149 else if (unformat (input, "skip-cores %u", &tm->skip_cores))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001150 ;
Dave Baracha690fdb2020-01-21 12:34:55 -05001151 else if (unformat (input, "numa-heap-size %U",
1152 unformat_memory_size, &tm->numa_heap_size))
1153 ;
Yi Hee4a9eb72018-07-17 14:18:41 +08001154 else if (unformat (input, "coremask-%s %U", &name,
1155 unformat_bitmap_mask, &bitmap) ||
1156 unformat (input, "corelist-%s %U", &name,
1157 unformat_bitmap_list, &bitmap))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001158 {
1159 p = hash_get_mem (tm->thread_registrations_by_name, name);
1160 if (p == 0)
1161 return clib_error_return (0, "no such thread type '%s'", name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162
Dave Barach9b8ffd92016-07-08 08:13:45 -04001163 tr = (vlib_thread_registration_t *) p[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164
Dave Barach9b8ffd92016-07-08 08:13:45 -04001165 if (tr->use_pthreads)
1166 return clib_error_return (0,
1167 "corelist cannot be set for '%s' threads",
1168 name);
Vladimir Isaev18a4a372020-03-17 12:30:11 +03001169 if (tr->count)
1170 return clib_error_return
1171 (0, "core placement of '%s' threads is already configured",
1172 name);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001173
Dave Barach9b8ffd92016-07-08 08:13:45 -04001174 tr->coremask = bitmap;
1175 tr->count = clib_bitmap_count_set_bits (tr->coremask);
1176 }
Pavel Kotucek1e765832016-09-23 08:54:14 +02001177 else
1178 if (unformat
1179 (input, "scheduler-policy %U", unformat_sched_policy,
1180 &tm->sched_policy))
1181 ;
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001182 else if (unformat (input, "scheduler-priority %u", &tm->sched_priority))
Pavel Kotucek1e765832016-09-23 08:54:14 +02001183 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001184 else if (unformat (input, "%s %u", &name, &count))
Dave Barach9b8ffd92016-07-08 08:13:45 -04001185 {
1186 p = hash_get_mem (tm->thread_registrations_by_name, name);
1187 if (p == 0)
Pavel Kotucek1e765832016-09-23 08:54:14 +02001188 return clib_error_return (0, "no such thread type 3 '%s'", name);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001189
1190 tr = (vlib_thread_registration_t *) p[0];
Vladimir Isaev18a4a372020-03-17 12:30:11 +03001191
Dave Barach9b8ffd92016-07-08 08:13:45 -04001192 if (tr->fixed_count)
1193 return clib_error_return
Vladimir Isaev18a4a372020-03-17 12:30:11 +03001194 (0, "number of '%s' threads not configurable", name);
1195 if (tr->count)
1196 return clib_error_return
1197 (0, "number of '%s' threads is already configured", name);
1198
Dave Barach9b8ffd92016-07-08 08:13:45 -04001199 tr->count = count;
1200 }
1201 else
1202 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203 }
1204
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001205 if (tm->sched_priority != ~0)
Pavel Kotucek1e765832016-09-23 08:54:14 +02001206 {
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001207 if (tm->sched_policy == SCHED_FIFO || tm->sched_policy == SCHED_RR)
Pavel Kotucek1e765832016-09-23 08:54:14 +02001208 {
1209 u32 prio_max = sched_get_priority_max (tm->sched_policy);
1210 u32 prio_min = sched_get_priority_min (tm->sched_policy);
1211 if (tm->sched_priority > prio_max)
1212 tm->sched_priority = prio_max;
1213 if (tm->sched_priority < prio_min)
1214 tm->sched_priority = prio_min;
1215 }
1216 else
Pavel Kotucekc08a1ed2016-09-23 08:54:14 +02001217 {
1218 return clib_error_return
1219 (0,
1220 "scheduling priority (%d) is not allowed for `normal` scheduling policy",
1221 tm->sched_priority);
1222 }
Pavel Kotucek1e765832016-09-23 08:54:14 +02001223 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001224 tr = tm->next;
1225
1226 if (!tm->thread_prefix)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001227 tm->thread_prefix = format (0, "vpp");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001228
1229 while (tr)
1230 {
1231 tm->n_thread_stacks += tr->count;
1232 tm->n_pthreads += tr->count * tr->use_pthreads;
Damjan Marion878c6092017-01-04 13:19:27 +01001233 tm->n_threads += tr->count * (tr->use_pthreads == 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001234 tr = tr->next;
1235 }
1236
1237 return 0;
1238}
1239
1240VLIB_EARLY_CONFIG_FUNCTION (cpu_config, "cpu");
1241
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001242 /*
1243 * Enforce minimum open time to minimize packet loss due to Rx overflow,
1244 * based on a test based heuristic that barrier should be open for at least
1245 * 3 time as long as it is closed (with an upper bound of 1ms because by that
1246 * point it is probably too late to make a difference)
1247 */
1248
1249#ifndef BARRIER_MINIMUM_OPEN_LIMIT
1250#define BARRIER_MINIMUM_OPEN_LIMIT 0.001
1251#endif
1252
1253#ifndef BARRIER_MINIMUM_OPEN_FACTOR
1254#define BARRIER_MINIMUM_OPEN_FACTOR 3
1255#endif
1256
Dave Barach9b8ffd92016-07-08 08:13:45 -04001257void
Dave Barachc602b382019-06-03 19:48:22 -04001258vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm)
1259{
1260 f64 deadline;
1261 f64 now = vlib_time_now (vm);
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001262 u32 count = vlib_get_n_threads () - 1;
Dave Barachc602b382019-06-03 19:48:22 -04001263
1264 /* No worker threads? */
1265 if (count == 0)
1266 return;
1267
1268 deadline = now + BARRIER_SYNC_TIMEOUT;
1269 *vlib_worker_threads->wait_at_barrier = 1;
1270 while (*vlib_worker_threads->workers_at_barrier != count)
1271 {
1272 if ((now = vlib_time_now (vm)) > deadline)
1273 {
1274 fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
1275 os_panic ();
1276 }
1277 CLIB_PAUSE ();
1278 }
1279 *vlib_worker_threads->wait_at_barrier = 0;
1280}
1281
Neale Ranns42845dd2020-05-26 13:12:17 +00001282/**
1283 * Return true if the wroker thread barrier is held
1284 */
1285u8
1286vlib_worker_thread_barrier_held (void)
1287{
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001288 if (vlib_get_n_threads () < 2)
Neale Ranns42845dd2020-05-26 13:12:17 +00001289 return (1);
1290
1291 return (*vlib_worker_threads->wait_at_barrier == 1);
1292}
1293
Dave Barachc602b382019-06-03 19:48:22 -04001294void
Damjan Marion8343ee52019-02-26 17:15:48 +01001295vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296{
1297 f64 deadline;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001298 f64 now;
1299 f64 t_entry;
1300 f64 t_open;
1301 f64 t_closed;
Dave Barach9ae190e2019-04-23 10:07:24 -04001302 f64 max_vector_rate;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001303 u32 count;
Dave Barach9ae190e2019-04-23 10:07:24 -04001304 int i;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001305
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001306 if (vlib_get_n_threads () < 2)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001307 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001308
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001309 ASSERT (vlib_get_thread_index () == 0);
1310
Damjan Marion8343ee52019-02-26 17:15:48 +01001311 vlib_worker_threads[0].barrier_caller = func_name;
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001312 count = vlib_get_n_threads () - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001313
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001314 /* Record entry relative to last close */
1315 now = vlib_time_now (vm);
1316 t_entry = now - vm->barrier_epoch;
1317
Ed Warnickecb9cada2015-12-08 15:45:58 -07001318 /* Tolerate recursive calls */
1319 if (++vlib_worker_threads[0].recursion_level > 1)
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001320 {
1321 barrier_trace_sync_rec (t_entry);
1322 return;
1323 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001324
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +00001325 if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0))
1326 clib_call_callbacks (vm->barrier_perf_callbacks, vm,
1327 vm->clib_time.last_cpu_time, 0 /* enter */ );
1328
Dave Barach9ae190e2019-04-23 10:07:24 -04001329 /*
1330 * Need data to decide if we're working hard enough to honor
1331 * the barrier hold-down timer.
1332 */
1333 max_vector_rate = 0.0;
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001334 for (i = 1; i < vlib_get_n_threads (); i++)
1335 {
1336 vlib_main_t *ovm = vlib_get_main_by_index (i);
1337 max_vector_rate = clib_max (max_vector_rate,
1338 (f64) vlib_last_vectors_per_main_loop (ovm));
1339 }
Dave Barach9ae190e2019-04-23 10:07:24 -04001340
Bud Grise42f20062016-03-16 13:09:46 -04001341 vlib_worker_threads[0].barrier_sync_count++;
1342
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001343 /* Enforce minimum barrier open time to minimize packet loss */
1344 ASSERT (vm->barrier_no_close_before <= (now + BARRIER_MINIMUM_OPEN_LIMIT));
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001345
Dave Barach9ae190e2019-04-23 10:07:24 -04001346 /*
1347 * If any worker thread seems busy, which we define
1348 * as a vector rate above 10, we enforce the barrier hold-down timer
1349 */
1350 if (max_vector_rate > 10.0)
Dave Barach36feebb2018-09-07 11:12:27 -04001351 {
Dave Barach9ae190e2019-04-23 10:07:24 -04001352 while (1)
Dave Barach36feebb2018-09-07 11:12:27 -04001353 {
Dave Barach9ae190e2019-04-23 10:07:24 -04001354 now = vlib_time_now (vm);
1355 /* Barrier hold-down timer expired? */
1356 if (now >= vm->barrier_no_close_before)
1357 break;
1358 if ((vm->barrier_no_close_before - now)
1359 > (2.0 * BARRIER_MINIMUM_OPEN_LIMIT))
1360 {
1361 clib_warning
1362 ("clock change: would have waited for %.4f seconds",
1363 (vm->barrier_no_close_before - now));
1364 break;
1365 }
Dave Barach36feebb2018-09-07 11:12:27 -04001366 }
1367 }
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001368 /* Record time of closure */
1369 t_open = now - vm->barrier_epoch;
1370 vm->barrier_epoch = now;
1371
1372 deadline = now + BARRIER_SYNC_TIMEOUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001373
1374 *vlib_worker_threads->wait_at_barrier = 1;
1375 while (*vlib_worker_threads->workers_at_barrier != count)
1376 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001377 if ((now = vlib_time_now (vm)) > deadline)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001378 {
1379 fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
1380 os_panic ();
1381 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001382 }
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001383
1384 t_closed = now - vm->barrier_epoch;
1385
1386 barrier_trace_sync (t_entry, t_open, t_closed);
1387
Ed Warnickecb9cada2015-12-08 15:45:58 -07001388}
1389
Dave Barach9b8ffd92016-07-08 08:13:45 -04001390void
1391vlib_worker_thread_barrier_release (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001392{
Damjan Marionfd8deb42021-03-06 12:26:28 +01001393 vlib_global_main_t *vgm = vlib_get_global_main ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001394 f64 deadline;
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001395 f64 now;
1396 f64 minimum_open;
1397 f64 t_entry;
1398 f64 t_closed_total;
1399 f64 t_update_main = 0.0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001400 int refork_needed = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001401
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001402 if (vlib_get_n_threads () < 2)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001403 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001404
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001405 ASSERT (vlib_get_thread_index () == 0);
1406
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001407
1408 now = vlib_time_now (vm);
1409 t_entry = now - vm->barrier_epoch;
1410
Ed Warnickecb9cada2015-12-08 15:45:58 -07001411 if (--vlib_worker_threads[0].recursion_level > 0)
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001412 {
1413 barrier_trace_release_rec (t_entry);
1414 return;
1415 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001416
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001417 /* Update (all) node runtimes before releasing the barrier, if needed */
Damjan Marionfd8deb42021-03-06 12:26:28 +01001418 if (vgm->need_vlib_worker_thread_node_runtime_update)
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001419 {
Dave Barach1ddbc012018-06-13 09:26:05 -04001420 /*
1421 * Lock stat segment here, so we's safe when
1422 * rebuilding the stat segment node clones from the
1423 * stat thread...
1424 */
Damjan Marion8973b072022-03-01 15:51:18 +01001425 vlib_stats_segment_lock ();
Dave Barach1ddbc012018-06-13 09:26:05 -04001426
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001427 /* Do stats elements on main thread */
1428 worker_thread_node_runtime_update_internal ();
Damjan Marionfd8deb42021-03-06 12:26:28 +01001429 vgm->need_vlib_worker_thread_node_runtime_update = 0;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001430
1431 /* Do per thread rebuilds in parallel */
1432 refork_needed = 1;
Sirshak Das2f6d7bb2018-10-03 22:53:51 +00001433 clib_atomic_fetch_add (vlib_worker_threads->node_reforks_required,
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001434 (vlib_get_n_threads () - 1));
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001435 now = vlib_time_now (vm);
1436 t_update_main = now - vm->barrier_epoch;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001437 }
1438
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001439 deadline = now + BARRIER_SYNC_TIMEOUT;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001440
Dave Baracha4324a92019-02-19 17:05:30 -05001441 /*
1442 * Note when we let go of the barrier.
1443 * Workers can use this to derive a reasonably accurate
1444 * time offset. See vlib_time_now(...)
1445 */
1446 vm->time_last_barrier_release = vlib_time_now (vm);
1447 CLIB_MEMORY_STORE_BARRIER ();
1448
Ed Warnickecb9cada2015-12-08 15:45:58 -07001449 *vlib_worker_threads->wait_at_barrier = 0;
1450
1451 while (*vlib_worker_threads->workers_at_barrier > 0)
1452 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001453 if ((now = vlib_time_now (vm)) > deadline)
Dave Barach9b8ffd92016-07-08 08:13:45 -04001454 {
1455 fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__);
1456 os_panic ();
1457 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001458 }
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001459
1460 /* Wait for reforks before continuing */
1461 if (refork_needed)
1462 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001463 now = vlib_time_now (vm);
1464
1465 deadline = now + BARRIER_SYNC_TIMEOUT;
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001466
1467 while (*vlib_worker_threads->node_reforks_required > 0)
1468 {
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001469 if ((now = vlib_time_now (vm)) > deadline)
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001470 {
1471 fformat (stderr, "%s: worker thread refork deadlock\n",
1472 __FUNCTION__);
1473 os_panic ();
1474 }
1475 }
Damjan Marion8973b072022-03-01 15:51:18 +01001476 vlib_stats_segment_unlock ();
Colin Tregenza Dancer21596182017-09-04 15:27:49 +01001477 }
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001478
1479 t_closed_total = now - vm->barrier_epoch;
1480
1481 minimum_open = t_closed_total * BARRIER_MINIMUM_OPEN_FACTOR;
1482
1483 if (minimum_open > BARRIER_MINIMUM_OPEN_LIMIT)
1484 {
1485 minimum_open = BARRIER_MINIMUM_OPEN_LIMIT;
1486 }
1487
1488 vm->barrier_no_close_before = now + minimum_open;
1489
1490 /* Record barrier epoch (used to enforce minimum open time) */
1491 vm->barrier_epoch = now;
1492
1493 barrier_trace_release (t_entry, t_closed_total, t_update_main);
1494
Tom Seidenberg6c81f5a2020-07-10 15:49:03 +00001495 if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0))
1496 clib_call_callbacks (vm->barrier_perf_callbacks, vm,
1497 vm->clib_time.last_cpu_time, 1 /* leave */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001498}
1499
Florin Coras4b208302022-03-30 13:50:19 -07001500static void
1501vlib_worker_sync_rpc (void *args)
1502{
1503 ASSERT (vlib_thread_is_main_w_barrier ());
1504 vlib_worker_threads->wait_before_barrier = 0;
1505}
1506
1507void
1508vlib_workers_sync (void)
1509{
1510 if (PREDICT_FALSE (!vlib_num_workers ()))
1511 return;
1512
1513 if (!(*vlib_worker_threads->wait_at_barrier) &&
1514 !clib_atomic_swap_rel_n (&vlib_worker_threads->wait_before_barrier, 1))
1515 {
1516 u32 thread_index = vlib_get_thread_index ();
1517 vlib_rpc_call_main_thread (vlib_worker_sync_rpc, (u8 *) &thread_index,
1518 sizeof (thread_index));
Florin Corase060b0a2024-02-01 21:13:10 -08001519 vlib_worker_flush_pending_rpc_requests (vlib_get_main ());
Florin Coras4b208302022-03-30 13:50:19 -07001520 }
1521
1522 /* Wait until main thread asks for barrier */
1523 while (!(*vlib_worker_threads->wait_at_barrier))
1524 ;
1525
1526 /* Stop before barrier and make sure all threads are either
1527 * at worker barrier or the barrier before it */
1528 clib_atomic_fetch_add (&vlib_worker_threads->workers_before_barrier, 1);
1529 while (vlib_num_workers () > (*vlib_worker_threads->workers_at_barrier +
1530 vlib_worker_threads->workers_before_barrier))
1531 ;
1532}
1533
1534void
1535vlib_workers_continue (void)
1536{
1537 if (PREDICT_FALSE (!vlib_num_workers ()))
1538 return;
1539
1540 clib_atomic_fetch_add (&vlib_worker_threads->done_work_before_barrier, 1);
1541
1542 /* Wait until all workers are done with work before barrier */
1543 while (vlib_worker_threads->done_work_before_barrier <
1544 vlib_worker_threads->workers_before_barrier)
1545 ;
1546
1547 clib_atomic_fetch_add (&vlib_worker_threads->done_work_before_barrier, -1);
1548 clib_atomic_fetch_add (&vlib_worker_threads->workers_before_barrier, -1);
1549}
1550
Neale Ranns42845dd2020-05-26 13:12:17 +00001551/**
1552 * Wait until each of the workers has been once around the track
1553 */
1554void
1555vlib_worker_wait_one_loop (void)
1556{
Damjan Marionfd8deb42021-03-06 12:26:28 +01001557 vlib_global_main_t *vgm = vlib_get_global_main ();
Neale Ranns42845dd2020-05-26 13:12:17 +00001558 ASSERT (vlib_get_thread_index () == 0);
1559
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001560 if (vlib_get_n_threads () < 2)
Neale Ranns42845dd2020-05-26 13:12:17 +00001561 return;
1562
1563 if (vlib_worker_thread_barrier_held ())
1564 return;
1565
1566 u32 *counts = 0;
1567 u32 ii;
1568
Damjan Marion6ffb7c62021-03-26 13:06:13 +01001569 vec_validate (counts, vlib_get_n_threads () - 1);
Neale Ranns42845dd2020-05-26 13:12:17 +00001570
1571 /* record the current loop counts */
Damjan Marionfd8deb42021-03-06 12:26:28 +01001572 vec_foreach_index (ii, vgm->vlib_mains)
1573 counts[ii] = vgm->vlib_mains[ii]->main_loop_count;
Neale Ranns42845dd2020-05-26 13:12:17 +00001574
1575 /* spin until each changes, apart from the main thread, or we'd be
1576 * a while */
1577 for (ii = 1; ii < vec_len (counts); ii++)
1578 {
Damjan Marionfd8deb42021-03-06 12:26:28 +01001579 while (counts[ii] == vgm->vlib_mains[ii]->main_loop_count)
Neale Ranns42845dd2020-05-26 13:12:17 +00001580 CLIB_PAUSE ();
1581 }
1582
1583 vec_free (counts);
1584 return;
1585}
1586
Dave Barach9b8ffd92016-07-08 08:13:45 -04001587void
Florin Coras4cadd3b2024-02-01 20:46:15 -08001588vlib_worker_flush_pending_rpc_requests (vlib_main_t *vm)
1589{
1590 vlib_main_t *vm_global = vlib_get_first_main ();
1591
1592 ASSERT (vm != vm_global);
1593
1594 clib_spinlock_lock_if_init (&vm_global->pending_rpc_lock);
1595 vec_append (vm_global->pending_rpc_requests, vm->pending_rpc_requests);
1596 vec_reset_length (vm->pending_rpc_requests);
1597 clib_spinlock_unlock_if_init (&vm_global->pending_rpc_lock);
1598}
1599
1600void
Dave Barach9b8ffd92016-07-08 08:13:45 -04001601vlib_worker_thread_fn (void *arg)
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001602{
Damjan Marionfd8deb42021-03-06 12:26:28 +01001603 vlib_global_main_t *vgm = vlib_get_global_main ();
Dave Barach9b8ffd92016-07-08 08:13:45 -04001604 vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg;
Dave Barach9b8ffd92016-07-08 08:13:45 -04001605 vlib_main_t *vm = vlib_get_main ();
Damjan Marione9f929b2017-03-16 11:32:09 +01001606 clib_error_t *e;
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001607
Damjan Marion586afd72017-04-05 19:18:20 +02001608 ASSERT (vm->thread_index == vlib_get_thread_index ());
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001609
1610 vlib_worker_thread_init (w);
1611 clib_time_init (&vm->clib_time);
1612 clib_mem_set_heap (w->thread_mheap);
1613
Damjan Marionfd8deb42021-03-06 12:26:28 +01001614 vm->worker_init_functions_called = hash_create (0, 0);
1615
1616 e = vlib_call_init_exit_functions_no_sort (
1617 vm, &vgm->worker_init_function_registrations, 1 /* call_once */,
1618 0 /* is_global */);
Damjan Marione9f929b2017-03-16 11:32:09 +01001619 if (e)
1620 clib_error_report (e);
1621
Damjan Marione9d52d52017-03-09 15:42:26 +01001622 vlib_worker_loop (vm);
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001623}
1624
1625VLIB_REGISTER_THREAD (worker_thread_reg, static) = {
1626 .name = "workers",
1627 .short_name = "wk",
1628 .function = vlib_worker_thread_fn,
1629};
1630
Mohammed Hawarie7149262022-05-18 10:08:47 +02001631extern clib_march_fn_registration
1632 *vlib_frame_queue_dequeue_with_aux_fn_march_fn_registrations;
1633extern clib_march_fn_registration
1634 *vlib_frame_queue_dequeue_fn_march_fn_registrations;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001635u32
1636vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts)
1637{
1638 vlib_thread_main_t *tm = vlib_get_thread_main ();
Mohammed Hawarie7149262022-05-18 10:08:47 +02001639 vlib_main_t *vm = vlib_get_main ();
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001640 vlib_frame_queue_main_t *fqm;
1641 vlib_frame_queue_t *fq;
Mohammed Hawarie7149262022-05-18 10:08:47 +02001642 vlib_node_t *node;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001643 int i;
Elias Rudberg368104d2020-04-16 16:01:52 +02001644 u32 num_threads;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001645
1646 if (frame_queue_nelts == 0)
dongjuan88752482019-06-04 10:59:02 +08001647 frame_queue_nelts = FRAME_QUEUE_MAX_NELTS;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001648
Elias Rudberg368104d2020-04-16 16:01:52 +02001649 num_threads = 1 /* main thread */ + tm->n_threads;
1650 ASSERT (frame_queue_nelts >= 8 + num_threads);
Damjan Marion78fd7e82018-07-20 18:47:05 +02001651
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001652 vec_add2 (tm->frame_queue_mains, fqm, 1);
1653
Mohammed Hawarie7149262022-05-18 10:08:47 +02001654 node = vlib_get_node (vm, fqm->node_index);
1655 ASSERT (node);
1656 if (node->aux_offset)
1657 {
1658 fqm->frame_queue_dequeue_fn =
1659 CLIB_MARCH_FN_VOID_POINTER (vlib_frame_queue_dequeue_with_aux_fn);
1660 }
1661 else
1662 {
1663 fqm->frame_queue_dequeue_fn =
1664 CLIB_MARCH_FN_VOID_POINTER (vlib_frame_queue_dequeue_fn);
1665 }
1666
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001667 fqm->node_index = node_index;
Damjan Marion78fd7e82018-07-20 18:47:05 +02001668 fqm->frame_queue_nelts = frame_queue_nelts;
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001669
1670 vec_validate (fqm->vlib_frame_queues, tm->n_vlib_mains - 1);
Damjan Marion8bea5892022-04-04 22:40:45 +02001671 vec_set_len (fqm->vlib_frame_queues, 0);
Damjan Marionaaef1eb2016-11-08 17:37:01 +01001672 for (i = 0; i < tm->n_vlib_mains; i++)
1673 {
1674 fq = vlib_frame_queue_alloc (frame_queue_nelts);
1675 vec_add1 (fqm->vlib_frame_queues, fq);
1676 }
1677
1678 return (fqm - tm->frame_queue_mains);
1679}
1680
Dave Barach69128d02017-09-26 10:54:34 -04001681void
1682vlib_process_signal_event_mt_helper (vlib_process_signal_event_mt_args_t *
1683 args)
1684{
1685 ASSERT (vlib_get_thread_index () == 0);
1686 vlib_process_signal_event (vlib_get_main (), args->node_index,
1687 args->type_opaque, args->data);
1688}
1689
1690void *rpc_call_main_thread_cb_fn;
1691
1692void
1693vlib_rpc_call_main_thread (void *callback, u8 * args, u32 arg_size)
1694{
1695 if (rpc_call_main_thread_cb_fn)
1696 {
1697 void (*fp) (void *, u8 *, u32) = rpc_call_main_thread_cb_fn;
1698 (*fp) (callback, args, arg_size);
1699 }
1700 else
1701 clib_warning ("BUG: rpc_call_main_thread_cb_fn NULL!");
1702}
1703
Dave Barach9b8ffd92016-07-08 08:13:45 -04001704clib_error_t *
1705threads_init (vlib_main_t * vm)
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001706{
Benoît Ganne8b153de2021-12-09 18:24:21 +01001707 const vlib_thread_main_t *tm = vlib_get_thread_main ();
1708
1709 if (tm->main_lcore == ~0 && tm->n_vlib_mains > 1)
1710 return clib_error_return (0, "Configuration error, a main core must "
1711 "be specified when using worker threads");
1712
Ed Warnickecb9cada2015-12-08 15:45:58 -07001713 return 0;
1714}
1715
Damjan Marion0f8ecf02016-06-27 08:30:30 +02001716VLIB_INIT_FUNCTION (threads_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001717
Dave Baracha4324a92019-02-19 17:05:30 -05001718static clib_error_t *
1719show_clock_command_fn (vlib_main_t * vm,
1720 unformat_input_t * input, vlib_cli_command_t * cmd)
1721{
Dave Barachc25048b2020-01-29 18:05:24 -05001722 int verbose = 0;
Dave Barach19718002020-03-11 10:31:36 -04001723 clib_timebase_t _tb, *tb = &_tb;
Dave Baracha4324a92019-02-19 17:05:30 -05001724
Dave Barachc25048b2020-01-29 18:05:24 -05001725 (void) unformat (input, "verbose %=", &verbose, 1);
Dave Baracha4324a92019-02-19 17:05:30 -05001726
Dave Barach19718002020-03-11 10:31:36 -04001727 clib_timebase_init (tb, 0 /* GMT */ , CLIB_TIMEBASE_DAYLIGHT_NONE,
1728 &vm->clib_time);
1729
1730 vlib_cli_output (vm, "%U, %U GMT", format_clib_time, &vm->clib_time,
1731 verbose, format_clib_timebase_time,
1732 clib_timebase_now (tb));
Dave Baracha4324a92019-02-19 17:05:30 -05001733
Dave Baracha4324a92019-02-19 17:05:30 -05001734 vlib_cli_output (vm, "Time last barrier release %.9f",
1735 vm->time_last_barrier_release);
1736
Benoît Ganne56eccdb2021-08-20 09:18:31 +02001737 foreach_vlib_main ()
Dave Baracha4324a92019-02-19 17:05:30 -05001738 {
Benoît Ganne56eccdb2021-08-20 09:18:31 +02001739 vlib_cli_output (vm, "%d: %U", this_vlib_main->thread_index,
1740 format_clib_time, &this_vlib_main->clib_time, verbose);
Dave Barachc25048b2020-01-29 18:05:24 -05001741
Benoît Ganne56eccdb2021-08-20 09:18:31 +02001742 vlib_cli_output (vm, "Thread %d offset %.9f error %.9f",
1743 this_vlib_main->thread_index,
1744 this_vlib_main->time_offset,
1745 vm->time_last_barrier_release -
1746 this_vlib_main->time_last_barrier_release);
Dave Baracha4324a92019-02-19 17:05:30 -05001747 }
1748 return 0;
1749}
1750
Dave Baracha4324a92019-02-19 17:05:30 -05001751VLIB_CLI_COMMAND (f_command, static) =
1752{
1753 .path = "show clock",
1754 .short_help = "show clock",
1755 .function = show_clock_command_fn,
1756};
Dave Baracha4324a92019-02-19 17:05:30 -05001757
Dave Barachab1a50c2020-10-06 14:08:16 -04001758vlib_thread_main_t *
1759vlib_get_thread_main_not_inline (void)
1760{
1761 return vlib_get_thread_main ();
1762}
1763
Dave Barach9b8ffd92016-07-08 08:13:45 -04001764/*
1765 * fd.io coding-style-patch-verification: ON
1766 *
1767 * Local Variables:
1768 * eval: (c-set-style "gnu")
1769 * End:
1770 */