diff options
Diffstat (limited to 'src/svm/fifo_segment.c')
-rw-r--r-- | src/svm/fifo_segment.c | 252 |
1 files changed, 128 insertions, 124 deletions
diff --git a/src/svm/fifo_segment.c b/src/svm/fifo_segment.c index 0263d1a57cc..758b2648ece 100644 --- a/src/svm/fifo_segment.c +++ b/src/svm/fifo_segment.c @@ -218,16 +218,18 @@ fifo_segment_main_init (fifo_segment_main_t * sm, u64 baseva, } static void -fifo_init_for_segment (fifo_segment_header_t * fsh, svm_fifo_t * f, - u32 size, u32 fl_index) +fifo_init_for_segment (svm_fifo_t * f, svm_fifo_chunk_t * c) { - f->freelist_index = fl_index; - f->default_chunk.start_byte = 0; - f->default_chunk.length = size; - f->default_chunk.next = f->start_chunk = f->end_chunk = &f->default_chunk; + f->start_chunk = f->end_chunk = c->next = c; f->head_chunk = f->tail_chunk = f->ooo_enq = f->ooo_deq = f->start_chunk; - f->next = fsh->free_fifos[fl_index]; - fsh->free_fifos[fl_index] = f; +} + +static void +fifo_init_chunk_for_segment (svm_fifo_chunk_t * c, u32 size) +{ + c->start_byte = 0; + c->length = size; + c->next = 0; } static inline int @@ -247,37 +249,76 @@ fs_chunk_size_is_valid (u32 size) && size <= FIFO_SEGMENT_MAX_FIFO_SIZE; } -static void -allocate_new_fifo_batch (fifo_segment_header_t * fsh, - u32 data_size_in_bytes, int chunk_size) +static svm_fifo_t * +fs_try_alloc_fifo_from_freelist (fifo_segment_header_t * fsh, u32 data_bytes) { - u32 size, rounded_data_size; - int i, fl_index; - u8 *fifos_mem; + svm_fifo_chunk_t *c; svm_fifo_t *f; + u32 fl_index; + + f = fsh->free_fifos; + fl_index = fs_free_list_for_size (data_bytes); + vec_validate_init_empty (fsh->free_chunks, fl_index, 0); + c = fsh->free_chunks[fl_index]; + + if (!f || !c) + return 0; + + fsh->free_fifos = f->next; + fsh->free_chunks[fl_index] = c->next; + c->next = c; + c->start_byte = 0; + c->length = data_bytes; + memset (f, 0, sizeof (*f)); + f->start_chunk = c; + f->end_chunk = c; + return f; +} - rounded_data_size = (1 << (max_log2 (data_size_in_bytes))); - fl_index = fs_free_list_for_size (data_size_in_bytes); +static svm_fifo_t * +fs_try_allocate_fifo_batch (ssvm_shared_header_t * sh, + fifo_segment_header_t * fsh, u32 data_bytes) +{ + u32 size, rounded_data_size; + svm_fifo_chunk_t *c; + u32 fl_index, hdrs; + svm_fifo_t *f; + void *oldheap; + u8 *fmem; + int i; - /* Calculate space requirement $$$ round-up data_size_in_bytes */ - size = (sizeof (*f) + rounded_data_size) * chunk_size; + rounded_data_size = (1 << (max_log2 (data_bytes))); + fl_index = fs_free_list_for_size (data_bytes); + vec_validate_init_empty (fsh->free_chunks, fl_index, 0); - /* Allocate fifo space. May fail. */ - fifos_mem = clib_mem_alloc_aligned_at_offset (size, CLIB_CACHE_LINE_BYTES, - 0 /* align_offset */ , - 0 /* os_out_of_memory */ ); + oldheap = ssvm_push_heap (sh); + hdrs = sizeof (*f) + sizeof (*c); + size = (hdrs + rounded_data_size) * FIFO_SEGMENT_ALLOC_BATCH_SIZE; + fmem = clib_mem_alloc_aligned_at_offset (size, CLIB_CACHE_LINE_BYTES, + 0 /* align_offset */ , + 0 /* os_out_of_memory */ ); + ssvm_pop_heap (oldheap); /* Out of space.. */ - if (fifos_mem == 0) - return; + if (fmem == 0) + return 0; - /* Carve fifo space */ - for (i = 0; i < chunk_size; i++) + /* Carve fifo + chunk space */ + for (i = 0; i < FIFO_SEGMENT_ALLOC_BATCH_SIZE; i++) { - f = (svm_fifo_t *) fifos_mem; - fifo_init_for_segment (fsh, f, rounded_data_size, fl_index); - fifos_mem += sizeof (*f) + rounded_data_size; + f = (svm_fifo_t *) fmem; + memset (f, 0, sizeof (*f)); + f->next = fsh->free_fifos; + fsh->free_fifos = f; + c = (svm_fifo_chunk_t *) (fmem + sizeof (*f)); + c->start_byte = 0; + c->length = rounded_data_size; + c->next = fsh->free_chunks[fl_index]; + fsh->free_chunks[fl_index] = c; + fmem += hdrs + rounded_data_size; } + + return fs_try_alloc_fifo_from_freelist (fsh, data_bytes); } /** @@ -290,8 +331,6 @@ fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes, fifo_segment_header_t *fsh; ssvm_shared_header_t *sh; svm_fifo_t *f = 0; - void *oldheap; - int fl_index; if (!fs_chunk_size_is_valid (data_bytes)) { @@ -299,45 +338,30 @@ fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes, return 0; } - fl_index = fs_free_list_for_size (data_bytes); - sh = fs->ssvm.sh; ssvm_lock_non_recursive (sh, 1); - fsh = fs->h; - vec_validate_init_empty (fsh->free_fifos, fl_index, 0); - f = fsh->free_fifos[fl_index]; - /* Try to allocate batch of fifos */ - if (PREDICT_FALSE (!f)) + /* Try the following steps in order: + * - grab fifo and chunk from freelists + * - batch fifo and chunk allocation + * - single fifo allocation + */ + f = fs_try_alloc_fifo_from_freelist (fsh, data_bytes); + if (!f) + f = fs_try_allocate_fifo_batch (sh, fsh, data_bytes); + if (!f) { - oldheap = ssvm_push_heap (sh); - allocate_new_fifo_batch (fsh, data_bytes, - FIFO_SEGMENT_ALLOC_BATCH_SIZE); + void *oldheap = ssvm_push_heap (sh); + f = svm_fifo_create (data_bytes); ssvm_pop_heap (oldheap); - f = fsh->free_fifos[fl_index]; - } - if (PREDICT_TRUE (f != 0)) - { - fsh->free_fifos[fl_index] = f->next; - /* (re)initialize the fifo, as in svm_fifo_create */ - memset (f, 0, sizeof (*f)); - svm_fifo_init (f, data_bytes); - goto found; + if (!f) + goto done; } - /* Failed to allocate batch, try just one fifo. This can also fail, - * in which case, create another segment */ - oldheap = ssvm_push_heap (sh); - f = svm_fifo_create (data_bytes); - ssvm_pop_heap (oldheap); - - if (PREDICT_FALSE (f == 0)) - goto done; + /* (re)initialize the fifo, as in svm_fifo_create */ + svm_fifo_init (f, data_bytes); - f->freelist_index = fl_index; - -found: /* If rx fifo type add to active fifos list. When cleaning up segment, * we need a list of active sessions that should be disconnected. Since * both rx and tx fifos keep pointers to the session, it's enough to track @@ -365,8 +389,10 @@ done: void fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f) { + svm_fifo_chunk_t *cur, *next; fifo_segment_header_t *fsh; ssvm_shared_header_t *sh; + void *oldheap; int fl_index; ASSERT (f->refcnt > 0); @@ -376,9 +402,6 @@ fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f) sh = fs->ssvm.sh; fsh = fs->h; - fl_index = f->freelist_index; - - ASSERT (fl_index < vec_len (fsh->free_fifos)); ssvm_lock_non_recursive (sh, 2); @@ -395,29 +418,26 @@ fifo_segment_free_fifo (fifo_segment_t * fs, svm_fifo_t * f) } /* Add to free list */ - f->next = fsh->free_fifos[fl_index]; + f->next = fsh->free_fifos; f->prev = 0; - fsh->free_fifos[fl_index] = f; + fsh->free_fifos = f; - /* If fifo has more chunks, free them */ - if (f->flags & SVM_FIFO_F_MULTI_CHUNK) + /* Free fifo chunks */ + cur = f->start_chunk; + do { - svm_fifo_chunk_t *cur, *next; - void *oldheap; - - next = f->start_chunk->next; - while (next != f->start_chunk) - { - cur = next; - next = next->next; - fl_index = fs_free_list_for_size (cur->length); - cur->next = fsh->free_chunks[fl_index]; - fsh->free_chunks[fl_index] = cur; - } - oldheap = ssvm_push_heap (sh); - svm_fifo_free_chunk_lookup (f); - ssvm_pop_heap (oldheap); + next = cur->next; + fl_index = fs_free_list_for_size (cur->length); + ASSERT (fl_index < vec_len (fsh->free_chunks)); + cur->next = fsh->free_chunks[fl_index]; + fsh->free_chunks[fl_index] = cur; + cur = next; } + while (cur != f->start_chunk); + + oldheap = ssvm_push_heap (sh); + svm_fifo_free_chunk_lookup (f); + ssvm_pop_heap (oldheap); /* not allocated on segment heap */ svm_fifo_free_ooo_data (f); @@ -447,8 +467,10 @@ fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs, int i, rx_fl_index, tx_fl_index; u8 *rx_fifo_mem, *tx_fifo_mem; uword space_available; + svm_fifo_chunk_t *c; void *oldheap; svm_fifo_t *f; + u32 hdrs; /* Parameter check */ if (rx_fifo_size == 0 || tx_fifo_size == 0 || *n_fifo_pairs == 0) @@ -471,8 +493,10 @@ fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs, tx_rounded_data_size = (1 << (max_log2 (tx_fifo_size))); tx_fl_index = fs_free_list_for_size (tx_fifo_size); + hdrs = sizeof (*f) + sizeof (*c); + /* Calculate space requirements */ - pair_size = 2 * sizeof (*f) + rx_rounded_data_size + tx_rounded_data_size; + pair_size = 2 * hdrs + rx_rounded_data_size + tx_rounded_data_size; #if USE_DLMALLOC == 0 space_available = fs->ssvm.ssvm_size - mheap_bytes (sh->heap); #else @@ -480,10 +504,10 @@ fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs, #endif pairs_to_allocate = clib_min (space_available / pair_size, *n_fifo_pairs); - rx_fifos_size = (sizeof (*f) + rx_rounded_data_size) * pairs_to_allocate; - tx_fifos_size = (sizeof (*f) + tx_rounded_data_size) * pairs_to_allocate; + rx_fifos_size = (hdrs + rx_rounded_data_size) * pairs_to_allocate; + tx_fifos_size = (hdrs + tx_rounded_data_size) * pairs_to_allocate; - vec_validate_init_empty (fsh->free_fifos, + vec_validate_init_empty (fsh->free_chunks, clib_max (rx_fl_index, tx_fl_index), 0); oldheap = ssvm_push_heap (sh); @@ -512,12 +536,16 @@ fifo_segment_preallocate_fifo_pairs (fifo_segment_t * fs, for (i = 0; i < pairs_to_allocate; i++) { f = (svm_fifo_t *) rx_fifo_mem; - fifo_init_for_segment (fsh, f, rx_rounded_data_size, rx_fl_index); - rx_fifo_mem += sizeof (*f) + rx_rounded_data_size; + c = (svm_fifo_chunk_t *) (rx_fifo_mem + sizeof (*f)); + fifo_init_chunk_for_segment (c, rx_rounded_data_size); + fifo_init_for_segment (f, c); + rx_fifo_mem += hdrs + rx_rounded_data_size; f = (svm_fifo_t *) tx_fifo_mem; - fifo_init_for_segment (fsh, f, tx_rounded_data_size, tx_fl_index); - tx_fifo_mem += sizeof (*f) + tx_rounded_data_size; + c = (svm_fifo_chunk_t *) (tx_fifo_mem + sizeof (*f)); + fifo_init_chunk_for_segment (c, tx_rounded_data_size); + fifo_init_for_segment (f, c); + tx_fifo_mem += hdrs + tx_rounded_data_size; } /* Account for the pairs allocated */ @@ -561,6 +589,7 @@ fifo_segment_grow_fifo (fifo_segment_t * fs, svm_fifo_t * f, u32 chunk_size) else { fs->h->free_chunks[fl_index] = c->next; + c->next = 0; } svm_fifo_add_chunk (f, c); @@ -611,40 +640,15 @@ fifo_segment_num_fifos (fifo_segment_t * fs) u32 fifo_segment_num_free_fifos (fifo_segment_t * fs, u32 fifo_size_in_bytes) { - u32 count = 0, rounded_data_size, fl_index; fifo_segment_header_t *fsh; ssvm_shared_header_t *sh; svm_fifo_t *f; - int i; + u32 count = 0; sh = fs->ssvm.sh; fsh = (fifo_segment_header_t *) sh->opaque[0]; - /* Count all free fifos? */ - if (fifo_size_in_bytes == ~0) - { - for (i = 0; i < vec_len (fsh->free_fifos); i++) - { - f = fsh->free_fifos[i]; - if (f == 0) - continue; - - while (f) - { - f = f->next; - count++; - } - } - return count; - } - - rounded_data_size = (1 << (max_log2 (fifo_size_in_bytes))); - fl_index = fs_free_list_for_size (rounded_data_size); - - if (fl_index >= vec_len (fsh->free_fifos)) - return 0; - - f = fsh->free_fifos[fl_index]; + f = fsh->free_fifos; if (f == 0) return 0; @@ -742,7 +746,7 @@ format_fifo_segment (u8 * s, va_list * args) int verbose __attribute__ ((unused)) = va_arg (*args, int); fifo_segment_header_t *fsh = sp->h; u32 count, indent; - svm_fifo_t *f; + svm_fifo_chunk_t *c; int i; indent = format_get_indent (s) + 2; @@ -753,15 +757,15 @@ format_fifo_segment (u8 * s, va_list * args) format_white_space, indent, fifo_segment_num_fifos (sp)); #endif - for (i = 0; i < vec_len (fsh->free_fifos); i++) + for (i = 0; i < vec_len (fsh->free_chunks); i++) { - f = fsh->free_fifos[i]; - if (f == 0) + c = fsh->free_chunks[i]; + if (c == 0) continue; count = 0; - while (f) + while (c) { - f = f->next; + c = c->next; count++; } |