X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlib%2Fthreads.c;h=1ce4dc15613bf1f1be05d58012a549203a3aee35;hb=2c8e0023f91882e53f06eb99c901b97fe013f981;hp=6a23bfd8a2fe85153a24387940bfc28b9c4f8e4c;hpb=f8d50682cd1245f6f5ce4c846ca6f1bdc11255a6;p=vpp.git diff --git a/src/vlib/threads.c b/src/vlib/threads.c index 6a23bfd8a2f..1ce4dc15613 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -23,9 +23,10 @@ #include #include +#include + DECLARE_CJ_GLOBAL_LOG; -#define FRAME_QUEUE_NELTS 64 u32 vl (void *p) @@ -43,28 +44,6 @@ vlib_thread_main_t vlib_thread_main; * imapacts observed timings. */ -u32 -elog_global_id_for_msg_name (const char *msg_name) -{ - uword *p, r; - static uword *h; - u8 *name_copy; - - if (!h) - h = hash_create_string (0, sizeof (uword)); - - p = hash_get_mem (h, msg_name); - if (p) - return p[0]; - r = elog_string (&vlib_global_main.elog_main, "%s", msg_name); - - name_copy = format (0, "%s%c", msg_name, 0); - - hash_set_mem (h, name_copy, r); - - return r; -} - static inline void barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed) { @@ -85,8 +64,8 @@ barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed) ed = ELOG_DATA (&vlib_global_main.elog_main, e); ed->count = (int) vlib_worker_threads[0].barrier_sync_count; - ed->caller = elog_global_id_for_msg_name - (vlib_worker_threads[0].barrier_caller); + ed->caller = elog_string (&vlib_global_main.elog_main, + (char *) vlib_worker_threads[0].barrier_caller); ed->t_entry = (int) (1000000.0 * t_entry); ed->t_open = (int) (1000000.0 * t_open); ed->t_closed = (int) (1000000.0 * t_closed); @@ -112,8 +91,8 @@ barrier_trace_sync_rec (f64 t_entry) ed = ELOG_DATA (&vlib_global_main.elog_main, e); ed->depth = (int) vlib_worker_threads[0].recursion_level - 1; - ed->caller = elog_global_id_for_msg_name - (vlib_worker_threads[0].barrier_caller); + ed->caller = elog_string (&vlib_global_main.elog_main, + (char *) vlib_worker_threads[0].barrier_caller); } static inline void @@ -276,6 +255,21 @@ 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); @@ -304,6 +298,8 @@ vlib_thread_init (vlib_main_t * vm) w->thread_id = pthread_self (); tm->n_vlib_mains = 1; + vlib_get_thread_core_numa (w, w->cpu_id); + if (tm->sched_policy != ~0) { struct sched_param sched_param; @@ -598,24 +594,23 @@ vlib_worker_thread_bootstrap_fn (void *arg) return rv; } -static void -vlib_get_thread_core_socket (vlib_worker_thread_t * w, unsigned cpu_id) +void +vlib_get_thread_core_numa (vlib_worker_thread_t * w, unsigned cpu_id) { const char *sys_cpu_path = "/sys/devices/system/cpu/cpu"; u8 *p = 0; - int core_id = -1, socket_id = -1; + int core_id = -1, numa_id = -1; p = format (p, "%s%u/topology/core_id%c", sys_cpu_path, cpu_id, 0); clib_sysfs_read ((char *) p, "%d", &core_id); vec_reset_length (p); - p = - format (p, "%s%u/topology/physical_package_id%c", sys_cpu_path, cpu_id, - 0); - clib_sysfs_read ((char *) p, "%d", &socket_id); + p = format (p, "%s%u/topology/physical_package_id%c", sys_cpu_path, + cpu_id, 0); + clib_sysfs_read ((char *) p, "%d", &numa_id); vec_free (p); w->core_id = core_id; - w->socket_id = socket_id; + w->numa_id = numa_id; } static clib_error_t * @@ -623,9 +618,28 @@ vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned cpu_id) { vlib_thread_main_t *tm = &vlib_thread_main; void *(*fp_arg) (void *) = fp; + void *numa_heap; w->cpu_id = cpu_id; - vlib_get_thread_core_socket (w, 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 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; + } + else + { + /* Or, use the main heap */ + clib_per_numa_mheaps[w->numa_id] = w->thread_mheap; + } + } + if (tm->cb.vlib_launch_thread_cb && !w->registration->use_pthreads) return tm->cb.vlib_launch_thread_cb (fp, (void *) w, cpu_id); else @@ -728,15 +742,8 @@ start_workers (vlib_main_t * vm) vec_add2 (vlib_worker_threads, w, 1); /* Currently unused, may not really work */ if (tr->mheap_size) - { -#if USE_DLMALLOC == 0 - w->thread_mheap = - mheap_alloc (0 /* use VM */ , tr->mheap_size); -#else - w->thread_mheap = create_mspace (tr->mheap_size, - 0 /* unlocked */ ); -#endif - } + w->thread_mheap = create_mspace (tr->mheap_size, + 0 /* unlocked */ ); else w->thread_mheap = main_heap; @@ -866,14 +873,20 @@ start_workers (vlib_main_t * vm) #ifdef VLIB_SUPPORTS_ARBITRARY_SCALAR_SIZES nm_clone->frame_size_hash = hash_create (0, sizeof (uword)); #endif + nm_clone->node_by_error = nm->node_by_error; /* 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); + /* 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); + 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); @@ -894,13 +907,8 @@ start_workers (vlib_main_t * vm) vec_add2 (vlib_worker_threads, w, 1); if (tr->mheap_size) { -#if USE_DLMALLOC == 0 - w->thread_mheap = - mheap_alloc (0 /* use VM */ , tr->mheap_size); -#else w->thread_mheap = create_mspace (tr->mheap_size, 0 /* locked */ ); -#endif } else w->thread_mheap = main_heap; @@ -1036,9 +1044,15 @@ vlib_worker_thread_node_refork (void) clib_memcpy_fast (&vm_clone->error_main, &vm->error_main, sizeof (vm->error_main)); j = vec_len (vm->error_main.counters) - 1; + + /* Switch to the stats segment ... */ + void *oldheap = vlib_stats_push_heap (0); vec_validate_aligned (old_counters, j, CLIB_CACHE_LINE_BYTES); - vec_validate_aligned (old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES); vm_clone->error_main.counters = old_counters; + vlib_stats_pop_heap2 (vm_clone->error_main.counters, vm_clone->thread_index, + oldheap, 0); + + vec_validate_aligned (old_counters_all_clear, j, CLIB_CACHE_LINE_BYTES); vm_clone->error_main.counters_last_clear = old_counters_all_clear; nm_clone = &vm_clone->node_main; @@ -1069,11 +1083,7 @@ vlib_worker_thread_node_refork (void) clib_mem_alloc_no_fail (vec_len (nm->nodes) * sizeof (*new_n_clone)); for (j = 0; j < vec_len (nm->nodes); j++) { - vlib_node_t *old_n_clone; - vlib_node_t *new_n; - - new_n = nm->nodes[j]; - old_n_clone = old_nodes_clone[j]; + vlib_node_t *new_n = nm->nodes[j]; clib_memcpy_fast (new_n_clone, new_n, sizeof (*new_n)); /* none of the copied nodes have enqueue rights given out */ @@ -1089,6 +1099,7 @@ vlib_worker_thread_node_refork (void) } else { + vlib_node_t *old_n_clone = old_nodes_clone[j]; /* Copy stats if the old data is valid */ clib_memcpy_fast (&new_n_clone->stats_total, &old_n_clone->stats_total, @@ -1192,6 +1203,7 @@ vlib_worker_thread_node_refork (void) nm_clone->processes = vec_dup_aligned (nm->processes, CLIB_CACHE_LINE_BYTES); + nm_clone->node_by_error = nm->node_by_error; } void @@ -1253,6 +1265,9 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) ; else if (unformat (input, "skip-cores %u", &tm->skip_cores)) ; + else if (unformat (input, "numa-heap-size %U", + unformat_memory_size, &tm->numa_heap_size)) + ; else if (unformat (input, "coremask-%s %U", &name, unformat_bitmap_mask, &bitmap) || unformat (input, "corelist-%s %U", &name, @@ -1376,6 +1391,31 @@ vlib_worker_thread_fork_fixup (vlib_fork_fixup_t which) #define BARRIER_MINIMUM_OPEN_FACTOR 3 #endif +void +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; + + /* No worker threads? */ + if (count == 0) + return; + + deadline = now + BARRIER_SYNC_TIMEOUT; + *vlib_worker_threads->wait_at_barrier = 1; + while (*vlib_worker_threads->workers_at_barrier != count) + { + if ((now = vlib_time_now (vm)) > deadline) + { + fformat (stderr, "%s: worker thread deadlock\n", __FUNCTION__); + os_panic (); + } + CLIB_PAUSE (); + } + *vlib_worker_threads->wait_at_barrier = 0; +} + void vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) { @@ -1415,7 +1455,7 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) for (i = 1; i < vec_len (vlib_mains); i++) max_vector_rate = clib_max (max_vector_rate, - vlib_last_vectors_per_main_loop_as_f64 (vlib_mains[i])); + (f64) vlib_last_vectors_per_main_loop (vlib_mains[i])); vlib_worker_threads[0].barrier_sync_count++; @@ -1466,18 +1506,6 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm, const char *func_name) } -void vlib_stat_segment_lock (void) __attribute__ ((weak)); -void -vlib_stat_segment_lock (void) -{ -} - -void vlib_stat_segment_unlock (void) __attribute__ ((weak)); -void -vlib_stat_segment_unlock (void) -{ -} - void vlib_worker_thread_barrier_release (vlib_main_t * vm) { @@ -1648,6 +1676,7 @@ vlib_frame_queue_dequeue (vlib_main_t * vm, vlib_frame_queue_main_t * fqm) while (1) { + vlib_buffer_t *b; if (fq->head == fq->tail) { fq->head_hint = fq->head; @@ -1670,6 +1699,11 @@ vlib_frame_queue_dequeue (vlib_main_t * vm, vlib_frame_queue_main_t * fqm) 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); n_left_to_node = elt->n_vectors; @@ -1731,15 +1765,15 @@ vlib_worker_thread_fn (void *arg) clib_time_init (&vm->clib_time); clib_mem_set_heap (w->thread_mheap); - /* Wait until the dpdk init sequence is complete */ - while (tm->extern_thread_mgmt && tm->worker_thread_release == 0) - vlib_worker_thread_barrier_check (); - - e = vlib_call_init_exit_functions + e = vlib_call_init_exit_functions_no_sort (vm, &vm->worker_init_function_registrations, 1 /* call_once */ ); if (e) clib_error_report (e); + /* Wait until the dpdk init sequence is complete */ + while (tm->extern_thread_mgmt && tm->worker_thread_release == 0) + vlib_worker_thread_barrier_check (); + vlib_worker_loop (vm); } @@ -1760,7 +1794,7 @@ vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts) int i; if (frame_queue_nelts == 0) - frame_queue_nelts = FRAME_QUEUE_NELTS; + frame_queue_nelts = FRAME_QUEUE_MAX_NELTS; ASSERT (frame_queue_nelts >= 8); @@ -1840,11 +1874,11 @@ show_clock_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { int i; - f64 now; + int verbose = 0; - now = vlib_time_now (vm); + (void) unformat (input, "verbose %=", &verbose, 1); - vlib_cli_output (vm, "Time now %.9f", now); + vlib_cli_output (vm, "%U", format_clib_time, &vm->clib_time, verbose); if (vec_len (vlib_mains) == 1) return 0; @@ -1856,6 +1890,10 @@ show_clock_command_fn (vlib_main_t * vm, { if (vlib_mains[i] == 0) continue; + + vlib_cli_output (vm, "%d: %U", i, format_clib_time, + &vlib_mains[i]->clib_time, verbose); + vlib_cli_output (vm, "Thread %d offset %.9f error %.9f", i, vlib_mains[i]->time_offset, vm->time_last_barrier_release -