diff options
author | Sirshak Das <sirshak.das@arm.com> | 2019-02-05 01:33:33 -0600 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2019-04-16 19:33:21 +0000 |
commit | 28aa539f7da7b172d0f35ea9a63f3986939477f7 (patch) | |
tree | be856eb44878b604b2fc93beffb7268db77b457b /src/vnet | |
parent | 39d04099467414175803273433c95a96c0276252 (diff) |
svm_fifo rework to avoid contention on cursize
Problems Addressed:
- Contention of cursize by producer and consumer.
- Reduce the no of modulo operations.
Changes:
- Synchronization between producer and consumer changed from cursize
to head and tail indexes
Implications: reduces the usable size of fifo by 1.
- Using weaker memory ordering C++11 atomics to access head and tail
based on producer and consumer role.
- Head and tail indexes are unsigned 32 bit integers. Additions and
subtraction on them are implicit 32 bit Modulo operation.
- Adding weaker memory ordering variants of max_enq, max_deq, is_empty
and is_full Using them appropriately in all places.
Perfomance improvement (iperf3 via Hoststack):
iperf3 Server: Marvell ThunderX2(AArch64) - iperf3 Client: Skylake(x86)
~6%(256 rxd/txd) - ~11%(2048 rxd/txd)
Change-Id: I1d484e000e437430fdd5a819657d1c6b62443018
Signed-off-by: Sirshak Das <sirshak.das@arm.com>
Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>
Diffstat (limited to 'src/vnet')
-rw-r--r-- | src/vnet/session-apps/echo_client.c | 8 | ||||
-rw-r--r-- | src/vnet/session-apps/echo_server.c | 8 | ||||
-rw-r--r-- | src/vnet/session-apps/http_server.c | 4 | ||||
-rw-r--r-- | src/vnet/session-apps/proxy.c | 2 | ||||
-rw-r--r-- | src/vnet/session/application_interface.h | 4 | ||||
-rw-r--r-- | src/vnet/session/application_worker.c | 19 | ||||
-rw-r--r-- | src/vnet/session/session.c | 6 | ||||
-rw-r--r-- | src/vnet/session/session.h | 4 | ||||
-rw-r--r-- | src/vnet/session/session_node.c | 10 | ||||
-rw-r--r-- | src/vnet/tcp/tcp_input.c | 2 | ||||
-rw-r--r-- | src/vnet/udp/udp_input.c | 5 |
11 files changed, 33 insertions, 39 deletions
diff --git a/src/vnet/session-apps/echo_client.c b/src/vnet/session-apps/echo_client.c index fb7de48f102..39f464d23ce 100644 --- a/src/vnet/session-apps/echo_client.c +++ b/src/vnet/session-apps/echo_client.c @@ -60,7 +60,7 @@ send_data_chunk (echo_client_main_t * ecm, eclient_session_t * s) if (ecm->no_copy) { svm_fifo_t *f = s->data.tx_fifo; - rv = clib_min (svm_fifo_max_enqueue (f), bytes_this_chunk); + rv = clib_min (svm_fifo_max_enqueue_prod (f), bytes_this_chunk); svm_fifo_enqueue_nocopy (f, rv); session_send_io_evt_to_thread_custom (&f->master_session_index, s->thread_index, @@ -77,7 +77,7 @@ send_data_chunk (echo_client_main_t * ecm, eclient_session_t * s) session_dgram_hdr_t hdr; svm_fifo_t *f = s->data.tx_fifo; app_session_transport_t *at = &s->data.transport; - u32 max_enqueue = svm_fifo_max_enqueue (f); + u32 max_enqueue = svm_fifo_max_enqueue_prod (f); if (max_enqueue <= sizeof (session_dgram_hdr_t)) return; @@ -151,7 +151,7 @@ receive_data_chunk (echo_client_main_t * ecm, eclient_session_t * s) } else { - n_read = svm_fifo_max_dequeue (rx_fifo); + n_read = svm_fifo_max_dequeue_cons (rx_fifo); svm_fifo_dequeue_drop (rx_fifo, n_read); } @@ -480,7 +480,7 @@ echo_clients_rx_callback (session_t * s) sp = pool_elt_at_index (ecm->sessions, s->rx_fifo->client_session_index); receive_data_chunk (ecm, sp); - if (svm_fifo_max_dequeue (s->rx_fifo)) + if (svm_fifo_max_dequeue_cons (s->rx_fifo)) { if (svm_fifo_set_event (s->rx_fifo)) session_send_io_evt_to_thread (s->rx_fifo, SESSION_IO_EVT_BUILTIN_RX); diff --git a/src/vnet/session-apps/echo_server.c b/src/vnet/session-apps/echo_server.c index d165fb35e01..4249ed83292 100644 --- a/src/vnet/session-apps/echo_server.c +++ b/src/vnet/session-apps/echo_server.c @@ -139,7 +139,7 @@ int echo_server_builtin_server_rx_callback_no_echo (session_t * s) { svm_fifo_t *rx_fifo = s->rx_fifo; - svm_fifo_dequeue_drop (rx_fifo, svm_fifo_max_dequeue (rx_fifo)); + svm_fifo_dequeue_drop (rx_fifo, svm_fifo_max_dequeue_cons (rx_fifo)); return 0; } @@ -161,10 +161,10 @@ echo_server_rx_callback (session_t * s) ASSERT (rx_fifo->master_thread_index == thread_index); ASSERT (tx_fifo->master_thread_index == thread_index); - max_enqueue = svm_fifo_max_enqueue (tx_fifo); + max_enqueue = svm_fifo_max_enqueue_prod (tx_fifo); if (!esm->is_dgram) { - max_dequeue = svm_fifo_max_dequeue (rx_fifo); + max_dequeue = svm_fifo_max_dequeue_cons (rx_fifo); } else { @@ -255,7 +255,7 @@ echo_server_rx_callback (session_t * s) if (n_written != max_transfer) clib_warning ("short trout! written %u read %u", n_written, max_transfer); - if (PREDICT_FALSE (svm_fifo_max_dequeue (rx_fifo))) + if (PREDICT_FALSE (svm_fifo_max_dequeue_cons (rx_fifo))) goto rx_event; return 0; diff --git a/src/vnet/session-apps/http_server.c b/src/vnet/session-apps/http_server.c index 4547a4dc4ef..c7e06bfbb2d 100644 --- a/src/vnet/session-apps/http_server.c +++ b/src/vnet/session-apps/http_server.c @@ -503,7 +503,7 @@ session_rx_request (http_session_t * hs) int n_read; cursize = vec_len (hs->rx_buf); - max_dequeue = svm_fifo_max_dequeue (hs->rx_fifo); + max_dequeue = svm_fifo_max_dequeue_cons (hs->rx_fifo); if (PREDICT_FALSE (max_dequeue == 0)) return -1; @@ -511,7 +511,7 @@ session_rx_request (http_session_t * hs) n_read = app_recv_stream_raw (hs->rx_fifo, hs->rx_buf + cursize, max_dequeue, 0, 0 /* peek */ ); ASSERT (n_read == max_dequeue); - if (svm_fifo_is_empty (hs->rx_fifo)) + if (svm_fifo_is_empty_cons (hs->rx_fifo)) svm_fifo_unset_event (hs->rx_fifo); _vec_len (hs->rx_buf) = cursize + n_read; diff --git a/src/vnet/session-apps/proxy.c b/src/vnet/session-apps/proxy.c index 0d4cdd43c1c..6542c160f63 100644 --- a/src/vnet/session-apps/proxy.c +++ b/src/vnet/session-apps/proxy.c @@ -227,7 +227,7 @@ proxy_rx_callback (session_t * s) ASSERT (rx_fifo->master_thread_index == thread_index); ASSERT (tx_fifo->master_thread_index == thread_index); - max_dequeue = svm_fifo_max_dequeue (s->rx_fifo); + max_dequeue = svm_fifo_max_dequeue_cons (s->rx_fifo); if (PREDICT_FALSE (max_dequeue == 0)) return 0; diff --git a/src/vnet/session/application_interface.h b/src/vnet/session/application_interface.h index 8323e72e768..b49744c0b29 100644 --- a/src/vnet/session/application_interface.h +++ b/src/vnet/session/application_interface.h @@ -459,7 +459,7 @@ app_send_dgram_raw (svm_fifo_t * f, app_session_transport_t * at, session_dgram_hdr_t hdr; int rv; - max_enqueue = svm_fifo_max_enqueue (f); + max_enqueue = svm_fifo_max_enqueue_prod (f); if (max_enqueue <= sizeof (session_dgram_hdr_t)) return 0; @@ -533,7 +533,7 @@ app_recv_dgram_raw (svm_fifo_t * f, u8 * buf, u32 len, u32 max_deq; int rv; - max_deq = svm_fifo_max_dequeue (f); + max_deq = svm_fifo_max_dequeue_cons (f); if (max_deq < sizeof (session_dgram_hdr_t)) { if (clear_evt) diff --git a/src/vnet/session/application_worker.c b/src/vnet/session/application_worker.c index a8edad3edbb..dd1088e2cbb 100644 --- a/src/vnet/session/application_worker.c +++ b/src/vnet/session/application_worker.c @@ -369,21 +369,12 @@ app_worker_own_session (app_worker_t * app_wrk, session_t * s) if (app_worker_alloc_session_fifos (sm, s)) return -1; - if (!svm_fifo_is_empty (rxf)) - { - clib_memcpy_fast (s->rx_fifo->data, rxf->data, rxf->nitems); - s->rx_fifo->head = rxf->head; - s->rx_fifo->tail = rxf->tail; - s->rx_fifo->cursize = rxf->cursize; - } + if (!svm_fifo_is_empty_cons (rxf)) + svm_fifo_clone (s->rx_fifo, rxf); + + if (!svm_fifo_is_empty_cons (txf)) + svm_fifo_clone (s->tx_fifo, txf); - if (!svm_fifo_is_empty (txf)) - { - clib_memcpy_fast (s->tx_fifo->data, txf->data, txf->nitems); - s->tx_fifo->head = txf->head; - s->tx_fifo->tail = txf->tail; - s->tx_fifo->cursize = txf->cursize; - } segment_manager_dealloc_fifos (rxf, txf); diff --git a/src/vnet/session/session.c b/src/vnet/session/session.c index 90248b64401..58ec1c01369 100644 --- a/src/vnet/session/session.c +++ b/src/vnet/session/session.c @@ -411,7 +411,7 @@ session_enqueue_dgram_connection (session_t * s, { int enqueued = 0, rv, in_order_off; - ASSERT (svm_fifo_max_enqueue (s->rx_fifo) + ASSERT (svm_fifo_max_enqueue_prod (s->rx_fifo) >= b->current_length + sizeof (*hdr)); svm_fifo_enqueue_nowait (s->rx_fifo, sizeof (session_dgram_hdr_t), @@ -508,7 +508,7 @@ session_enqueue_notify_inline (session_t * s) /* *INDENT-OFF* */ SESSION_EVT_DBG(SESSION_EVT_ENQ, s, ({ ed->data[0] = SESSION_IO_EVT_RX; - ed->data[1] = svm_fifo_max_dequeue (s->rx_fifo); + ed->data[1] = svm_fifo_max_dequeue_prod (s->rx_fifo); })); /* *INDENT-ON* */ @@ -1112,7 +1112,7 @@ session_transport_close (session_t * s) * point, either after sending everything or after a timeout, call delete * notify. This will finally lead to the complete cleanup of the session. */ - if (svm_fifo_max_dequeue (s->tx_fifo)) + if (svm_fifo_max_dequeue_cons (s->tx_fifo)) s->session_state = SESSION_STATE_CLOSED_WAITING; else s->session_state = SESSION_STATE_CLOSED; diff --git a/src/vnet/session/session.h b/src/vnet/session/session.h index ed42e5476e9..997d15395ef 100644 --- a/src/vnet/session/session.h +++ b/src/vnet/session/session.h @@ -378,14 +378,14 @@ always_inline u32 transport_max_rx_enqueue (transport_connection_t * tc) { session_t *s = session_get (tc->s_index, tc->thread_index); - return svm_fifo_max_enqueue (s->rx_fifo); + return svm_fifo_max_enqueue_prod (s->rx_fifo); } always_inline u32 transport_max_tx_dequeue (transport_connection_t * tc) { session_t *s = session_get (tc->s_index, tc->thread_index); - return svm_fifo_max_dequeue (s->tx_fifo); + return svm_fifo_max_dequeue_cons (s->tx_fifo); } always_inline u32 diff --git a/src/vnet/session/session_node.c b/src/vnet/session/session_node.c index 2eac5152e16..c894c437cde 100644 --- a/src/vnet/session/session_node.c +++ b/src/vnet/session/session_node.c @@ -82,7 +82,8 @@ session_mq_accepted_reply_handler (void *data) { old_state = s->session_state; s->session_state = SESSION_STATE_READY; - if (!svm_fifo_is_empty (s->rx_fifo)) + + if (!svm_fifo_is_empty_prod (s->rx_fifo)) app_worker_lock_and_send_event (app_wrk, s, SESSION_IO_EVT_RX); /* Closed while waiting for app to reply. Resend disconnect */ @@ -557,7 +558,7 @@ session_tx_set_dequeue_params (vlib_main_t * vm, session_tx_context_t * ctx, u32 max_segs, u8 peek_data) { u32 n_bytes_per_buf, n_bytes_per_seg; - ctx->max_dequeue = svm_fifo_max_dequeue (ctx->s->tx_fifo); + ctx->max_dequeue = svm_fifo_max_dequeue_cons (ctx->s->tx_fifo); if (peek_data) { /* Offset in rx fifo from where to peek data */ @@ -788,7 +789,7 @@ session_tx_fifo_read_and_snd_i (vlib_main_t * vm, vlib_node_runtime_t * node, svm_fifo_overwrite_head (ctx->s->tx_fifo, (u8 *) & ctx->hdr, sizeof (session_dgram_pre_hdr_t)); /* More data needs to be read */ - else if (svm_fifo_max_dequeue (ctx->s->tx_fifo) > 0) + else if (svm_fifo_max_dequeue_cons (ctx->s->tx_fifo) > 0) if (svm_fifo_set_event (ctx->s->tx_fifo)) vec_add1 (wrk->pending_event_vector, *e); } @@ -956,7 +957,8 @@ session_queue_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, * and the tx queue is still not empty, try to wait for some * dispatch cycles */ if (!e->postponed - || (e->postponed < 200 && svm_fifo_max_dequeue (s->tx_fifo))) + || (e->postponed < 200 + && svm_fifo_max_dequeue_cons (s->tx_fifo))) { e->postponed += 1; vec_add1 (wrk->pending_disconnects, *e); diff --git a/src/vnet/tcp/tcp_input.c b/src/vnet/tcp/tcp_input.c index f838bc562ff..3d40c062a87 100644 --- a/src/vnet/tcp/tcp_input.c +++ b/src/vnet/tcp/tcp_input.c @@ -1871,7 +1871,7 @@ tcp_session_enqueue_ooo (tcp_connection_t * tc, vlib_buffer_t * b, newest = svm_fifo_newest_ooo_segment (s0->rx_fifo); if (newest) { - offset = ooo_segment_offset (s0->rx_fifo, newest); + offset = ooo_segment_offset_prod (s0->rx_fifo, newest); ASSERT (offset <= vnet_buffer (b)->tcp.seq_number - tc->rcv_nxt); start = tc->rcv_nxt + offset; end = start + ooo_segment_length (s0->rx_fifo, newest); diff --git a/src/vnet/udp/udp_input.c b/src/vnet/udp/udp_input.c index db634cb2ddb..52c29d7ebfa 100644 --- a/src/vnet/udp/udp_input.c +++ b/src/vnet/udp/udp_input.c @@ -229,7 +229,7 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, if (!uc0->is_connected) { - if (svm_fifo_max_enqueue (s0->rx_fifo) + if (svm_fifo_max_enqueue_prod (s0->rx_fifo) < b0->current_length + sizeof (session_dgram_hdr_t)) { error0 = UDP_ERROR_FIFO_FULL; @@ -255,7 +255,8 @@ udp46_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node, } else { - if (svm_fifo_max_enqueue (s0->rx_fifo) < b0->current_length) + if (svm_fifo_max_enqueue_prod (s0->rx_fifo) < + b0->current_length) { error0 = UDP_ERROR_FIFO_FULL; goto trace0; |