X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlib%2Fthreads.c;h=499a626e4701be08ffcbff16f45824697262f290;hb=a606d9210;hp=3f090542118ff72970e2ffce1f19dea3a9f8e8f3;hpb=4fbb9daa90b53e0abaa060cf6db7762e708ce5b6;p=vpp.git diff --git a/src/vlib/threads.c b/src/vlib/threads.c index 3f090542118..499a626e470 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -17,17 +17,15 @@ #include #include #include +#include +#include #include #include #include -#include #include -DECLARE_CJ_GLOBAL_LOG; - - u32 vl (void *p) { @@ -50,13 +48,11 @@ barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed) if (!vlib_worker_threads->barrier_elog_enabled) return; - /* *INDENT-OFF* */ - ELOG_TYPE_DECLARE (e) = - { - .format = "bar-trace-%s-#%d", - .format_args = "T4i4", - }; - /* *INDENT-ON* */ + ELOG_TYPE_DECLARE (e) = { + .format = "bar-trace-%s-#%d", + .format_args = "T4i4", + }; + struct { u32 caller, count, t_entry, t_open, t_closed; @@ -77,13 +73,11 @@ barrier_trace_sync_rec (f64 t_entry) if (!vlib_worker_threads->barrier_elog_enabled) return; - /* *INDENT-OFF* */ - ELOG_TYPE_DECLARE (e) = - { - .format = "bar-syncrec-%s-#%d", - .format_args = "T4i4", - }; - /* *INDENT-ON* */ + ELOG_TYPE_DECLARE (e) = { + .format = "bar-syncrec-%s-#%d", + .format_args = "T4i4", + }; + struct { u32 caller, depth; @@ -101,13 +95,11 @@ barrier_trace_release_rec (f64 t_entry) if (!vlib_worker_threads->barrier_elog_enabled) return; - /* *INDENT-OFF* */ - ELOG_TYPE_DECLARE (e) = - { - .format = "bar-relrrec-#%d", - .format_args = "i4", - }; - /* *INDENT-ON* */ + ELOG_TYPE_DECLARE (e) = { + .format = "bar-relrrec-#%d", + .format_args = "i4", + }; + struct { u32 depth; @@ -123,13 +115,11 @@ barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main) if (!vlib_worker_threads->barrier_elog_enabled) return; - /* *INDENT-OFF* */ - ELOG_TYPE_DECLARE (e) = - { - .format = "bar-rel-#%d-e%d-u%d-t%d", - .format_args = "i4i4i4i4", - }; - /* *INDENT-ON* */ + ELOG_TYPE_DECLARE (e) = { + .format = "bar-rel-#%d-e%d-u%d-t%d", + .format_args = "i4i4i4i4", + }; + struct { u32 count, t_entry, t_update_main, t_closed_total; @@ -176,33 +166,6 @@ sort_registrations_by_no_clone (void *a0, void *a1) - ((i32) ((*tr1)->no_data_structure_clone))); } -static uword * -clib_sysfs_list_to_bitmap (char *filename) -{ - FILE *fp; - uword *r = 0; - - fp = fopen (filename, "r"); - - if (fp != NULL) - { - u8 *buffer = 0; - vec_validate (buffer, 256 - 1); - if (fgets ((char *) buffer, 256, fp)) - { - unformat_input_t in; - unformat_init_string (&in, (char *) buffer, - strlen ((char *) buffer)); - if (unformat (&in, "%U", unformat_bitmap_list, &r) != 1) - clib_warning ("unformat_bitmap_list failed"); - unformat_free (&in); - } - vec_free (buffer); - fclose (fp); - } - return r; -} - /* Called early in the init sequence */ @@ -255,21 +218,6 @@ vlib_thread_init (vlib_main_t * vm) } avail_cpu = clib_bitmap_set (avail_cpu, tm->main_lcore, 0); - /* - * Determine if the number of workers is greater than 0. - * If so, mark CPU 0 unavailable so workers will be numbered after main. - */ - u32 n_workers = 0; - uword *p = hash_get_mem (tm->thread_registrations_by_name, "workers"); - if (p != 0) - { - vlib_thread_registration_t *tr = (vlib_thread_registration_t *) p[0]; - int worker_thread_count = tr->count; - n_workers = worker_thread_count; - } - if (tm->skip_cores == 0 && n_workers) - avail_cpu = clib_bitmap_set (avail_cpu, 0, 0); - /* assume that there is socket 0 only if there is no data from sysfs */ if (!tm->cpu_socket_bitmap) tm->cpu_socket_bitmap = clib_bitmap_set (0, 0, 1); @@ -338,25 +286,37 @@ vlib_thread_init (vlib_main_t * vm) { uword c; /* *INDENT-OFF* */ - clib_bitmap_foreach (c, tr->coremask, ({ + clib_bitmap_foreach (c, tr->coremask) { if (clib_bitmap_get(avail_cpu, c) == 0) return clib_error_return (0, "cpu %u is not available to be used" " for the '%s' thread",c, tr->name); avail_cpu = clib_bitmap_set(avail_cpu, c, 0); - })); + } /* *INDENT-ON* */ } else { for (j = 0; j < tr->count; j++) { + /* Do not use CPU 0 by default - leave it to the host and IRQs */ + uword avail_c0 = clib_bitmap_get (avail_cpu, 0); + avail_cpu = clib_bitmap_set (avail_cpu, 0, 0); + uword c = clib_bitmap_first_set (avail_cpu); + /* Use CPU 0 as a last resort */ + if (c == ~0 && avail_c0) + { + c = 0; + avail_c0 = 0; + } + if (c == ~0) return clib_error_return (0, "no available cpus to be used for" " the '%s' thread", tr->name); + avail_cpu = clib_bitmap_set (avail_cpu, 0, avail_c0); avail_cpu = clib_bitmap_set (avail_cpu, c, 0); tr->coremask = clib_bitmap_set (tr->coremask, c, 1); } @@ -587,6 +547,8 @@ vlib_worker_thread_bootstrap_fn (void *arg) __os_thread_index = w - vlib_worker_threads; + vlib_process_start_switch_stack (vlib_get_main_by_index (__os_thread_index), + 0); rv = (void *) clib_calljmp ((uword (*)(uword)) w->thread_function, (uword) arg, w->thread_stack + VLIB_THREAD_STACK_SIZE); @@ -611,14 +573,14 @@ vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id) /* *INDENT-OFF* */ clib_sysfs_read ("/sys/devices/system/node/online", "%U", unformat_bitmap_list, &nbmp); - clib_bitmap_foreach (node, nbmp, ({ + clib_bitmap_foreach (node, nbmp) { p = format (p, "%s%u/cpulist%c", sys_node_path, node, 0); clib_sysfs_read ((char *) p, "%U", unformat_bitmap_list, &cbmp); if (clib_bitmap_get (cbmp, cpu_id)) numa_id = node; vec_reset_length (cbmp); vec_reset_length (p); - })); + } /* *INDENT-ON* */ vec_free (nbmp); vec_free (cbmp); @@ -631,6 +593,7 @@ vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id) static clib_error_t * vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id) { + clib_mem_main_t *mm = &clib_mem_main; vlib_thread_main_t *tm = &vlib_thread_main; void *(*fp_arg) (void *) = fp; void *numa_heap; @@ -639,19 +602,22 @@ vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id) vlib_get_thread_core_numa (w, cpu_id); /* Set up NUMA-bound heap if indicated */ - if (clib_per_numa_mheaps[w->numa_id] == 0) + if (mm->per_numa_mheaps[w->numa_id] == 0) { /* If the user requested a NUMA heap, create it... */ if (tm->numa_heap_size) { - numa_heap = clib_mem_init_thread_safe_numa - (0 /* DIY */ , tm->numa_heap_size, w->numa_id); - clib_per_numa_mheaps[w->numa_id] = numa_heap; + clib_mem_set_numa_affinity (w->numa_id, 1 /* force */ ); + numa_heap = clib_mem_create_heap (0 /* DIY */ , tm->numa_heap_size, + 1 /* is_locked */ , + "numa %u heap", w->numa_id); + clib_mem_set_default_numa_affinity (); + mm->per_numa_mheaps[w->numa_id] = numa_heap; } else { /* Or, use the main heap */ - clib_per_numa_mheaps[w->numa_id] = w->thread_mheap; + mm->per_numa_mheaps[w->numa_id] = w->thread_mheap; } } @@ -677,6 +643,7 @@ vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id) static clib_error_t * start_workers (vlib_main_t * vm) { + vlib_global_main_t *vgm = vlib_get_global_main (); int i, j; vlib_worker_thread_t *w; vlib_main_t *vm_clone; @@ -686,14 +653,15 @@ start_workers (vlib_main_t * vm) vlib_node_runtime_t *rt; u32 n_vlib_mains = tm->n_vlib_mains; u32 worker_thread_index; - u8 *main_heap = clib_mem_get_per_cpu_heap (); + clib_mem_heap_t *main_heap = clib_mem_get_per_cpu_heap (); + vlib_stats_register_mem_heap (main_heap); vec_reset_length (vlib_worker_threads); /* Set up the main thread */ vec_add2_aligned (vlib_worker_threads, w, 1, CLIB_CACHE_LINE_BYTES); w->elog_track.name = "main thread"; - elog_track_register (&vm->elog_main, &w->elog_track); + elog_track_register (vlib_get_elog_main (), &w->elog_track); if (vec_len (tm->thread_prefix)) { @@ -701,20 +669,20 @@ start_workers (vlib_main_t * vm) vlib_set_thread_name ((char *) w->name); } - vm->elog_main.lock = + vgm->elog_main.lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, CLIB_CACHE_LINE_BYTES); - vm->elog_main.lock[0] = 0; + vgm->elog_main.lock[0] = 0; - if (n_vlib_mains > 1) - { - /* Replace hand-crafted length-1 vector with a real vector */ - vlib_mains = 0; + clib_callback_data_init (&vm->vlib_node_runtime_perf_callbacks, + &vm->worker_thread_main_loop_callback_lock); - vec_validate_aligned (vlib_mains, tm->n_vlib_mains - 1, - CLIB_CACHE_LINE_BYTES); - _vec_len (vlib_mains) = 0; - vec_add1_aligned (vlib_mains, vm, CLIB_CACHE_LINE_BYTES); + vec_validate_aligned (vgm->vlib_mains, n_vlib_mains - 1, + CLIB_CACHE_LINE_BYTES); + _vec_len (vgm->vlib_mains) = 0; + vec_add1_aligned (vgm->vlib_mains, vm, CLIB_CACHE_LINE_BYTES); + if (n_vlib_mains > 1) + { vlib_worker_threads->wait_at_barrier = clib_mem_alloc_aligned (sizeof (u32), CLIB_CACHE_LINE_BYTES); vlib_worker_threads->workers_at_barrier = @@ -732,13 +700,14 @@ start_workers (vlib_main_t * vm) /* Without update or refork */ *vlib_worker_threads->node_reforks_required = 0; - vm->need_vlib_worker_thread_node_runtime_update = 0; + vgm->need_vlib_worker_thread_node_runtime_update = 0; /* init timing */ vm->barrier_epoch = 0; vm->barrier_no_close_before = 0; worker_thread_index = 1; + clib_spinlock_init (&vm->worker_thread_main_loop_callback_lock); for (i = 0; i < vec_len (tm->registrations); i++) { @@ -757,8 +726,10 @@ start_workers (vlib_main_t * vm) vec_add2 (vlib_worker_threads, w, 1); /* Currently unused, may not really work */ if (tr->mheap_size) - w->thread_mheap = create_mspace (tr->mheap_size, - 0 /* unlocked */ ); + w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size, + /* unlocked */ 0, + "%s%d heap", + tr->name, k); else w->thread_mheap = main_heap; @@ -772,7 +743,7 @@ start_workers (vlib_main_t * vm) w->elog_track.name = (char *) format (0, "%s %d", tr->name, k + 1); vec_add1 (w->elog_track.name, 0); - elog_track_register (&vm->elog_main, &w->elog_track); + elog_track_register (vlib_get_elog_main (), &w->elog_track); if (tr->no_data_structure_clone) continue; @@ -782,21 +753,25 @@ start_workers (vlib_main_t * vm) vm_clone = clib_mem_alloc_aligned (sizeof (*vm_clone), CLIB_CACHE_LINE_BYTES); - clib_memcpy (vm_clone, vlib_mains[0], sizeof (*vm_clone)); + clib_memcpy (vm_clone, vlib_get_first_main (), + sizeof (*vm_clone)); vm_clone->thread_index = worker_thread_index; vm_clone->heap_base = w->thread_mheap; vm_clone->heap_aligned_base = (void *) (((uword) w->thread_mheap) & ~(VLIB_FRAME_ALIGN - 1)); - vm_clone->init_functions_called = - hash_create (0, /* value bytes */ 0); vm_clone->pending_rpc_requests = 0; vec_validate (vm_clone->pending_rpc_requests, 0); _vec_len (vm_clone->pending_rpc_requests) = 0; clib_memset (&vm_clone->random_buffer, 0, sizeof (vm_clone->random_buffer)); + clib_spinlock_init + (&vm_clone->worker_thread_main_loop_callback_lock); + clib_callback_data_init + (&vm_clone->vlib_node_runtime_perf_callbacks, + &vm_clone->worker_thread_main_loop_callback_lock); - nm = &vlib_mains[0]->node_main; + nm = &vlib_get_first_main ()->node_main; nm_clone = &vm_clone->node_main; /* fork next frames array, preserving node runtime indices */ nm_clone->next_frames = vec_dup_aligned (nm->next_frames, @@ -854,6 +829,9 @@ start_workers (vlib_main_t * vm) nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] = vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT], CLIB_CACHE_LINE_BYTES); + clib_interrupt_init ( + &nm_clone->interrupts, + vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])); vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) { vlib_node_t *n = vlib_get_node (vm, rt->node_index); @@ -893,18 +871,20 @@ start_workers (vlib_main_t * vm) /* Packet trace buffers are guaranteed to be empty, nothing to do here */ clib_mem_set_heap (oldheap); - vec_add1_aligned (vlib_mains, vm_clone, CLIB_CACHE_LINE_BYTES); + vec_add1_aligned (vgm->vlib_mains, vm_clone, + CLIB_CACHE_LINE_BYTES); /* Switch to the stats segment ... */ void *oldheap = vlib_stats_push_heap (0); - vm_clone->error_main.counters = vec_dup_aligned - (vlib_mains[0]->error_main.counters, CLIB_CACHE_LINE_BYTES); + vm_clone->error_main.counters = + vec_dup_aligned (vlib_get_first_main ()->error_main.counters, + CLIB_CACHE_LINE_BYTES); vlib_stats_pop_heap2 (vm_clone->error_main.counters, worker_thread_index, oldheap, 1); - vm_clone->error_main.counters_last_clear = vec_dup_aligned - (vlib_mains[0]->error_main.counters_last_clear, - CLIB_CACHE_LINE_BYTES); + vm_clone->error_main.counters_last_clear = vec_dup_aligned ( + vlib_get_first_main ()->error_main.counters_last_clear, + CLIB_CACHE_LINE_BYTES); worker_thread_index++; } @@ -922,8 +902,10 @@ start_workers (vlib_main_t * vm) vec_add2 (vlib_worker_threads, w, 1); if (tr->mheap_size) { - w->thread_mheap = - create_mspace (tr->mheap_size, 0 /* locked */ ); + w->thread_mheap = clib_mem_create_heap (0, tr->mheap_size, + /* locked */ 0, + "%s%d heap", + tr->name, j); } else w->thread_mheap = main_heap; @@ -936,7 +918,7 @@ start_workers (vlib_main_t * vm) (char *) format (0, "%s %d", tr->name, j + 1); w->registration = tr; vec_add1 (w->elog_track.name, 0); - elog_track_register (&vm->elog_main, &w->elog_track); + elog_track_register (vlib_get_elog_main (), &w->elog_track); } } } @@ -965,13 +947,13 @@ start_workers (vlib_main_t * vm) { uword c; /* *INDENT-OFF* */ - clib_bitmap_foreach (c, tr->coremask, ({ + clib_bitmap_foreach (c, tr->coremask) { w = vlib_worker_threads + worker_thread_index++; err = vlib_launch_thread_int (vlib_worker_thread_bootstrap_fn, w, c); if (err) clib_error_report (err); - })); + } /* *INDENT-ON* */ } } @@ -991,15 +973,10 @@ worker_thread_node_runtime_update_internal (void) vlib_node_main_t *nm, *nm_clone; vlib_main_t *vm_clone; vlib_node_runtime_t *rt; - never_inline void - vlib_node_runtime_sync_stats (vlib_main_t * vm, - vlib_node_runtime_t * r, - uword n_calls, - uword n_vectors, uword n_clocks); ASSERT (vlib_get_thread_index () == 0); - vm = vlib_mains[0]; + vm = vlib_get_first_main (); nm = &vm->node_main; ASSERT (*vlib_worker_threads->wait_at_barrier == 1); @@ -1015,11 +992,11 @@ worker_thread_node_runtime_update_internal (void) vlib_node_sync_stats (vm, n); } - for (i = 1; i < vec_len (vlib_mains); i++) + for (i = 1; i < vlib_get_n_threads (); i++) { vlib_node_t *n; - vm_clone = vlib_mains[i]; + vm_clone = vlib_get_main_by_index (i); nm_clone = &vm_clone->node_main; for (j = 0; j < vec_len (nm_clone->nodes); j++) @@ -1047,7 +1024,7 @@ vlib_worker_thread_node_refork (void) int j; - vm = vlib_mains[0]; + vm = vlib_get_first_main (); nm = &vm->node_main; vm_clone = vlib_get_main (); nm_clone = &vm_clone->node_main; @@ -1125,6 +1102,7 @@ vlib_worker_thread_node_refork (void) /* keep previous node state */ new_n_clone->state = old_n_clone->state; + new_n_clone->flags = old_n_clone->flags; } vec_add1 (nm_clone->nodes, new_n_clone); new_n_clone++; @@ -1156,6 +1134,7 @@ vlib_worker_thread_node_refork (void) { rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index); rt->state = old_rt[j].state; + rt->flags = old_rt[j].flags; clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data, VLIB_NODE_RUNTIME_DATA_SIZE); } @@ -1167,6 +1146,9 @@ vlib_worker_thread_node_refork (void) nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT] = vec_dup_aligned (nm->nodes_by_type[VLIB_NODE_TYPE_INPUT], CLIB_CACHE_LINE_BYTES); + clib_interrupt_resize ( + &nm_clone->interrupts, + vec_len (nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT])); vec_foreach (rt, nm_clone->nodes_by_type[VLIB_NODE_TYPE_INPUT]) { @@ -1183,6 +1165,7 @@ vlib_worker_thread_node_refork (void) { rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index); rt->state = old_rt[j].state; + rt->flags = old_rt[j].flags; clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data, VLIB_NODE_RUNTIME_DATA_SIZE); } @@ -1210,6 +1193,7 @@ vlib_worker_thread_node_refork (void) { rt = vlib_node_get_runtime (vm_clone, old_rt[j].node_index); rt->state = old_rt[j].state; + rt->flags = old_rt[j].flags; clib_memcpy_fast (rt->runtime_data, old_rt[j].runtime_data, VLIB_NODE_RUNTIME_DATA_SIZE); } @@ -1298,6 +1282,10 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) return clib_error_return (0, "corelist cannot be set for '%s' threads", name); + if (tr->count) + return clib_error_return + (0, "core placement of '%s' threads is already configured", + name); tr->coremask = bitmap; tr->count = clib_bitmap_count_set_bits (tr->coremask); @@ -1316,9 +1304,14 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) return clib_error_return (0, "no such thread type 3 '%s'", name); tr = (vlib_thread_registration_t *) p[0]; + if (tr->fixed_count) return clib_error_return - (0, "number of %s threads not configurable", tr->name); + (0, "number of '%s' threads not configurable", name); + if (tr->count) + return clib_error_return + (0, "number of '%s' threads is already configured", name); + tr->count = count; } else @@ -1362,35 +1355,6 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) VLIB_EARLY_CONFIG_FUNCTION (cpu_config, "cpu"); -void vnet_main_fixup (vlib_fork_fixup_t which) __attribute__ ((weak)); -void -vnet_main_fixup (vlib_fork_fixup_t which) -{ -} - -void -vlib_worker_thread_fork_fixup (vlib_fork_fixup_t which) -{ - vlib_main_t *vm = vlib_get_main (); - - if (vlib_mains == 0) - return; - - ASSERT (vlib_get_thread_index () == 0); - vlib_worker_thread_barrier_sync (vm); - - switch (which) - { - case VLIB_WORKER_THREAD_FORK_FIXUP_NEW_SW_IF_INDEX: - vnet_main_fixup (VLIB_WORKER_THREAD_FORK_FIXUP_NEW_SW_IF_INDEX); - break; - - default: - ASSERT (0); - } - vlib_worker_thread_barrier_release (vm); -} - /* * Enforce minimum open time to minimize packet loss due to Rx overflow, * based on a test based heuristic that barrier should be open for at least @@ -1411,7 +1375,7 @@ vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm) { f64 deadline; f64 now = vlib_time_now (vm); - u32 count = vec_len (vlib_mains) - 1; + u32 count = vlib_get_n_threads () - 1; /* No worker threads? */ if (count == 0) @@ -1431,6 +1395,18 @@ vlib_worker_thread_initial_barrier_sync_and_release (vlib_main_t * vm) *vlib_worker_threads->wait_at_barrier = 0; } +/** + * Return true if the wroker thread barrier is held + */ +u8 +vlib_worker_thread_barrier_held (void) +{ + if (vlib_get_n_threads () < 2) + return (1); + + return (*vlib_worker_threads->wait_at_barrier == 1); +} + void vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) { @@ -1443,13 +1419,13 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) u32 count; int i; - if (vec_len (vlib_mains) < 2) + if (vlib_get_n_threads () < 2) return; ASSERT (vlib_get_thread_index () == 0); vlib_worker_threads[0].barrier_caller = func_name; - count = vec_len (vlib_mains) - 1; + count = vlib_get_n_threads () - 1; /* Record entry relative to last close */ now = vlib_time_now (vm); @@ -1462,15 +1438,21 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) return; } + if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0)) + clib_call_callbacks (vm->barrier_perf_callbacks, vm, + vm->clib_time.last_cpu_time, 0 /* enter */ ); + /* * Need data to decide if we're working hard enough to honor * the barrier hold-down timer. */ max_vector_rate = 0.0; - for (i = 1; i < vec_len (vlib_mains); i++) - max_vector_rate = - clib_max (max_vector_rate, - (f64) vlib_last_vectors_per_main_loop (vlib_mains[i])); + for (i = 1; i < vlib_get_n_threads (); i++) + { + vlib_main_t *ovm = vlib_get_main_by_index (i); + max_vector_rate = clib_max (max_vector_rate, + (f64) vlib_last_vectors_per_main_loop (ovm)); + } vlib_worker_threads[0].barrier_sync_count++; @@ -1524,6 +1506,7 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) void vlib_worker_thread_barrier_release (vlib_main_t * vm) { + vlib_global_main_t *vgm = vlib_get_global_main (); f64 deadline; f64 now; f64 minimum_open; @@ -1532,7 +1515,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) f64 t_update_main = 0.0; int refork_needed = 0; - if (vec_len (vlib_mains) < 2) + if (vlib_get_n_threads () < 2) return; ASSERT (vlib_get_thread_index () == 0); @@ -1548,7 +1531,7 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) } /* Update (all) node runtimes before releasing the barrier, if needed */ - if (vm->need_vlib_worker_thread_node_runtime_update) + if (vgm->need_vlib_worker_thread_node_runtime_update) { /* * Lock stat segment here, so we's safe when @@ -1559,12 +1542,12 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) /* Do stats elements on main thread */ worker_thread_node_runtime_update_internal (); - vm->need_vlib_worker_thread_node_runtime_update = 0; + vgm->need_vlib_worker_thread_node_runtime_update = 0; /* Do per thread rebuilds in parallel */ refork_needed = 1; clib_atomic_fetch_add (vlib_worker_threads->node_reforks_required, - (vec_len (vlib_mains) - 1)); + (vlib_get_n_threads () - 1)); now = vlib_time_now (vm); t_update_main = now - vm->barrier_epoch; } @@ -1625,163 +1608,69 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) barrier_trace_release (t_entry, t_closed_total, t_update_main); + if (PREDICT_FALSE (vec_len (vm->barrier_perf_callbacks) != 0)) + clib_call_callbacks (vm->barrier_perf_callbacks, vm, + vm->clib_time.last_cpu_time, 1 /* leave */ ); } -/* - * Check the frame queue to see if any frames are available. - * If so, pull the packets off the frames and put them to - * the handoff node. +/** + * Wait until each of the workers has been once around the track */ -int -vlib_frame_queue_dequeue (vlib_main_t * vm, vlib_frame_queue_main_t * fqm) +void +vlib_worker_wait_one_loop (void) { - u32 thread_id = vm->thread_index; - vlib_frame_queue_t *fq = fqm->vlib_frame_queues[thread_id]; - vlib_frame_queue_elt_t *elt; - u32 *from, *to; - vlib_frame_t *f; - int msg_type; - int processed = 0; - u32 n_left_to_node; - u32 vectors = 0; - - ASSERT (fq); - ASSERT (vm == vlib_mains[thread_id]); - - if (PREDICT_FALSE (fqm->node_index == ~0)) - return 0; - /* - * Gather trace data for frame queues - */ - if (PREDICT_FALSE (fq->trace)) - { - frame_queue_trace_t *fqt; - frame_queue_nelt_counter_t *fqh; - u32 elix; - - fqt = &fqm->frame_queue_traces[thread_id]; - - fqt->nelts = fq->nelts; - fqt->head = fq->head; - fqt->head_hint = fq->head_hint; - fqt->tail = fq->tail; - fqt->threshold = fq->vector_threshold; - fqt->n_in_use = fqt->tail - fqt->head; - if (fqt->n_in_use >= fqt->nelts) - { - // if beyond max then use max - fqt->n_in_use = fqt->nelts - 1; - } - - /* Record the number of elements in use in the histogram */ - fqh = &fqm->frame_queue_histogram[thread_id]; - fqh->count[fqt->n_in_use]++; - - /* Record a snapshot of the elements in use */ - for (elix = 0; elix < fqt->nelts; elix++) - { - elt = fq->elts + ((fq->head + 1 + elix) & (fq->nelts - 1)); - if (1 || elt->valid) - { - fqt->n_vectors[elix] = elt->n_vectors; - } - } - fqt->written = 1; - } - - while (1) - { - vlib_buffer_t *b; - if (fq->head == fq->tail) - { - fq->head_hint = fq->head; - return processed; - } - - elt = fq->elts + ((fq->head + 1) & (fq->nelts - 1)); - - if (!elt->valid) - { - fq->head_hint = fq->head; - return processed; - } - - from = elt->buffer_index; - msg_type = elt->msg_type; - - ASSERT (msg_type == VLIB_FRAME_QUEUE_ELT_DISPATCH_FRAME); - ASSERT (elt->n_vectors <= VLIB_FRAME_SIZE); - - f = vlib_get_frame_to_node (vm, fqm->node_index); - - /* If the first vector is traced, set the frame trace flag */ - b = vlib_get_buffer (vm, from[0]); - if (b->flags & VLIB_BUFFER_IS_TRACED) - f->frame_flags |= VLIB_NODE_FLAG_TRACE; - - to = vlib_frame_vector_args (f); + vlib_global_main_t *vgm = vlib_get_global_main (); + ASSERT (vlib_get_thread_index () == 0); - n_left_to_node = elt->n_vectors; + if (vlib_get_n_threads () < 2) + return; - while (n_left_to_node >= 4) - { - to[0] = from[0]; - to[1] = from[1]; - to[2] = from[2]; - to[3] = from[3]; - to += 4; - from += 4; - n_left_to_node -= 4; - } + if (vlib_worker_thread_barrier_held ()) + return; - while (n_left_to_node > 0) - { - to[0] = from[0]; - to++; - from++; - n_left_to_node--; - } + u32 *counts = 0; + u32 ii; - vectors += elt->n_vectors; - f->n_vectors = elt->n_vectors; - vlib_put_frame_to_node (vm, fqm->node_index, f); + vec_validate (counts, vlib_get_n_threads () - 1); - elt->valid = 0; - elt->n_vectors = 0; - elt->msg_type = 0xfefefefe; - CLIB_MEMORY_BARRIER (); - fq->head++; - processed++; + /* record the current loop counts */ + vec_foreach_index (ii, vgm->vlib_mains) + counts[ii] = vgm->vlib_mains[ii]->main_loop_count; - /* - * Limit the number of packets pushed into the graph - */ - if (vectors >= fq->vector_threshold) - { - fq->head_hint = fq->head; - return processed; - } + /* spin until each changes, apart from the main thread, or we'd be + * a while */ + for (ii = 1; ii < vec_len (counts); ii++) + { + while (counts[ii] == vgm->vlib_mains[ii]->main_loop_count) + CLIB_PAUSE (); } - ASSERT (0); - return processed; + + vec_free (counts); + return; } void vlib_worker_thread_fn (void *arg) { + vlib_global_main_t *vgm = vlib_get_global_main (); vlib_worker_thread_t *w = (vlib_worker_thread_t *) arg; vlib_thread_main_t *tm = vlib_get_thread_main (); vlib_main_t *vm = vlib_get_main (); clib_error_t *e; + vlib_process_finish_switch_stack (vm); + ASSERT (vm->thread_index == vlib_get_thread_index ()); vlib_worker_thread_init (w); clib_time_init (&vm->clib_time); clib_mem_set_heap (w->thread_mheap); - e = vlib_call_init_exit_functions_no_sort - (vm, &vm->worker_init_function_registrations, 1 /* call_once */ ); + vm->worker_init_functions_called = hash_create (0, 0); + + e = vlib_call_init_exit_functions_no_sort ( + vm, &vgm->worker_init_function_registrations, 1 /* call_once */, + 0 /* is_global */); if (e) clib_error_report (e); @@ -1807,17 +1696,19 @@ vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts) vlib_frame_queue_main_t *fqm; vlib_frame_queue_t *fq; int i; + u32 num_threads; if (frame_queue_nelts == 0) frame_queue_nelts = FRAME_QUEUE_MAX_NELTS; - ASSERT (frame_queue_nelts >= 8); + num_threads = 1 /* main thread */ + tm->n_threads; + ASSERT (frame_queue_nelts >= 8 + num_threads); vec_add2 (tm->frame_queue_mains, fqm, 1); fqm->node_index = node_index; fqm->frame_queue_nelts = frame_queue_nelts; - fqm->queue_hi_thresh = frame_queue_nelts - 2; + fqm->queue_hi_thresh = frame_queue_nelts - num_threads; vec_validate (fqm->vlib_frame_queues, tm->n_vlib_mains - 1); vec_validate (fqm->per_thread_data, tm->n_vlib_mains - 1); @@ -1890,29 +1781,35 @@ show_clock_command_fn (vlib_main_t * vm, { int i; int verbose = 0; + clib_timebase_t _tb, *tb = &_tb; (void) unformat (input, "verbose %=", &verbose, 1); - vlib_cli_output (vm, "%U", format_clib_time, &vm->clib_time, verbose); + clib_timebase_init (tb, 0 /* GMT */ , CLIB_TIMEBASE_DAYLIGHT_NONE, + &vm->clib_time); - if (vec_len (vlib_mains) == 1) + vlib_cli_output (vm, "%U, %U GMT", format_clib_time, &vm->clib_time, + verbose, format_clib_timebase_time, + clib_timebase_now (tb)); + + if (vlib_get_n_threads () == 1) return 0; vlib_cli_output (vm, "Time last barrier release %.9f", vm->time_last_barrier_release); - for (i = 1; i < vec_len (vlib_mains); i++) + for (i = 1; i < vlib_get_n_threads (); i++) { - if (vlib_mains[i] == 0) + vlib_main_t *ovm = vlib_get_main_by_index (i); + if (ovm == 0) continue; - vlib_cli_output (vm, "%d: %U", i, format_clib_time, - &vlib_mains[i]->clib_time, verbose); + vlib_cli_output (vm, "%d: %U", i, format_clib_time, &ovm->clib_time, + verbose); - vlib_cli_output (vm, "Thread %d offset %.9f error %.9f", i, - vlib_mains[i]->time_offset, - vm->time_last_barrier_release - - vlib_mains[i]->time_last_barrier_release); + vlib_cli_output ( + vm, "Thread %d offset %.9f error %.9f", i, ovm->time_offset, + vm->time_last_barrier_release - ovm->time_last_barrier_release); } return 0; } @@ -1926,6 +1823,12 @@ VLIB_CLI_COMMAND (f_command, static) = }; /* *INDENT-ON* */ +vlib_thread_main_t * +vlib_get_thread_main_not_inline (void) +{ + return vlib_get_thread_main (); +} + /* * fd.io coding-style-patch-verification: ON *