X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvlib%2Fthreads.c;h=c99458ddaec3865c4d4fb186041ce71b762c4a4c;hb=332287ef5da930dc71f01d927582da7ba7ff7b7b;hp=c53c5d6c170ea1fa9cd31259859f61eaa7e2ec80;hpb=6a5adc369591fcac2447e9809deaa22f56b53911;p=vpp.git diff --git a/src/vlib/threads.c b/src/vlib/threads.c index c53c5d6c170..c99458ddaec 100644 --- a/src/vlib/threads.c +++ b/src/vlib/threads.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,7 @@ DECLARE_CJ_GLOBAL_LOG; -#define FRAME_QUEUE_NELTS 32 +#define FRAME_QUEUE_NELTS 64 u32 vl (void *p) @@ -42,13 +43,8 @@ vlib_thread_main_t vlib_thread_main; * imapacts observed timings. */ -#ifdef BARRIER_TRACING - /* - * Output of barrier tracing can be to syslog or elog as suits - */ -#ifdef BARRIER_TRACING_ELOG -static u32 -elog_id_for_msg_name (const char *msg_name) +u32 +elog_global_id_for_msg_name (const char *msg_name) { uword *p, r; static uword *h; @@ -69,29 +65,28 @@ elog_id_for_msg_name (const char *msg_name) return r; } - /* - * elog Barrier trace functions, which are nulled out if BARRIER_TRACING isn't - * defined - */ - static inline void 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 = "barrier <%d#%s(O:%dus:%dus)(%dus)", - .format_args = "i4T4i4i4i4", + .format = "bar-trace-%s-#%d", + .format_args = "T4i4", }; /* *INDENT-ON* */ struct { - u32 count, caller, t_entry, t_open, t_closed; + u32 caller, count, t_entry, t_open, t_closed; } *ed = 0; ed = ELOG_DATA (&vlib_global_main.elog_main, e); ed->count = (int) vlib_worker_threads[0].barrier_sync_count; - ed->caller = elog_id_for_msg_name (vlib_worker_threads[0].barrier_caller); + ed->caller = elog_global_id_for_msg_name + (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); @@ -100,57 +95,65 @@ barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed) static inline void barrier_trace_sync_rec (f64 t_entry) { + if (!vlib_worker_threads->barrier_elog_enabled) + return; + /* *INDENT-OFF* */ ELOG_TYPE_DECLARE (e) = { - .format = "barrier <%d(%dus)%s", - .format_args = "i4i4T4", + .format = "bar-syncrec-%s-#%d", + .format_args = "T4i4", }; /* *INDENT-ON* */ struct { - u32 depth, t_entry, caller; + u32 caller, depth; } *ed = 0; ed = ELOG_DATA (&vlib_global_main.elog_main, e); ed->depth = (int) vlib_worker_threads[0].recursion_level - 1; - ed->t_entry = (int) (1000000.0 * t_entry); - ed->caller = elog_id_for_msg_name (vlib_worker_threads[0].barrier_caller); + ed->caller = elog_global_id_for_msg_name + (vlib_worker_threads[0].barrier_caller); } static inline void barrier_trace_release_rec (f64 t_entry) { + if (!vlib_worker_threads->barrier_elog_enabled) + return; + /* *INDENT-OFF* */ ELOG_TYPE_DECLARE (e) = { - .format = "barrier (%dus)%d>", - .format_args = "i4i4", + .format = "bar-relrrec-#%d", + .format_args = "i4", }; /* *INDENT-ON* */ struct { - u32 t_entry, depth; + u32 depth; } *ed = 0; ed = ELOG_DATA (&vlib_global_main.elog_main, e); - ed->t_entry = (int) (1000000.0 * t_entry); ed->depth = (int) vlib_worker_threads[0].recursion_level; } static inline void 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 = "barrier (%dus){%d}(C:%dus)#%d>", + .format = "bar-rel-#%d-e%d-u%d-t%d", .format_args = "i4i4i4i4", }; /* *INDENT-ON* */ struct { - u32 t_entry, t_update_main, t_closed_total, count; + u32 count, t_entry, t_update_main, t_closed_total; } *ed = 0; ed = ELOG_DATA (&vlib_global_main.elog_main, e); @@ -162,94 +165,6 @@ barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main) /* Reset context for next trace */ vlib_worker_threads[0].barrier_context = NULL; } -#else -char barrier_trace[65536]; -char *btp = barrier_trace; - - /* - * syslog Barrier trace functions, which are nulled out if BARRIER_TRACING - * isn't defined - */ - - -static inline void -barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed) -{ - btp += sprintf (btp, "<%u#%s", - (unsigned int) vlib_worker_threads[0].barrier_sync_count, - vlib_worker_threads[0].barrier_caller); - - if (vlib_worker_threads[0].barrier_context) - { - btp += sprintf (btp, "[%s]", vlib_worker_threads[0].barrier_context); - - } - - btp += sprintf (btp, "(O:%dus:%dus)(%dus):", - (int) (1000000.0 * t_entry), - (int) (1000000.0 * t_open), (int) (1000000.0 * t_closed)); - -} - -static inline void -barrier_trace_sync_rec (f64 t_entry) -{ - btp += sprintf (btp, "<%u(%dus)%s:", - (int) vlib_worker_threads[0].recursion_level - 1, - (int) (1000000.0 * t_entry), - vlib_worker_threads[0].barrier_caller); -} - -static inline void -barrier_trace_release_rec (f64 t_entry) -{ - btp += sprintf (btp, ":(%dus)%u>", (int) (1000000.0 * t_entry), - (int) vlib_worker_threads[0].recursion_level); -} - -static inline void -barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main) -{ - - btp += sprintf (btp, ":(%dus)", (int) (1000000.0 * t_entry)); - if (t_update_main > 0) - { - btp += sprintf (btp, "{%dus}", (int) (1000000.0 * t_update_main)); - } - - btp += sprintf (btp, "(C:%dus)#%u>", - (int) (1000000.0 * t_closed_total), - (int) vlib_worker_threads[0].barrier_sync_count); - - /* Dump buffer to syslog, and reset for next trace */ - fformat (stderr, "BTRC %s\n", barrier_trace); - btp = barrier_trace; - vlib_worker_threads[0].barrier_context = NULL; -} -#endif -#else - - /* Null functions for default case where barrier tracing isn't used */ -static inline void -barrier_trace_sync (f64 t_entry, f64 t_open, f64 t_closed) -{ -} - -static inline void -barrier_trace_sync_rec (f64 t_entry) -{ -} - -static inline void -barrier_trace_release_rec (f64 t_entry) -{ -} - -static inline void -barrier_trace_release (f64 t_entry, f64 t_closed_total, f64 t_update_main) -{ -} -#endif uword os_get_nthreads (void) @@ -393,7 +308,7 @@ vlib_thread_init (vlib_main_t * vm) w = vlib_worker_threads; w->thread_mheap = clib_mem_get_heap (); w->thread_stack = vlib_thread_stacks[0]; - w->lcore_id = tm->main_lcore; + w->cpu_id = tm->main_lcore; w->lwp = syscall (SYS_gettid); w->thread_id = pthread_self (); tm->n_vlib_mains = 1; @@ -478,7 +393,7 @@ vlib_frame_queue_alloc (int nelts) vlib_frame_queue_t *fq; fq = clib_mem_alloc_aligned (sizeof (*fq), CLIB_CACHE_LINE_BYTES); - memset (fq, 0, sizeof (*fq)); + clib_memset (fq, 0, sizeof (*fq)); fq->nelts = nelts; fq->vector_threshold = 128; // packets vec_validate_aligned (fq->elts, nelts - 1, CLIB_CACHE_LINE_BYTES); @@ -601,7 +516,7 @@ vlib_frame_queue_enqueue (vlib_main_t * vm, u32 node_runtime_index, ASSERT (fq); - new_tail = __sync_add_and_fetch (&fq->tail, 1); + new_tail = clib_atomic_add_fetch (&fq->tail, 1); /* Wait until a ring slot is available */ while (new_tail >= fq->head + fq->nelts) @@ -661,12 +576,12 @@ vlib_worker_thread_init (vlib_worker_thread_t * w) { /* Initial barrier sync, for both worker and i/o threads */ - clib_smp_atomic_add (vlib_worker_threads->workers_at_barrier, 1); + clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, 1); while (*vlib_worker_threads->wait_at_barrier) ; - clib_smp_atomic_add (vlib_worker_threads->workers_at_barrier, -1); + clib_atomic_fetch_add (vlib_worker_threads->workers_at_barrier, -1); } } @@ -688,21 +603,42 @@ vlib_worker_thread_bootstrap_fn (void *arg) return rv; } +static void +vlib_get_thread_core_socket (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; + + 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); + vec_free (p); + + w->core_id = core_id; + w->socket_id = socket_id; +} + static clib_error_t * -vlib_launch_thread_int (void *fp, vlib_worker_thread_t * w, unsigned lcore_id) +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; - w->lcore_id = lcore_id; + w->cpu_id = cpu_id; + vlib_get_thread_core_socket (w, cpu_id); if (tm->cb.vlib_launch_thread_cb && !w->registration->use_pthreads) - return tm->cb.vlib_launch_thread_cb (fp, (void *) w, lcore_id); + return tm->cb.vlib_launch_thread_cb (fp, (void *) w, cpu_id); else { pthread_t worker; cpu_set_t cpuset; CPU_ZERO (&cpuset); - CPU_SET (lcore_id, &cpuset); + CPU_SET (cpu_id, &cpuset); if (pthread_create (&worker, NULL /* attr */ , fp_arg, (void *) w)) return clib_error_return_unix (0, "pthread_create"); @@ -839,8 +775,8 @@ start_workers (vlib_main_t * vm) vm_clone->pending_rpc_requests = 0; vec_validate (vm_clone->pending_rpc_requests, 0); _vec_len (vm_clone->pending_rpc_requests) = 0; - memset (&vm_clone->random_buffer, 0, - sizeof (vm_clone->random_buffer)); + clib_memset (&vm_clone->random_buffer, 0, + sizeof (vm_clone->random_buffer)); nm = &vlib_mains[0]->node_main; nm_clone = &vm_clone->node_main; @@ -876,9 +812,9 @@ start_workers (vlib_main_t * vm) clib_memcpy (n, nm->nodes[j], sizeof (*n)); /* none of the copied nodes have enqueue rights given out */ n->owner_node_index = VLIB_INVALID_NODE_INDEX; - memset (&n->stats_total, 0, sizeof (n->stats_total)); - memset (&n->stats_last_clear, 0, - sizeof (n->stats_last_clear)); + clib_memset (&n->stats_total, 0, sizeof (n->stats_total)); + clib_memset (&n->stats_last_clear, 0, + sizeof (n->stats_last_clear)); vec_add1 (nm_clone->nodes, n); n++; } @@ -1151,10 +1087,10 @@ vlib_worker_thread_node_refork (void) if (j >= vec_len (old_nodes_clone)) { /* new node, set to zero */ - memset (&new_n_clone->stats_total, 0, - sizeof (new_n_clone->stats_total)); - memset (&new_n_clone->stats_last_clear, 0, - sizeof (new_n_clone->stats_last_clear)); + clib_memset (&new_n_clone->stats_total, 0, + sizeof (new_n_clone->stats_total)); + clib_memset (&new_n_clone->stats_last_clear, 0, + sizeof (new_n_clone->stats_last_clear)); } else { @@ -1267,7 +1203,6 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) uword *p; vlib_thread_main_t *tm = &vlib_thread_main; u8 *name; - u64 coremask; uword *bitmap; u32 count; @@ -1296,25 +1231,10 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) ; else if (unformat (input, "skip-cores %u", &tm->skip_cores)) ; - else if (unformat (input, "coremask-%s %llx", &name, &coremask)) - { - p = hash_get_mem (tm->thread_registrations_by_name, name); - if (p == 0) - return clib_error_return (0, "no such thread type '%s'", name); - - tr = (vlib_thread_registration_t *) p[0]; - - if (tr->use_pthreads) - return clib_error_return (0, - "coremask cannot be set for '%s' threads", - name); - - tr->coremask = clib_bitmap_set_multiple - (tr->coremask, 0, coremask, BITS (coremask)); - tr->count = clib_bitmap_count_set_bits (tr->coremask); - } - else if (unformat (input, "corelist-%s %U", &name, unformat_bitmap_list, - &bitmap)) + else if (unformat (input, "coremask-%s %U", &name, + unformat_bitmap_mask, &bitmap) || + unformat (input, "corelist-%s %U", &name, + unformat_bitmap_list, &bitmap)) { p = hash_get_mem (tm->thread_registrations_by_name, name); if (p == 0) @@ -1390,22 +1310,6 @@ cpu_config (vlib_main_t * vm, unformat_input_t * input) VLIB_EARLY_CONFIG_FUNCTION (cpu_config, "cpu"); -#if !defined (__x86_64__) && !defined (__i386__) && !defined (__aarch64__) && !defined (__powerpc64__) && !defined(__arm__) -void -__sync_fetch_and_add_8 (void) -{ - fformat (stderr, "%s called\n", __FUNCTION__); - abort (); -} - -void -__sync_add_and_fetch_8 (void) -{ - fformat (stderr, "%s called\n", __FUNCTION__); - abort (); -} -#endif - void vnet_main_fixup (vlib_fork_fixup_t which) __attribute__ ((weak)); void vnet_main_fixup (vlib_fork_fixup_t which) @@ -1482,9 +1386,21 @@ vlib_worker_thread_barrier_sync_int (vlib_main_t * vm) /* Enforce minimum barrier open time to minimize packet loss */ ASSERT (vm->barrier_no_close_before <= (now + BARRIER_MINIMUM_OPEN_LIMIT)); - while ((now = vlib_time_now (vm)) < vm->barrier_no_close_before) - ; + while (1) + { + now = vlib_time_now (vm); + /* Barrier hold-down timer expired? */ + if (now >= vm->barrier_no_close_before) + break; + if ((vm->barrier_no_close_before - now) + > (2.0 * BARRIER_MINIMUM_OPEN_LIMIT)) + { + clib_warning ("clock change: would have waited for %.4f seconds", + (vm->barrier_no_close_before - now)); + break; + } + } /* Record time of closure */ t_open = now - vm->barrier_epoch; vm->barrier_epoch = now; @@ -1561,8 +1477,8 @@ vlib_worker_thread_barrier_release (vlib_main_t * vm) /* Do per thread rebuilds in parallel */ refork_needed = 1; - clib_smp_atomic_add (vlib_worker_threads->node_reforks_required, - (vec_len (vlib_mains) - 1)); + clib_atomic_fetch_add (vlib_worker_threads->node_reforks_required, + (vec_len (vlib_mains) - 1)); now = vlib_time_now (vm); t_update_main = now - vm->barrier_epoch; } @@ -1795,16 +1711,29 @@ vlib_frame_queue_main_init (u32 node_index, u32 frame_queue_nelts) if (frame_queue_nelts == 0) frame_queue_nelts = FRAME_QUEUE_NELTS; + ASSERT (frame_queue_nelts >= 8); + 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; vec_validate (fqm->vlib_frame_queues, tm->n_vlib_mains - 1); + vec_validate (fqm->per_thread_data, tm->n_vlib_mains - 1); _vec_len (fqm->vlib_frame_queues) = 0; for (i = 0; i < tm->n_vlib_mains; i++) { + vlib_frame_queue_per_thread_data_t *ptd; fq = vlib_frame_queue_alloc (frame_queue_nelts); vec_add1 (fqm->vlib_frame_queues, fq); + + ptd = vec_elt_at_index (fqm->per_thread_data, i); + vec_validate (ptd->handoff_queue_elt_by_thread_index, + tm->n_vlib_mains - 1); + vec_validate_init_empty (ptd->congested_handoff_queue_by_thread_index, + tm->n_vlib_mains - 1, + (vlib_frame_queue_t *) (~0)); } return (fqm - tm->frame_queue_mains);