diff options
author | Florin Coras <fcoras@cisco.com> | 2019-12-19 16:10:58 -0800 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2020-02-25 19:18:49 +0000 |
commit | f22f4e562e1b922cff036ef628b77fd2d479d015 (patch) | |
tree | 4cbc3091a5ce89a73c94685dcee198dd583ca375 /src/plugins/unittest/svm_fifo_test.c | |
parent | b020806806c0e6c54886cdb4347a5fd1f19504b0 (diff) |
svm: refactor fifo
Type: refactor
Switch from a wrapped byte space to a "continuous" one wherein fifo
chunks are appended to the fifo as more data is enqueued and chunks are
removed as data is dequeued.
The fifo is still subject to a maximum size, i.e., maximum number of
bytes that can be enqueued, so the max number of chunks associated to
the fifo is also constrained.
When enqueueing data, which must fit within the available free space, if
not enough "supporting" chunk memory is available, the fifo asks the
fifo segment for enough chunk memory to ensure that the write can
succeed. To avoid allocating large amounts of small chunks due to small
writes, if possible, the size of the chunks requested is lower capped by
min_alloc.
When dequeuing data, all the chunks that have been completely drained,
i.e., head moved beyond the chunks’ end bytes, are unlinked from the
fifo and returned to the fifo segment. The one exception to this is the
last chunk which is never unlinked.
Change-Id: I98c1dbd9135fb79650365c7e40c29238b96cd4ee
Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/plugins/unittest/svm_fifo_test.c')
-rw-r--r-- | src/plugins/unittest/svm_fifo_test.c | 1523 |
1 files changed, 724 insertions, 799 deletions
diff --git a/src/plugins/unittest/svm_fifo_test.c b/src/plugins/unittest/svm_fifo_test.c index 8b43ee370f1..8579cec15b4 100644 --- a/src/plugins/unittest/svm_fifo_test.c +++ b/src/plugins/unittest/svm_fifo_test.c @@ -158,18 +158,54 @@ fifo_get_validate_pattern (vlib_main_t * vm, test_pattern_t * test_data, return validate_pattern; } +static fifo_segment_t * +fifo_segment_prepare (fifo_segment_main_t * sm, char *seg_name, u32 seg_size) +{ + fifo_segment_create_args_t _a, *a = &_a; + + clib_memset (a, 0, sizeof (*a)); + a->segment_name = seg_name; + a->segment_size = seg_size ? seg_size : 32 << 20; + + if (fifo_segment_create (sm, a)) + return 0; + + return fifo_segment_get_segment (sm, a->new_segment_indices[0]); +} + +static void +ft_fifo_segment_free (fifo_segment_main_t * sm, fifo_segment_t * fs) +{ + fifo_segment_delete (sm, fs); +} + static svm_fifo_t * -fifo_prepare (u32 fifo_size) +fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes, + fifo_segment_ftype_t ftype) +{ + return fifo_segment_alloc_fifo_w_slice (fs, 0, data_bytes, ftype); +} + +static svm_fifo_t * +fifo_prepare (fifo_segment_t * fs, u32 fifo_size) { svm_fifo_t *f; - f = svm_fifo_create (fifo_size); + + f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO); /* Paint fifo data vector with -1's */ - clib_memset (f->head_chunk->data, 0xFF, fifo_size); + clib_memset (svm_fifo_head_chunk (f)->data, 0xFF, fifo_size); + svm_fifo_init_ooo_lookup (f, 1 /* deq ooo */ ); return f; } +static void +ft_fifo_free (fifo_segment_t * fs, svm_fifo_t * f) +{ + fifo_segment_free_fifo (fs, f); +} + static int compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index) { @@ -189,14 +225,14 @@ compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index) int sfifo_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) { - svm_fifo_t *f; - u32 fifo_size = 1 << 20; - u32 *test_data = 0; - u32 offset; + u32 fifo_size = 1 << 20, *test_data = 0, offset, data_word, test_data_len; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; + u8 *data, *s, *data_buf = 0; int i, rv, verbose = 0; - u32 data_word, test_data_len, j; ooo_segment_t *ooo_seg; - u8 *data, *s, *data_buf = 0; + fifo_segment_t *fs; + svm_fifo_t *f; + u32 j; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -210,7 +246,8 @@ sfifo_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) for (i = 0; i < vec_len (test_data); i++) test_data[i] = i; - f = fifo_prepare (fifo_size); + fs = fifo_segment_prepare (fsm, "fifo-test1", 0); + f = fifo_prepare (fs, fifo_size); /* * Enqueue an initial (un-dequeued) chunk @@ -337,8 +374,8 @@ sfifo_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) /* * Test segment overlaps: last ooo segment overlaps all */ - svm_fifo_free (f); - f = fifo_prepare (fifo_size); + ft_fifo_free (fs, f); + f = fifo_prepare (fs, fifo_size); for (i = 0; i < 4; i++) { @@ -378,8 +415,8 @@ sfifo_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) /* * Test segment overlaps: enqueue and overlap ooo segments */ - svm_fifo_free (f); - f = fifo_prepare (fifo_size); + ft_fifo_free (fs, f); + f = fifo_prepare (fs, fifo_size); for (i = 0; i < 4; i++) { @@ -419,26 +456,31 @@ sfifo_test_fifo1 (vlib_main_t * vm, unformat_input_t * input) SFIFO_TEST ((rv == 0), "peeked %u expected 0", rv); vec_free (data_buf); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); vec_free (test_data); return 0; err: - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); vec_free (test_data); + return -1; } static int sfifo_test_fifo2 (vlib_main_t * vm) { - svm_fifo_t *f; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; + test_pattern_t *tp, *vp, *test_data; u32 fifo_size = (1 << 20) + 1; int i, rv, test_data_len; - u64 data64; - test_pattern_t *tp, *vp, *test_data; ooo_segment_t *ooo_seg; + fifo_segment_t *fs; + svm_fifo_t *f; + u64 data64; test_data = test_pattern; test_data_len = ARRAY_LEN (test_pattern); @@ -446,7 +488,8 @@ sfifo_test_fifo2 (vlib_main_t * vm) vp = fifo_get_validate_pattern (vm, test_data, test_data_len); /* Create a fifo */ - f = fifo_prepare (fifo_size); + fs = fifo_segment_prepare (fsm, "fifo-test2", 0); + f = fifo_prepare (fs, fifo_size); /* * Try with sorted data @@ -472,14 +515,14 @@ sfifo_test_fifo2 (vlib_main_t * vm) rv = svm_fifo_enqueue (f, sizeof (u32), (u8 *) & data64); SFIFO_TEST ((rv == 3000), "bytes to be enqueued %u", rv); - svm_fifo_free (f); + ft_fifo_free (fs, f); vec_free (vp); /* * Now try it again w/ unsorted data... */ - f = fifo_prepare (fifo_size); + f = fifo_prepare (fs, fifo_size); for (i = 0; i < test_data_len; i++) { @@ -507,7 +550,8 @@ sfifo_test_fifo2 (vlib_main_t * vm) SFIFO_TEST ((rv == 3000), "bytes to be enqueued %u", rv); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); return 0; } @@ -515,16 +559,15 @@ sfifo_test_fifo2 (vlib_main_t * vm) static int sfifo_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) { - svm_fifo_t *f; - u32 fifo_size = (4 << 10) + 1; - u32 fifo_initial_offset = 0; - u32 total_size = 2 << 10; + u32 nsegs = 2, seg_size, length_so_far, current_offset, offset_increment; int overlap = 0, verbose = 0, randomize = 1, drop = 0, in_seq_all = 0; + u32 len_this_chunk, seed = 0xdeaddabe, j, total_size = 2 << 10; + u32 fifo_size = (4 << 10) + 1, fifo_initial_offset = 0; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u8 *data_pattern = 0, *data_buf = 0; test_pattern_t *tp, *generate = 0; - u32 nsegs = 2, seg_size, length_so_far; - u32 current_offset, offset_increment, len_this_chunk; - u32 seed = 0xdeaddabe, j; + fifo_segment_t *fs; + svm_fifo_t *f; int i, rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -649,7 +692,8 @@ sfifo_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) /* * Create a fifo and add segments */ - f = fifo_prepare (fifo_size); + fs = fifo_segment_prepare (fsm, "fifo-test3", 0); + f = fifo_prepare (fs, fifo_size); /* manually set head and tail pointers to validate modular arithmetic */ fifo_initial_offset = fifo_initial_offset % fifo_size; @@ -730,7 +774,8 @@ sfifo_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) SFIFO_TEST ((svm_fifo_max_dequeue (f) == 0), "fifo has %d bytes", svm_fifo_max_dequeue (f)); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); vec_free (data_pattern); vec_free (data_buf); @@ -740,12 +785,12 @@ sfifo_test_fifo3 (vlib_main_t * vm, unformat_input_t * input) static int sfifo_test_fifo4 (vlib_main_t * vm, unformat_input_t * input) { - svm_fifo_t *f; - u32 fifo_size = 6 << 10; - u32 fifo_initial_offset = 1000000000; - u32 test_n_bytes = 5000, j; + u32 fifo_size = 6 << 10, fifo_initial_offset = 1e9, test_n_bytes = 5000, j; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u8 *test_data = 0, *data_buf = 0; int i, rv, verbose = 0; + fifo_segment_t *fs; + svm_fifo_t *f; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -763,7 +808,8 @@ sfifo_test_fifo4 (vlib_main_t * vm, unformat_input_t * input) /* * Create a fifo and add segments */ - f = fifo_prepare (fifo_size); + fs = fifo_segment_prepare (fsm, "fifo-test4", 0); + f = fifo_prepare (fs, fifo_size); /* Set head and tail pointers */ fifo_initial_offset = fifo_initial_offset % fifo_size; @@ -780,12 +826,7 @@ sfifo_test_fifo4 (vlib_main_t * vm, unformat_input_t * input) if (verbose) vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8)); if (rv) - { - clib_warning ("enqueue returned %d", rv); - svm_fifo_free (f); - vec_free (test_data); - return -1; - } + SFIFO_TEST (0, "enqueue returned %d", rv); } svm_fifo_enqueue (f, sizeof (u8), &test_data[0]); @@ -799,7 +840,8 @@ sfifo_test_fifo4 (vlib_main_t * vm, unformat_input_t * input) test_data[j]); SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); vec_free (test_data); return 0; } @@ -807,7 +849,7 @@ sfifo_test_fifo4 (vlib_main_t * vm, unformat_input_t * input) static u32 fifo_pos (svm_fifo_t * f, u32 pos) { - return pos % f->size; + return pos; } /* Avoids exposing svm_fifo.c internal function */ @@ -822,11 +864,13 @@ ooo_seg_next (svm_fifo_t * f, ooo_segment_t * s) static int sfifo_test_fifo5 (vlib_main_t * vm, unformat_input_t * input) { - svm_fifo_t *f; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u32 fifo_size = 401, j = 0, offset = 200; - int i, rv, verbose = 0; u8 *test_data = 0, *data_buf = 0; + int i, rv, verbose = 0; ooo_segment_t *ooo_seg; + fifo_segment_t *fs; + svm_fifo_t *f; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -841,7 +885,8 @@ sfifo_test_fifo5 (vlib_main_t * vm, unformat_input_t * input) } } - f = fifo_prepare (fifo_size); + fs = fifo_segment_prepare (fsm, "fifo-test5", 0); + f = fifo_prepare (fs, fifo_size); svm_fifo_init_pointers (f, offset, offset); vec_validate (test_data, 399); @@ -930,8 +975,8 @@ sfifo_test_fifo5 (vlib_main_t * vm, unformat_input_t * input) /* * Add [100 200] and overlap it with [50 250] */ - svm_fifo_free (f); - f = fifo_prepare (fifo_size); + ft_fifo_free (fs, f); + f = fifo_prepare (fs, fifo_size); svm_fifo_enqueue_with_offset (f, 100, 100, &test_data[100]); svm_fifo_enqueue_with_offset (f, 50, 200, &test_data[50]); @@ -943,7 +988,8 @@ sfifo_test_fifo5 (vlib_main_t * vm, unformat_input_t * input) SFIFO_TEST ((ooo_seg->length == 200), "first seg length %u expected %u", ooo_seg->length, 200); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); vec_free (test_data); return 0; } @@ -954,10 +1000,12 @@ sfifo_test_fifo5 (vlib_main_t * vm, unformat_input_t * input) static int sfifo_test_fifo6 (vlib_main_t * vm, unformat_input_t * input) { + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u32 fifo_size = 101, n_test_bytes = 100; int i, j, rv, __clib_unused verbose = 0; u8 *test_data = 0, *data_buf = 0; ooo_segment_t *ooo_seg; + fifo_segment_t *fs; svm_fifo_t *f; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -972,40 +1020,18 @@ sfifo_test_fifo6 (vlib_main_t * vm, unformat_input_t * input) } } - f = fifo_prepare (fifo_size); + fs = fifo_segment_prepare (fsm, "fifo-test6", 0); + f = fifo_prepare (fs, fifo_size); + vec_validate (test_data, n_test_bytes - 1); vec_validate (data_buf, n_test_bytes - 1); for (i = 0; i < vec_len (test_data); i++) test_data[i] = i % 0xff; /* - * Test ooo segment distance to/from tail with u32 wrap - */ - - /* - * |0|---[start]--(len5)-->|0|--(len6)-->[end]---|0| - */ - rv = f_distance_from (f, ~0 - 5, 5); - SFIFO_TEST (rv == 11, "distance to tail should be %u is %u", 11, rv); - - rv = f_distance_to (f, ~0 - 5, 5); - SFIFO_TEST (rv == f->size - 11, "distance from tail should be %u is %u", - f->size - 11, rv); - - /* - * |0|---[end]--(len5)-->|0|--(len6)-->[start]---|0| - */ - rv = f_distance_to (f, 5, ~0 - 5); - SFIFO_TEST (rv == 11, "distance from tail should be %u is %u", 11, rv); - - rv = f_distance_from (f, 5, ~0 - 5); - SFIFO_TEST (rv == f->size - 11, "distance to tail should be %u is %u", - f->size - 11, rv); - - /* * Add ooo with tail and ooo segment start u32 wrap */ - svm_fifo_init_pointers (f, ~0, ~0); + svm_fifo_init_pointers (f, ~0 % fifo_size, ~0 % fifo_size); svm_fifo_enqueue_with_offset (f, 10, 10, &test_data[10]); SFIFO_TEST ((svm_fifo_n_ooo_segments (f) == 1), "number of ooo segments %u", svm_fifo_n_ooo_segments (f)); @@ -1032,7 +1058,7 @@ sfifo_test_fifo6 (vlib_main_t * vm, unformat_input_t * input) /* * Force collect with tail u32 wrap and without ooo segment start u32 wrap */ - svm_fifo_init_pointers (f, ~0 - 10, ~0 - 10); + svm_fifo_init_pointers (f, (~0 - 10) % fifo_size, (~0 - 10) % fifo_size); svm_fifo_enqueue_with_offset (f, 5, 15, &test_data[5]); svm_fifo_enqueue (f, 12, test_data); @@ -1051,7 +1077,8 @@ sfifo_test_fifo6 (vlib_main_t * vm, unformat_input_t * input) */ vec_free (test_data); vec_free (data_buf); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); return 0; } @@ -1061,10 +1088,12 @@ sfifo_test_fifo6 (vlib_main_t * vm, unformat_input_t * input) static int sfifo_test_fifo7 (vlib_main_t * vm, unformat_input_t * input) { + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u32 fifo_size = 101, n_iterations = 100; int i, j, rv, __clib_unused verbose = 0; u8 *test_data = 0, *data_buf = 0; u64 n_test_bytes = 100; + fifo_segment_t *fs; svm_fifo_t *f; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -1082,8 +1111,9 @@ sfifo_test_fifo7 (vlib_main_t * vm, unformat_input_t * input) /* * Prepare data structures */ - f = fifo_prepare (fifo_size); - svm_fifo_init_pointers (f, ~0, ~0); + fs = fifo_segment_prepare (fsm, "fifo-test7", 0); + f = fifo_prepare (fs, fifo_size); + svm_fifo_init_pointers (f, ~0 % fifo_size, ~0 % fifo_size); vec_validate (test_data, n_test_bytes - 1); vec_validate (data_buf, n_test_bytes - 1); @@ -1118,7 +1148,7 @@ sfifo_test_fifo7 (vlib_main_t * vm, unformat_input_t * input) if (compare_data (data_buf, test_data, 0, n_test_bytes, (u32 *) & j)) SFIFO_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j], test_data[j]); - svm_fifo_init_pointers (f, ~0 - i, ~0 - i); + svm_fifo_init_pointers (f, (~0 - i) % f->size, (~0 - i) % f->size); } SFIFO_TEST (1, "passed multiple ooo enqueue/dequeue"); @@ -1127,7 +1157,8 @@ sfifo_test_fifo7 (vlib_main_t * vm, unformat_input_t * input) */ vec_free (test_data); vec_free (data_buf); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); return 0; } @@ -1137,10 +1168,12 @@ sfifo_test_fifo7 (vlib_main_t * vm, unformat_input_t * input) static int sfifo_test_fifo_large (vlib_main_t * vm, unformat_input_t * input) { - u32 n_iterations = 100, n_bytes_per_iter, half; + u32 n_iterations = 100, n_bytes_per_iter, half, fifo_size; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; int i, j, rv, __clib_unused verbose = 0; u8 *test_data = 0, *data_buf = 0; u64 n_test_bytes = 100; + fifo_segment_t *fs; svm_fifo_t *f; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -1155,13 +1188,14 @@ sfifo_test_fifo_large (vlib_main_t * vm, unformat_input_t * input) } } - n_test_bytes = 5ULL << 30; n_iterations = 1 << 10; n_bytes_per_iter = n_test_bytes / n_iterations; + fifo_size = n_bytes_per_iter + 1; - f = fifo_prepare (n_bytes_per_iter + 1); - svm_fifo_init_pointers (f, ~0, ~0); + fs = fifo_segment_prepare (fsm, "fifo-large", 0); + f = fifo_prepare (fs, fifo_size); + svm_fifo_init_pointers (f, ~0 % fifo_size, ~0 % fifo_size); vec_validate (test_data, n_bytes_per_iter - 1); vec_validate (data_buf, n_bytes_per_iter - 1); @@ -1184,17 +1218,162 @@ sfifo_test_fifo_large (vlib_main_t * vm, unformat_input_t * input) } SFIFO_TEST (1, "passed large transfer"); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); + + return 0; +} + +static void +validate_test_and_buf_vecs (u8 ** test_data, u8 ** data_buf, u32 len) +{ + int i, cur_len; + + cur_len = vec_len (*test_data); + vec_validate (*test_data, len - 1); + vec_validate (*data_buf, len - 1); + + for (i = cur_len; i < vec_len (*test_data); i++) + (*test_data)[i] = i; +} + +static int +enqueue_ooo (svm_fifo_t * f, u8 * test_data, u32 len, u32 iterations) +{ + u32 offset, enq_now, ooo_chunk; + int i, rv; + + ooo_chunk = len / iterations; + for (i = iterations; i > 0; i--) + { + offset = i * ooo_chunk; + enq_now = clib_min (ooo_chunk, len - offset); + if (!enq_now) + continue; + rv = svm_fifo_enqueue_with_offset (f, offset, enq_now, + test_data + offset); + if (rv) + return rv; + } + + return 0; +} + +static int +enqueue_ooo_packets (svm_fifo_t * f, u32 len, u32 enq_chunk, u8 * test_data) +{ + u32 offset, enq_now; + int i, rv; + + for (i = 1; i <= len / enq_chunk; i++) + { + offset = i * enq_chunk; + enq_now = clib_min (enq_chunk, len - offset); + if (!enq_now) + continue; + rv = svm_fifo_enqueue_with_offset (f, offset, enq_now, + test_data + offset); + if (rv) + return rv; + + if (svm_fifo_size (f) < len - 4096) + svm_fifo_set_size (f, svm_fifo_size (f) + enq_now); + else + svm_fifo_set_size (f, len); + } + + return 0; +} + +static int +enqueue_packets_inc (svm_fifo_t * f, u32 len, u32 enq_chunk, u8 * test_data) +{ + u32 enq_now, offset; + int i, rv; + + for (i = 0; i <= len / enq_chunk; i++) + { + offset = i * enq_chunk; + enq_now = clib_min (enq_chunk, len - offset); + rv = svm_fifo_enqueue (f, enq_now, test_data + offset); + if (rv != enq_now) + return -1; + if (svm_fifo_size (f) < len - 4096) + svm_fifo_set_size (f, svm_fifo_size (f) + enq_now); + else + svm_fifo_set_size (f, len); + } + return 0; +} + +static int +dequeue_ooo (svm_fifo_t * f, u8 * data_buf, u32 len, u32 iterations) +{ + u32 offset, ooo_chunk, deq_now; + int i, rv; + + ooo_chunk = len / iterations; + for (i = iterations; i >= 0; i--) + { + offset = i * ooo_chunk; + deq_now = clib_min (ooo_chunk, len - offset); + if (deq_now == 0) + continue; + rv = svm_fifo_peek (f, offset, deq_now, data_buf + offset); + if (rv != deq_now) + return rv; + } + return 0; +} + +static int +dequeue_ooo_inc (svm_fifo_t * f, u8 * data_buf, u32 len, u32 iterations) +{ + u32 offset, ooo_chunk, deq_now; + int i, rv; + + ooo_chunk = len / iterations; + for (i = 0; i <= iterations; i++) + { + offset = i * ooo_chunk; + deq_now = clib_min (ooo_chunk, len - offset); + if (deq_now == 0) + continue; + rv = svm_fifo_peek (f, offset, deq_now, data_buf + offset); + if (rv != deq_now) + return rv; + } + return 0; +} + +static int +dequeue_packets (svm_fifo_t * f, u32 len, u32 deq_chunk, u8 * data_buf) +{ + u32 offset, deq_now; + int i, rv; + + for (i = 0; i <= len / deq_chunk; i++) + { + offset = i * deq_chunk; + deq_now = clib_min (deq_chunk, len - offset); + if (deq_now == 0) + continue; + rv = svm_fifo_dequeue (f, deq_now, data_buf + offset); + if (rv != deq_now) + return rv; + } return 0; } static int sfifo_test_fifo_grow (vlib_main_t * vm, unformat_input_t * input) { - int verbose = 0, fifo_size = 201, start_offset = 100, i, j, rv; - int test_n_bytes, deq_bytes, enq_bytes, n_deqs, n_enqs; - svm_fifo_chunk_t *c, *next, *prev; + int __clib_unused verbose = 0, fifo_size = 4096, fifo_inc = 4096, rv, i; + u32 enq_chunk, offset, deq_now, last_start_byte; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u8 *test_data = 0, *data_buf = 0; - u32 old_tail, offset; + svm_fifo_chunk_t *c; + fifo_segment_t *fs; svm_fifo_t *f; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) @@ -1209,365 +1388,364 @@ sfifo_test_fifo_grow (vlib_main_t * vm, unformat_input_t * input) } } - f = fifo_prepare (fifo_size); - svm_fifo_init_pointers (f, start_offset, start_offset); + fs = fifo_segment_prepare (fsm, "fifo-grow", 0); + f = fifo_prepare (fs, fifo_size); /* - * Add with fifo not wrapped + * Grow size and alloc chunks by enqueueing in order */ - c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100); - c->length = 100; - c->start_byte = ~0; - c->next = 0; + fifo_size += fifo_inc; + svm_fifo_set_size (f, fifo_size); + last_start_byte = 4096; + validate_test_and_buf_vecs (&test_data, &data_buf, fifo_size); - svm_fifo_add_chunk (f, c); + rv = svm_fifo_enqueue (f, fifo_size, test_data); - SFIFO_TEST (f->size == fifo_size + 100, "size expected %u is %u", - fifo_size + 100, f->size); - SFIFO_TEST (c->start_byte == fifo_size, "start byte expected %u is %u", - fifo_size, c->start_byte); + SFIFO_TEST (rv == fifo_size, "enqueue should work"); + SFIFO_TEST (svm_fifo_size (f) == fifo_size, "size expected %u is %u", + fifo_size, svm_fifo_size (f)); + SFIFO_TEST (svm_fifo_max_dequeue (f) == fifo_size, "max deq should be %u", + fifo_size); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have 2 chunks has %u", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + c = f->head_chunk; + SFIFO_TEST (c->start_byte == 0, "head start byte should be %u", 0); + SFIFO_TEST (c->length == 4096, "head chunk length should be %u", 4096); + SFIFO_TEST (f->tail_chunk == 0, "no tail chunk"); + SFIFO_TEST (f->ooo_enq == 0, "should have no ooo enq chunk"); + SFIFO_TEST (f->ooo_deq == 0, "should have no ooo deq chunk"); + c = f->end_chunk; + SFIFO_TEST (c->start_byte == last_start_byte, "end chunk start byte should" + " be %u", last_start_byte); + SFIFO_TEST (c->length == 4096, "end chunk length should be %u", 4096); + /* - * Add with fifo wrapped + * Dequeue and validate data */ - svm_fifo_init_pointers (f, f->nitems - 100, f->nitems + 100); - c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100); - c->length = 100; - c->start_byte = ~0; - c->next = 0; + rv = svm_fifo_dequeue (f, fifo_size, data_buf); + SFIFO_TEST (rv == fifo_size, "should dequeue all data"); + last_start_byte += 4096; /* size of last segment */ - svm_fifo_add_chunk (f, c); + rv = compare_data (data_buf, test_data, 0, vec_len (test_data), + (u32 *) & i); - SFIFO_TEST (f->end_chunk != c, "tail chunk should not be updated"); - SFIFO_TEST (f->size == fifo_size + 100, "size expected %u is %u", - fifo_size + 100, f->size); - SFIFO_TEST (c->start_byte == fifo_size + 100, "start byte expected %u is " - " %u", fifo_size + 100, c->start_byte); + if (rv) + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); + SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); + SFIFO_TEST (f->head_chunk == 0, "head chunk should be 0"); + SFIFO_TEST (f->tail_chunk == 0, "tail chunk should be 0"); + SFIFO_TEST (f->ooo_deq == 0, "should have no ooo deq chunk"); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); /* - * Unwrap fifo + * Allocate one new chunk by enqueueing out of order all but first chunk + * */ - vec_validate (data_buf, 200); - svm_fifo_dequeue (f, 201, data_buf); - SFIFO_TEST (f->end_chunk == c, "tail chunk should be updated"); - SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u", - fifo_size + 200, f->size); - SFIFO_TEST (c->start_byte == fifo_size + 100, "start byte expected %u is " - "%u", fifo_size + 100, c->start_byte); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + enq_chunk = vec_len (test_data) / 10; + rv = enqueue_ooo (f, test_data, vec_len (test_data), 10); + SFIFO_TEST (!rv, "enqueue ooo should work"); - /* - * Add N chunks - */ - svm_fifo_init_pointers (f, f->nitems - 100, f->nitems + 100); - - prev = 0; - for (i = 0; i < 5; i++) - { - c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100); - c->length = 100; - c->start_byte = ~0; - c->next = prev; - prev = c; - } - - svm_fifo_add_chunk (f, c); - SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u", - fifo_size + 200, f->size); + SFIFO_TEST (svm_fifo_size (f) == fifo_size, "size expected %u is %u", + fifo_size, svm_fifo_size (f)); + SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "max deq should be %u", 0); + /* Fifo has 2 chunks because the we didn't allow the first chunk to be + * freed when all the data was dequeued. Could be optimized in the future */ + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have %u chunks has %u", 2, rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - prev = 0; - for (i = 0; i < 5; i++) - { - c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + 100); - c->length = 100; - c->start_byte = ~0; - c->next = prev; - prev = c; - } - - svm_fifo_add_chunk (f, c); - SFIFO_TEST (f->size == fifo_size + 200, "size expected %u is %u", - fifo_size + 200, f->size); - - old_tail = f->tail; - svm_fifo_dequeue (f, 101, data_buf); + SFIFO_TEST (f->head_chunk == 0, "should have no head chunk"); + /* When new fifo chunks are allocated, tail is initialized */ + SFIFO_TEST (f->tail_chunk != 0, "should have no tail chunk"); + SFIFO_TEST (f->ooo_enq != 0, "should have an ooo enq chunk"); - SFIFO_TEST (f->size == fifo_size + 200 + 10 * 100, "size expected %u is %u", - fifo_size + 200 + 10 * 100, f->size); - SFIFO_TEST (f->tail == old_tail, "new tail expected %u is %u", old_tail, - f->tail); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + c = f->end_chunk; + SFIFO_TEST (c->start_byte == last_start_byte, + "end chunk should start at %u", last_start_byte); + SFIFO_TEST (c->length == 8192, "end chunk length should be %u", 8192); + SFIFO_TEST (f->ooo_enq == c, "ooo enq chunk should be end chunk"); /* - * Enqueue/dequeue tests + * Enqueue the first chunk */ + rv = svm_fifo_enqueue (f, enq_chunk, test_data); + SFIFO_TEST (rv == fifo_size, "enq should succeed %u", rv); + rv = svm_fifo_max_dequeue (f); + SFIFO_TEST (rv == fifo_size, "max deq should be %u is %u", fifo_size, rv); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have %u chunks has %u", 2, rv); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - test_n_bytes = f->nitems; - vec_validate (test_data, test_n_bytes - 1); - vec_validate (data_buf, vec_len (test_data)); - n_deqs = n_enqs = 6; - deq_bytes = enq_bytes = vec_len (test_data) / n_deqs; - - for (i = 0; i < vec_len (test_data); i++) - test_data[i] = i; + SFIFO_TEST (f->head_chunk == 0, "should have no head chunk"); + /* Fifo is full so tail and ooo_enq should be 0 */ + SFIFO_TEST (f->tail_chunk == 0, "should have no tail chunk"); + SFIFO_TEST (f->ooo_enq == 0, "should have no ooo enq chunk"); /* - * Enqueue/deq boundary conditions + * Peek and validate data */ - svm_fifo_init_pointers (f, 201, 201); - SFIFO_TEST (f->tail_chunk->start_byte == 201, "start byte expected %u is " - "%u", 201, f->tail_chunk->start_byte); - svm_fifo_enqueue (f, 200, test_data); - SFIFO_TEST (f->tail_chunk->start_byte == 401, "start byte expected %u is " - "%u", 401, f->tail_chunk->start_byte); + memset (data_buf, 0, vec_len (data_buf)); + + rv = dequeue_ooo_inc (f, data_buf, fifo_size, 10); + SFIFO_TEST (!rv, "ooo deq should work %d", rv); - svm_fifo_dequeue (f, 200, data_buf); - SFIFO_TEST (f->head_chunk->start_byte == 401, "start byte expected %u is " - "%u", 401, f->head_chunk->start_byte); + rv = compare_data (data_buf, test_data, 0, vec_len (test_data), + (u32 *) & i); + if (rv) + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); + SFIFO_TEST ((rv == 0), "peeked compared to original returned %d", rv); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* Peeked all the data in a full fifo so ooo_deq ends up 0 */ + SFIFO_TEST (f->ooo_deq == 0, "should have no ooo deq chunk"); /* - * Simple enqueue/deq and data validation (1) + * Peek in reverse order and validate data + * + * RB tree should be exercised */ - svm_fifo_init_pointers (f, f->nitems / 2, f->nitems / 2); - for (i = 0; i < test_n_bytes; i++) + + memset (data_buf, 0, vec_len (data_buf)); + for (i = 10; i >= 0; i--) { - rv = svm_fifo_enqueue (f, sizeof (u8), &test_data[i]); - if (rv < 0) - { - clib_warning ("enqueue returned %d", rv); - goto cleanup; - } + offset = i * enq_chunk; + deq_now = clib_min (enq_chunk, vec_len (test_data) - offset); + rv = svm_fifo_peek (f, offset, deq_now, data_buf + offset); + if (rv != deq_now) + SFIFO_TEST (0, "failed to peek"); } - SFIFO_TEST (svm_fifo_max_dequeue (f) == test_n_bytes, "max deq expected %u " - "is %u", test_n_bytes, svm_fifo_max_dequeue (f)); - - for (i = 0; i < test_n_bytes; i++) - svm_fifo_dequeue (f, 1, &data_buf[i]); - rv = compare_data (data_buf, test_data, 0, vec_len (test_data), - (u32 *) & j); + (u32 *) & i); + if (rv) - vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j], - test_data[j]); - SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); + SFIFO_TEST ((rv == 0), "peeked compared to original returned %d", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* Last chunk peeked is the first, so ooo_deq should be non zero */ + SFIFO_TEST (f->ooo_deq != 0, "should have ooo deq chunk"); /* - * Simple enqueue/deq and data validation (2) + * Dequeue drop all bytes */ - for (i = 0; i <= n_enqs; i++) - { - rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes); - if (rv < 0) - { - clib_warning ("enqueue returned %d", rv); - goto cleanup; - } - } + rv = svm_fifo_dequeue_drop (f, fifo_size); + SFIFO_TEST ((rv == fifo_size), "all bytes should be dropped %u", rv); + last_start_byte += 8192; - SFIFO_TEST (svm_fifo_max_dequeue (f) == test_n_bytes, "max deq expected %u " - "is %u", test_n_bytes, svm_fifo_max_dequeue (f)); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + SFIFO_TEST (f->head_chunk == 0, "should have no head chunk"); + SFIFO_TEST (f->tail_chunk == 0, "should have no tail chunk"); - for (i = 0; i <= n_deqs; i++) - svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes); + /* We don't remove the last chunk even when the fifo goes empty */ + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 1, "should have %u chunks has %u", 1, rv); - rv = compare_data (data_buf, test_data, 0, vec_len (test_data), - (u32 *) & j); - if (rv) - vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j], - test_data[j]); - SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* + * Increase size such that it can't be the sum of multiple chunk lengths + * + * A chunk of 16kB should be allocated + */ + fifo_size += 2 * fifo_inc - 100; + svm_fifo_set_size (f, fifo_size); + validate_test_and_buf_vecs (&test_data, &data_buf, fifo_size + fifo_inc); + enq_chunk = vec_len (test_data) / 10; + memset (data_buf, 0, vec_len (data_buf)); /* - * Simple enqueue and drop + * Enqueue data ooo */ - for (i = 0; i <= n_enqs; i++) - { - rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes); - if (rv < 0) - SFIFO_TEST (0, "failed to enqueue"); - } + rv = enqueue_ooo (f, test_data, fifo_size, 10); + SFIFO_TEST (!rv, "enqueue ooo should work"); + + SFIFO_TEST (svm_fifo_size (f) == fifo_size, "size expected %u is %u", + fifo_size, svm_fifo_size (f)); + SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "max deq should be %u", 0); + /* Fifo has 2 chunks because the we didn't allow the first chunk to be + * freed when all the data was dequeued. Could be optimized in the future */ + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have %u chunks has %u", 2, rv); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + + SFIFO_TEST (f->head_chunk == 0, "should have no head chunk"); + /* When new fifo chunks are allocated, tail is initialized */ + SFIFO_TEST (f->tail_chunk != 0, "should have no tail chunk"); + SFIFO_TEST (f->ooo_enq != 0, "should have an ooo enq chunk"); - rv = svm_fifo_dequeue_drop (f, test_n_bytes / 2); - SFIFO_TEST (rv == test_n_bytes / 2, "drop should be equal"); - SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid"); - rv = svm_fifo_dequeue_drop (f, test_n_bytes / 2); - SFIFO_TEST (rv == test_n_bytes / 2, "drop should be equal"); - SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid"); - SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "should be empty"); + c = f->end_chunk; + SFIFO_TEST (c->start_byte == last_start_byte, + "end chunk should start at %u", last_start_byte); + SFIFO_TEST (c->length == 16384, "end chunk length should be %u", 16384); + SFIFO_TEST (f->ooo_enq == c, "ooo enq chunk should be end chunk"); /* - * Simple enqueue and drop all + * Enqueue the first chunk */ + rv = svm_fifo_enqueue (f, enq_chunk, test_data); + SFIFO_TEST (rv == fifo_size, "enq should succeed %u", rv); + rv = svm_fifo_max_dequeue (f); + SFIFO_TEST (rv == fifo_size, "max deq should be %u is %u", fifo_size, rv); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have %u chunks has %u", 2, rv); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - /* Enqueue just enough data to make sure fifo is not full */ - for (i = 0; i <= n_enqs / 2; i++) - { - rv = svm_fifo_enqueue (f, enq_bytes, test_data + i * enq_bytes); - if (rv < 0) - SFIFO_TEST (0, "failed to enqueue"); - } - - /* check drop all as well */ - svm_fifo_dequeue_drop_all (f); - SFIFO_TEST (svm_fifo_is_sane (f), "head chunk should be valid"); - SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "should be empty"); + /* + * Dequeue just a part of data + */ + rv = svm_fifo_dequeue (f, fifo_inc, data_buf); + SFIFO_TEST (rv == fifo_inc, "should dequeue all data"); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 1, "should have %u chunks has %u", 1, rv); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); /* - * OOO enqueues/dequeues and data validation (1) + * Enqueue ooo as much data as it was dequeued */ - for (i = test_n_bytes - 1; i > 0; i--) - { - rv = svm_fifo_enqueue_with_offset (f, i, sizeof (u8), &test_data[i]); - if (verbose) - vlib_cli_output (vm, "add [%d] [%d, %d]", i, i, i + sizeof (u8)); - if (rv) - { - clib_warning ("enqueue returned %d", rv); - goto cleanup; - } - } + rv = enqueue_ooo (f, test_data + fifo_size, fifo_inc, 2); + SFIFO_TEST (!rv, "ooo enqueue should work %d", rv); + + rv = svm_fifo_enqueue (f, fifo_inc / 2, test_data + fifo_size); + SFIFO_TEST (rv == fifo_inc, "enqueue should work %d", rv); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have %u chunks has %u", 2, rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - SFIFO_TEST (svm_fifo_max_dequeue (f) == 0, "max deq expected %u is %u", - 0, svm_fifo_max_dequeue (f)); - svm_fifo_enqueue (f, sizeof (u8), &test_data[0]); + last_start_byte += 16384; + c = f->end_chunk; + SFIFO_TEST (c->start_byte == last_start_byte, + "end chunk should start at %u", last_start_byte); + SFIFO_TEST (c->length == 4096, "end chunk length should be %u", 4096); - memset (data_buf, 0, vec_len (data_buf)); - offset = 0; - for (i = 0; i <= n_deqs; i++) - { - rv = svm_fifo_peek (f, offset, deq_bytes, data_buf + i * deq_bytes); - if (rv < 0 || (rv != deq_bytes && i != n_deqs)) - SFIFO_TEST (0, "unexpected peek %d", rv); - offset += rv; - } - svm_fifo_dequeue_drop (f, offset); + /* + * Dequeue all + */ + rv = svm_fifo_dequeue (f, fifo_size, data_buf + fifo_inc); + SFIFO_TEST (rv == fifo_size, "should dequeue all data"); rv = compare_data (data_buf, test_data, 0, vec_len (test_data), - (u32 *) & j); + (u32 *) & i); if (rv) - vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j], - test_data[j]); + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* fifo does not end on chunk boundary because of the - 100 */ + SFIFO_TEST (f->head_chunk != 0, "should have head chunk"); + SFIFO_TEST (f->tail_chunk != 0, "should have tail chunk"); /* - * OOO enqueues/dequeues and data validation (2) + * Enqueue and dequeue byte-by-byte ooo */ - for (i = n_enqs; i > 0; i--) - { - u32 enq_now = clib_min (enq_bytes, vec_len (test_data) - i * enq_bytes); - rv = svm_fifo_enqueue_with_offset (f, i * enq_bytes, enq_now, - test_data + i * enq_bytes); - if (verbose) - vlib_cli_output (vm, "add [%d, %d]", i * enq_bytes, - i * enq_bytes + enq_now); - if (rv) - { - clib_warning ("enqueue returned %d", rv); - goto cleanup; - } - } - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + memset (data_buf, 0, vec_len (data_buf)); - svm_fifo_enqueue (f, enq_bytes, &test_data[0]); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + rv = enqueue_ooo (f, test_data, fifo_size, fifo_size); + SFIFO_TEST (!rv, "ooo enqueue should work %d", rv); - memset (data_buf, 0, vec_len (data_buf)); - for (i = 0; i <= n_deqs; i++) - svm_fifo_dequeue (f, deq_bytes, data_buf + i * deq_bytes); + rv = svm_fifo_enqueue (f, 1, test_data); + SFIFO_TEST (rv == fifo_size, "enqueue should work %d", rv); - rv = compare_data (data_buf, test_data, 0, vec_len (test_data), - (u32 *) & j); + rv = dequeue_ooo (f, data_buf, fifo_size, fifo_size); + SFIFO_TEST (!rv, "ooo deq should work %d", rv); + + rv = compare_data (data_buf, test_data, 0, fifo_size, (u32 *) & i); if (rv) - vlib_cli_output (vm, "[%d] dequeued %u expected %u", j, data_buf[j], - test_data[j]); + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + last_start_byte += 4096; + c = f->end_chunk; + SFIFO_TEST (c->start_byte == last_start_byte, + "end chunk should start at %u", last_start_byte); + SFIFO_TEST (c->length == 16384, "end chunk length should be %u", 16384); + + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 2, "should have %u chunks has %u", 2, rv); + /* - * Cleanup + * Dequeue drop all bytes */ + rv = svm_fifo_dequeue_drop (f, fifo_size); + SFIFO_TEST ((rv == fifo_size), "all bytes should be dropped %u", rv); -cleanup: + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + SFIFO_TEST (f->head_chunk != 0, "should have head chunk"); + SFIFO_TEST (f->tail_chunk != 0, "should have tail chunk"); - c = f->start_chunk->next; - while (c && c != f->start_chunk) - { - next = c->next; - clib_mem_free (c); - c = next; - } + /* We don't remove the last chunk even when the fifo goes empty */ + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 1, "should have %u chunks has %u", 1, rv); + SFIFO_TEST (f->ooo_enq == 0, "should have no ooo enq chunk"); + SFIFO_TEST (f->ooo_deq == 0, "should have no ooo deq chunk"); - svm_fifo_free (f); - vec_free (test_data); - vec_free (data_buf); - return 0; -} + /* + * Grow fifo to 4MB and force only 4kB chunk allocations + */ + fifo_size = 4 << 20; + svm_fifo_set_size (f, fifo_inc); + validate_test_and_buf_vecs (&test_data, &data_buf, fifo_size); + enq_chunk = 1500; + memset (data_buf, 0, vec_len (data_buf)); -static int -chunk_list_len (svm_fifo_chunk_t * c) -{ - svm_fifo_chunk_t *it; - int count = 0; + rv = enqueue_packets_inc (f, fifo_size, enq_chunk, test_data); + SFIFO_TEST (!rv, "incremental packet enqueue should work"); - if (!c) - return 0; + SFIFO_TEST (svm_fifo_max_dequeue (f) == fifo_size, "max deq should be %u", + fifo_size); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - count = 1; - it = c->next; - while (it && it != c) - { - it = it->next; - count++; - } - return count; -} + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == (fifo_size / 4096) + 1, "should have %u chunks has %u", + (fifo_size / 4096) + 1, rv); -static void -chunk_list_free (svm_fifo_chunk_t * c, svm_fifo_chunk_t * stop) -{ - svm_fifo_chunk_t *it, *next; - it = c; - while (it && it != stop) - { - next = it->next; - clib_mem_free (it); - it = next; - } -} + /* + * Dequeue all + */ + rv = svm_fifo_dequeue (f, fifo_size, data_buf); + SFIFO_TEST (rv == fifo_size, "should dequeue all data"); -static void -chunk_list_splice (svm_fifo_chunk_t * a, svm_fifo_chunk_t * b) -{ - svm_fifo_chunk_t *it; + rv = compare_data (data_buf, test_data, 0, vec_len (test_data), + (u32 *) & i); + if (rv) + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + SFIFO_TEST ((rv == 0), "dequeued compared to original returned %d", rv); + SFIFO_TEST (f->ooo_deq == 0, "should have no ooo deq chunk"); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 1, "should have %u chunks has %u", 1, rv); - it = a; - while (it->next) - it = it->next; - it->next = b; + /* + * Cleanup + */ + + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); + vec_free (test_data); + vec_free (data_buf); + return 0; } static int sfifo_test_fifo_shrink (vlib_main_t * vm, unformat_input_t * input) { - int __clib_unused verbose = 0, fifo_size = 101, chunk_size = 100; - int i, rv, test_n_bytes, diff, deq_bytes; - svm_fifo_chunk_t *c, *prev, *collected; + int __clib_unused verbose = 0, fifo_size = 4096, deq_chunk; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; u8 *test_data = 0, *data_buf = 0; + fifo_segment_t *fs; svm_fifo_t *f; + u32 enq_chunk; + int i, rv; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { @@ -1582,404 +1760,214 @@ sfifo_test_fifo_shrink (vlib_main_t * vm, unformat_input_t * input) } /* - * Init fifo with multiple chunks + * Init fifo and enqueue data such that multiple 4096 chunks are allocated */ - f = fifo_prepare (fifo_size); - svm_fifo_init_pointers (f, 0, 0); - - prev = 0; - for (i = 0; i < 11; i++) - { - c = clib_mem_alloc (sizeof (svm_fifo_chunk_t) + chunk_size); - c->length = 100; - c->start_byte = ~0; - c->next = prev; - prev = c; - } + fs = fifo_segment_prepare (fsm, "fifo-shrink", 0); + f = fifo_prepare (fs, fifo_size); - svm_fifo_add_chunk (f, c); - SFIFO_TEST (f->size == 12 * chunk_size + 1, "size expected %u is %u", - 12 * chunk_size + 1, f->size); - - /* - * No fifo wrap and no chunk used (one chunk) - */ - rv = svm_fifo_reduce_size (f, chunk_size, 0); - SFIFO_TEST (rv == chunk_size, "len expected %u is %u", chunk_size, rv); - SFIFO_TEST (f->size == 12 * chunk_size + 1, "size expected %u is %u", - 12 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + fifo_size = 4 << 20; + svm_fifo_set_size (f, 4096); + validate_test_and_buf_vecs (&test_data, &data_buf, fifo_size); + enq_chunk = 1500; + rv = enqueue_packets_inc (f, fifo_size, enq_chunk, test_data); + SFIFO_TEST (!rv, "incremental packet enqueue should work"); - /* Check enqueue space to force size reduction */ - (void) svm_fifo_max_enqueue (f); - - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should" - " be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be" - " set"); + rv = svm_fifo_max_enqueue (f); + SFIFO_TEST (rv == 0, "enqueue space %u", rv); + SFIFO_TEST (svm_fifo_max_dequeue (f) == fifo_size, "max deq should be %u", + fifo_size); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - collected = c = svm_fifo_collect_chunks (f); - rv = chunk_list_len (c); - SFIFO_TEST (rv == 1, "expected %u chunks got %u", 1, rv); - rv = chunk_list_len (f->start_chunk); - SFIFO_TEST (rv == 11, "expected %u chunks got %u", 11, rv); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == (fifo_size / 4096), "should have %u chunks has %u", + (fifo_size / 4096), rv); /* - * Fifo wrap and multiple chunks used + * Dequeue enough to collect one chunk */ + deq_chunk = 4096; + rv = svm_fifo_dequeue (f, deq_chunk, data_buf); + SFIFO_TEST (rv == deq_chunk, "should dequeue all data"); - /* Init test data and fifo */ - test_n_bytes = f->nitems; - vec_validate (test_data, test_n_bytes - 1); - vec_validate (data_buf, vec_len (test_data)); - - for (i = 0; i < vec_len (test_data); i++) - test_data[i] = i; - - svm_fifo_init_pointers (f, f->size / 2, f->size / 2); - for (i = 0; i < test_n_bytes; i++) - { - rv = svm_fifo_enqueue (f, sizeof (u8), &test_data[i]); - if (rv < 0) - SFIFO_TEST (0, "enqueue returned"); - } - - /* Try to reduce fifo size with fifo full */ - rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 0); - SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size, - rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == (fifo_size / 4096) - 1, "should have %u chunks has %u", + (fifo_size / 4096) - 1, rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - /* Check enqueue space to try size reduction. Should not work */ rv = svm_fifo_max_enqueue (f); + SFIFO_TEST (rv == deq_chunk, "enqueue space %u", rv); - SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - /* Dequeue byte-by-byte up to last byte on last chunk */ - deq_bytes = f->size - f->size / 2 - 1; - for (i = 0; i < deq_bytes; i++) - { - (void) svm_fifo_max_enqueue (f); - rv = svm_fifo_dequeue (f, 1, &data_buf[i]); - if (rv < 0) - SFIFO_TEST (0, "dequeue returned"); - } - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* + * Dequeue ooo byte-by-byte remaining data + */ + rv = dequeue_ooo (f, data_buf + deq_chunk, fifo_size - deq_chunk, + fifo_size - deq_chunk); + SFIFO_TEST (!rv, "ooo deq should work %d", rv); - rv = svm_fifo_max_enqueue (f); + rv = compare_data (data_buf, test_data, 0, fifo_size, (u32 *) & i); + if (rv) + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); - /* We've dequeued more than 3*chunk_size so nitems should be updated */ - SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u", - 8 * chunk_size, f->nitems); - /* Free space should be what was dequeued - 3 * chunk_size, which was - * consumed by shrinking the fifo */ - diff = deq_bytes - 3 * chunk_size; - SFIFO_TEST (rv == diff, "free space expected %u is %u", diff, rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == (fifo_size / 4096) - 1, "should have %u chunks has %u", + (fifo_size / 4096) - 1, rv); - /* Dequeue one more such that head goes beyond last chunk */ - rv = svm_fifo_dequeue (f, 1, &data_buf[deq_bytes]); - if (rv < 0) - SFIFO_TEST (0, "dequeue returned"); - - rv = svm_fifo_max_enqueue (f); - SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u", - 8 * chunk_size, f->nitems); - SFIFO_TEST (rv == diff + 1, "free space expected %u is %u", diff + 1, rv); - SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u", - 8 * chunk_size + 1, f->size); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be" - " set"); - SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should" - " be set"); + /* + * Drop all data + */ + rv = svm_fifo_dequeue_drop (f, fifo_size - deq_chunk); + SFIFO_TEST (rv == fifo_size - deq_chunk, "should drop all data"); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - /* Dequeue the rest of the data */ - deq_bytes += 1; - for (i = 0; i < test_n_bytes - deq_bytes; i++) - { - rv = svm_fifo_dequeue (f, 1, &data_buf[i + deq_bytes]); - if (rv < 0) - SFIFO_TEST (0, "dequeue returned"); - } - + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == 1, "should have %u chunks has %u", 1, rv); rv = svm_fifo_max_enqueue (f); + SFIFO_TEST (rv == fifo_size, "enqueue space %u", rv); - SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u", - 8 * chunk_size + 1, f->size); - SFIFO_TEST (rv == 8 * chunk_size, "free space expected %u is %u", - 8 * chunk_size, rv); - - rv = compare_data (data_buf, test_data, 0, vec_len (test_data), - (u32 *) & i); - if (rv) - SFIFO_TEST (0, "[%d] dequeued %u expected %u", i, data_buf[i], - test_data[i]); - - c = svm_fifo_collect_chunks (f); - rv = chunk_list_len (c); - SFIFO_TEST (rv == 3, "expected %u chunks got %u", 3, rv); - rv = chunk_list_len (f->start_chunk); - SFIFO_TEST (rv == 8, "expected %u chunks got %u", 8, rv); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); /* - * OOO segment on chunk that should be removed + * Reset size and enqueue ooo all data */ - - svm_fifo_add_chunk (f, c); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - - memset (data_buf, 0, vec_len (data_buf)); - svm_fifo_init_pointers (f, f->size / 2, f->size / 2); - svm_fifo_enqueue (f, 200, test_data); - svm_fifo_enqueue_with_offset (f, 50, vec_len (test_data) - 250, - &test_data[250]); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - /* Free space */ - rv = svm_fifo_max_enqueue (f); - SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u", - vec_len (test_data) - 200, rv); + svm_fifo_set_size (f, 4096); + enq_chunk = deq_chunk = 1500; + rv = enqueue_ooo_packets (f, vec_len (test_data), 1500, test_data); + SFIFO_TEST (!rv, "enqueue ooo should work"); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - /* Ask to reduce size */ - rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 0); - SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size, - rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - /* Try to force size reduction but it should fail */ - rv = svm_fifo_max_enqueue (f); + /* 1 additional chunk left from previous test */ + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == (fifo_size / 4096) + 1, "should have %u chunks has %u", + (fifo_size / 4096) + 1, rv); - SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u", - vec_len (test_data) - 200, rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); + /* + * Add missing first chunk + */ + rv = svm_fifo_enqueue (f, enq_chunk, test_data); + SFIFO_TEST (rv == fifo_size, "enq should succeed %u", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + rv = svm_fifo_max_dequeue (f); + SFIFO_TEST (rv == fifo_size, "max deq should be %u is %u", fifo_size, rv); + rv = svm_fifo_n_chunks (f); + SFIFO_TEST (rv == (fifo_size / 4096) + 1, "should have %u chunks has %u", + (fifo_size / 4096) + 1, rv); - /* Dequeue the in order data. This should shrink nitems */ - rv = svm_fifo_dequeue (f, 200, data_buf); - if (rv < 0) - SFIFO_TEST (0, "dequeue returned"); + /* + * Dequeue as packets + */ + memset (data_buf, 0, vec_len (data_buf)); + rv = dequeue_packets (f, fifo_size, deq_chunk, data_buf); + SFIFO_TEST (!rv, "deq pkts should work %d", rv); - rv = svm_fifo_max_enqueue (f); - SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u", - vec_len (test_data) - 200, rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->nitems == 11 * chunk_size - 200, "nitems expected %u is %u", - 11 * chunk_size - 200, f->nitems); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + rv = compare_data (data_buf, test_data, 0, fifo_size, (u32 *) & i); + if (rv) + vlib_cli_output (vm, "[%d] dequeued %u expected %u", i, data_buf[i], + test_data[i]); - /* Enqueue the missing 50 bytes. Fifo will become full */ - rv = svm_fifo_enqueue (f, 50, &test_data[200]); - SFIFO_TEST (rv == vec_len (test_data) - 200, "free space expected %u is %u", - vec_len (test_data) - 200, rv); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* + * Enqueue and dequeue set of packets + */ + svm_fifo_set_size (f, 4096); + for (i = 0; i < 1000; i++) + { + rv = svm_fifo_enqueue (f, enq_chunk, test_data); + if (rv != enq_chunk) + SFIFO_TEST (0, "enq fail"); + rv = svm_fifo_dequeue (f, deq_chunk, data_buf); + if (rv != deq_chunk) + SFIFO_TEST (0, "deq fail"); + } - rv = svm_fifo_max_enqueue (f); + /* + * Cleanup + */ - SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); + vec_free (test_data); + vec_free (data_buf); + return 0; +} - /* Dequeue a chunk and check nitems shrink but fifo still full */ - svm_fifo_dequeue (f, 100, &data_buf[200]); +static int +sfifo_test_fifo_indirect (vlib_main_t * vm, unformat_input_t * input) +{ + int __clib_unused verbose = 0, fifo_size = 4096, deq_chunk; + fifo_segment_main_t _fsm = { 0 }, *fsm = &_fsm; + u8 *test_data = 0, *data_buf = 0; + svm_fifo_chunk_t *c; + fifo_segment_t *fs; + svm_fifo_t *f; + int rv; - rv = svm_fifo_max_enqueue (f); + while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) + { + if (unformat (input, "verbose")) + verbose = 1; + else + { + vlib_cli_output (vm, "parse error: '%U'", format_unformat_error, + input); + return -1; + } + } - SFIFO_TEST (rv == 0, "free space expected %u is %u", 0, rv); - SFIFO_TEST (f->size == 11 * chunk_size + 1, "size expected %u is %u", - 11 * chunk_size + 1, f->size); - SFIFO_TEST (f->nitems == 11 * chunk_size - 300, "nitems expected %u is %u", - 11 * chunk_size - 300, f->nitems); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + /* + * Init fifo and enqueue data such that multiple 4096 chunks are allocated + */ + fs = fifo_segment_prepare (fsm, "fifo-indirect", 0); + f = fifo_prepare (fs, fifo_size); - /* Dequeue enough to unwrap the fifo */ - deq_bytes = f->size - f->size / 2 - 300; - svm_fifo_dequeue (f, deq_bytes, &data_buf[300]); - rv = svm_fifo_max_enqueue (f); + fifo_size = 4 << 20; + svm_fifo_set_size (f, fifo_size); + validate_test_and_buf_vecs (&test_data, &data_buf, fifo_size); - /* Overall we've dequeued deq_bytes + 300, but fifo size shrunk 300 */ - SFIFO_TEST (rv == 300 + deq_bytes - 300, "free space expected %u is %u", - 300 + deq_bytes - 300, rv); - SFIFO_TEST (f->size == 8 * chunk_size + 1, "size expected %u is %u", - 8 * chunk_size + 1, f->size); - SFIFO_TEST (f->nitems == 8 * chunk_size, "nitems expected %u is %u", - 8 * chunk_size, f->nitems); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be" - " set"); - SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should" - " be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + c = f->start_chunk; + SFIFO_TEST (c->next == 0, "no next"); - /* Dequeue the rest */ - svm_fifo_dequeue (f, test_n_bytes / 2, &data_buf[300 + deq_bytes]); - rv = compare_data (data_buf, test_data, 0, vec_len (test_data), - (u32 *) & i); - if (rv) - SFIFO_TEST (0, "[%d] dequeued %u expected %u", i, data_buf[i], - test_data[i]); - - c = svm_fifo_collect_chunks (f); - rv = chunk_list_len (c); - SFIFO_TEST (rv == 3, "expected %u chunks got %u", 3, rv); - rv = chunk_list_len (f->start_chunk); - SFIFO_TEST (rv == 8, "expected %u chunks got %u", 8, rv); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + svm_fifo_fill_chunk_list (f); + SFIFO_TEST (c->next != 0, "new chunk should've been allocated"); + SFIFO_TEST (c->next->length == 4 << 20, "new chunk should be 4MB"); - chunk_list_splice (collected, c); + rv = svm_fifo_max_write_chunk (f); + SFIFO_TEST (rv == 4096, "max write chunk %u", rv); /* - * Remove all chunks possible (1) - * - * Tail and head are in first chunk that is not removed - */ - svm_fifo_init_pointers (f, 600, 600); - rv = svm_fifo_reduce_size (f, 8 * chunk_size, 1); - SFIFO_TEST (rv == 7 * chunk_size, "actual len expected %u is %u", - 7 * chunk_size, rv); - SFIFO_TEST (f->size == 6 * chunk_size + 1, "size expected %u is %u", - 6 * chunk_size + 1, f->size); - SFIFO_TEST (f->nitems == 1 * chunk_size, "nitems expected %u is %u", - 1 * chunk_size, f->nitems); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - rv = svm_fifo_max_enqueue (f); - SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size, - rv); + * Enqueue enough to fill first chunk + */ + svm_fifo_enqueue_nocopy (f, 4096); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - /* Force head/tail to move to first chunk */ - svm_fifo_enqueue (f, 1, test_data); - svm_fifo_dequeue (f, 1, data_buf); - rv = svm_fifo_max_enqueue (f); - - SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size, - rv); - SFIFO_TEST (f->size == chunk_size + 1, "size expected %u is %u", - chunk_size + 1, f->size); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be" - " set"); - SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should" - " be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + c = svm_fifo_tail_chunk (f); + SFIFO_TEST (c == f->end_chunk, "tail is end chunk"); - c = svm_fifo_collect_chunks (f); - rv = chunk_list_len (c); - SFIFO_TEST (rv == 7, "expected %u chunks got %u", 7, rv); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_MULTI_CHUNK), "multi-chunk flag should" - " not be set"); + /* Initialize head chunk */ + rv = svm_fifo_max_read_chunk (f); + SFIFO_TEST (rv == 4096, "max read chunk %u", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - /* re-add chunks for next test */ - svm_fifo_add_chunk (f, c); - /* - * Remove all chunks possible (2) - * - * Tail and head are in the first chunk that should eventually be removed - */ - svm_fifo_init_pointers (f, 601, 601); - rv = svm_fifo_reduce_size (f, 8 * chunk_size, 1); - SFIFO_TEST (rv == 7 * chunk_size, "actual len expected %u is %u", - 7 * chunk_size, rv); - SFIFO_TEST (f->size == 7 * chunk_size + 1, "size expected %u is %u", - 7 * chunk_size + 1, f->size); - SFIFO_TEST (f->nitems == 1 * chunk_size, "nitems expected %u is %u", - 1 * chunk_size, f->nitems); - SFIFO_TEST (f->flags & SVM_FIFO_F_SHRINK, "shrink flag should be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - rv = svm_fifo_max_enqueue (f); - SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size, - rv); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); - - /* Force head/tail to move to first chunk */ - svm_fifo_enqueue (f, chunk_size, test_data); - svm_fifo_dequeue (f, chunk_size, data_buf); - rv = svm_fifo_max_enqueue (f); + * Move head over last segment + */ + rv = svm_fifo_dequeue (f, 4096, data_buf); + SFIFO_TEST (rv == 4096, "dequeue should work"); - SFIFO_TEST (rv == chunk_size, "free space expected %u is %u", chunk_size, - rv); - SFIFO_TEST (f->size == chunk_size + 1, "size expected %u is %u", - chunk_size + 1, f->size); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_SHRINK), "shrink flag should not be" - " set"); - SFIFO_TEST (f->flags & SVM_FIFO_F_COLLECT_CHUNKS, "collect flag should" - " be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + c = svm_fifo_head_chunk (f); + SFIFO_TEST (c == f->end_chunk, "head chunk should be last"); - c = svm_fifo_collect_chunks (f); - rv = chunk_list_len (c); - SFIFO_TEST (rv == 7, "expected %u chunks got %u", 7, rv); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_COLLECT_CHUNKS), "collect flag should" - " not be set"); - SFIFO_TEST (!(f->flags & SVM_FIFO_F_MULTI_CHUNK), "multi-chunk flag should" - " not be set"); - SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + rv = svm_fifo_max_read_chunk (f); + SFIFO_TEST (rv == 0, "max read chunk %u", rv); - chunk_list_splice (collected, c); + rv = svm_fifo_max_write_chunk (f); + SFIFO_TEST (rv == 4 << 20, "max write chunk %u", rv); /* * Cleanup */ - chunk_list_free (f->start_chunk->next, f->start_chunk); - chunk_list_free (collected, 0); - svm_fifo_free (f); + ft_fifo_free (fs, f); + ft_fifo_segment_free (fsm, fs); vec_free (test_data); vec_free (data_buf); @@ -2023,13 +2011,6 @@ sfifo_test_fifo_replay (vlib_main_t * vm, unformat_input_t * input) static fifo_segment_main_t segment_main; -static svm_fifo_t * -fifo_segment_alloc_fifo (fifo_segment_t * fs, u32 data_bytes, - fifo_segment_ftype_t ftype) -{ - return fifo_segment_alloc_fifo_w_slice (fs, 0, data_bytes, ftype); -} - static int sfifo_test_fifo_segment_hello_world (int verbose) { @@ -2084,6 +2065,7 @@ sfifo_test_fifo_segment_fifo_grow (int verbose) int rv, fifo_size = 4096, n_chunks, n_batch; fifo_segment_main_t *sm = &segment_main; fifo_segment_create_args_t _a, *a = &_a; + u8 *test_data = 0, *data_buf = 0; u32 n_free_chunk_bytes; fifo_segment_t *fs; svm_fifo_t *f; @@ -2101,7 +2083,7 @@ sfifo_test_fifo_segment_fifo_grow (int verbose) SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv); /* - * Alloc and grow fifo + * Alloc fifo */ fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]); f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO); @@ -2115,10 +2097,14 @@ sfifo_test_fifo_segment_fifo_grow (int verbose) SFIFO_TEST (rv == (n_batch - 1) * fifo_size, "free chunk bytes %u " "expected %u", rv, (n_batch - 1) * fifo_size); - /* Grow by preallocated fifo_size chunk */ - fifo_segment_grow_fifo (fs, f, fifo_size); - SFIFO_TEST (f->size == 2 * fifo_size, "fifo size should be %u is %u", - 2 * fifo_size, f->size); + /* + * Grow fifo by preallocated fifo_size chunk + */ + svm_fifo_set_size (f, 2 * fifo_size); + validate_test_and_buf_vecs (&test_data, &data_buf, 2 * fifo_size); + + rv = svm_fifo_enqueue (f, vec_len (test_data), test_data); + SFIFO_TEST (rv == vec_len (test_data), "enq should succeed %u", rv); SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); n_chunks = fifo_segment_num_free_chunks (fs, fifo_size); @@ -2133,9 +2119,13 @@ sfifo_test_fifo_segment_fifo_grow (int verbose) SFIFO_TEST (rv > 16 * fifo_size, "free bytes %u more than %u", rv, 16 * fifo_size); - fifo_segment_grow_fifo (fs, f, 16 * fifo_size); - SFIFO_TEST (f->size == 18 * fifo_size, "fifo size should be %u is %u", - 18 * fifo_size, f->size); + /* Force fifo growth */ + svm_fifo_set_size (f, svm_fifo_size (f) + 16 * fifo_size); + validate_test_and_buf_vecs (&test_data, &data_buf, svm_fifo_size (f)); + rv = svm_fifo_enqueue (f, vec_len (test_data), test_data); + + SFIFO_TEST (svm_fifo_size (f) == 18 * fifo_size, "fifo size should be %u " + "is %u", 18 * fifo_size, svm_fifo_size (f)); rv = fifo_segment_fl_chunk_bytes (fs); SFIFO_TEST (rv == (n_batch - 2) * fifo_size, "free chunk bytes %u " @@ -2164,12 +2154,21 @@ sfifo_test_fifo_segment_fifo_grow (int verbose) */ f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO); - fifo_segment_grow_fifo (fs, f, fifo_size); + /* Force chunk allocation */ + svm_fifo_set_size (f, svm_fifo_size (f) + fifo_size); + rv = svm_fifo_enqueue (f, svm_fifo_size (f), test_data); + + SFIFO_TEST (rv == svm_fifo_size (f), "enq should succeed %u", rv); + SFIFO_TEST (svm_fifo_is_sane (f), "fifo should be sane"); + n_chunks = fifo_segment_num_free_chunks (fs, fifo_size); SFIFO_TEST (n_chunks == n_batch - 2, "free 2^10B chunks should be %u is %u", n_batch - 2, n_chunks); - fifo_segment_grow_fifo (fs, f, 16 * fifo_size); + /* Grow and alloc 16 * fifo_size chunk */ + svm_fifo_set_size (f, svm_fifo_size (f) + 16 * fifo_size); + rv = svm_fifo_enqueue (f, svm_fifo_size (f), test_data); + n_chunks = fifo_segment_num_free_chunks (fs, 16 * fifo_size); SFIFO_TEST (n_chunks == 0, "free 2^14B chunks should be %u is %u", 0, n_chunks); @@ -2261,88 +2260,16 @@ sfifo_test_fifo_segment_fifo_grow (int verbose) * Allocate fifo and try to grow beyond available space */ f = fifo_segment_alloc_fifo (fs, fifo_size, FIFO_SEGMENT_RX_FIFO); - rv = fifo_segment_grow_fifo (fs, f, n_free_chunk_bytes); - - SFIFO_TEST (rv == -1, "grow should fail"); - - fifo_segment_free_fifo (fs, f); - - /* - * Cleanup - */ - fifo_segment_delete (sm, fs); - vec_free (a->new_segment_indices); - return 0; -} - -static int -sfifo_test_fifo_segment_fifo_shrink (int verbose) -{ - int i, rv, chunk_size = 4096, n_chunks, n_free; - fifo_segment_main_t *sm = &segment_main; - fifo_segment_create_args_t _a, *a = &_a; - fifo_segment_t *fs; - svm_fifo_t *f; - - clib_memset (a, 0, sizeof (*a)); - a->segment_name = "fifo-test1"; - a->segment_size = 256 << 10; - - rv = fifo_segment_create (sm, a); - SFIFO_TEST (!rv, "svm_fifo_segment_create returned %d", rv); - - /* - * Alloc and grow fifo - */ - fs = fifo_segment_get_segment (sm, a->new_segment_indices[0]); - f = fifo_segment_alloc_fifo (fs, chunk_size, FIFO_SEGMENT_RX_FIFO); - n_free = FIFO_SEGMENT_ALLOC_BATCH_SIZE - 1; - - SFIFO_TEST (f != 0, "svm_fifo_segment_alloc_fifo"); - - for (i = 0; i < 9; i++) - { - fifo_segment_grow_fifo (fs, f, chunk_size); - n_free -= 1; - if (f->size != (i + 2) * chunk_size) - SFIFO_TEST (0, "fifo size should be %u is %u", - (i + 2) * chunk_size, f->size); - } - - rv = svm_fifo_reduce_size (f, 3.5 * chunk_size, 1 /* is producer */ ); - SFIFO_TEST (rv == 3 * chunk_size, "len expected %u is %u", 3 * chunk_size, - rv); - - n_chunks = fifo_segment_num_free_chunks (fs, chunk_size); - SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free, - n_chunks); - - fifo_segment_collect_fifo_chunks (fs, f); + /* Try to force fifo growth */ + svm_fifo_set_size (f, svm_fifo_size (f) + n_free_chunk_bytes); + validate_test_and_buf_vecs (&test_data, &data_buf, svm_fifo_size (f)); + rv = svm_fifo_enqueue (f, svm_fifo_size (f), test_data); - n_free += 3; - n_chunks = fifo_segment_num_free_chunks (fs, chunk_size); - SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free, - n_chunks); - - rv = svm_fifo_reduce_size (f, 7 * chunk_size - 1, 1 /* is producer */ ); - SFIFO_TEST (rv == 6 * chunk_size, "len expected %u is %u", 6 * chunk_size, - rv); - - fifo_segment_collect_fifo_chunks (fs, f); + SFIFO_TEST (rv != svm_fifo_size (f), "grow should fail size %u wrote %d", + svm_fifo_size (f), rv); - n_free += 6; - n_chunks = fifo_segment_num_free_chunks (fs, chunk_size); - SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free, - n_chunks); - /* - * Free - */ fifo_segment_free_fifo (fs, f); - n_free += 1; - n_chunks = fifo_segment_num_free_chunks (fs, ~0); - SFIFO_TEST (n_chunks == n_free, "free chunks should be %u is %u", n_free, - n_chunks); /* * Cleanup @@ -2666,11 +2593,6 @@ sfifo_test_fifo_segment (vlib_main_t * vm, unformat_input_t * input) if ((rv = sfifo_test_fifo_segment_fifo_grow (verbose))) return -1; } - else if (unformat (input, "shrink fifo")) - { - if ((rv = sfifo_test_fifo_segment_fifo_shrink (verbose))) - return -1; - } else if (unformat (input, "prealloc")) { if ((rv = sfifo_test_fifo_segment_prealloc (verbose))) @@ -2684,8 +2606,6 @@ sfifo_test_fifo_segment (vlib_main_t * vm, unformat_input_t * input) return -1; if ((rv = sfifo_test_fifo_segment_fifo_grow (verbose))) return -1; - if ((rv = sfifo_test_fifo_segment_fifo_shrink (verbose))) - return -1; if ((rv = sfifo_test_fifo_segment_prealloc (verbose))) return -1; /* Pretty slow so avoid running it always @@ -2735,6 +2655,8 @@ svm_fifo_test (vlib_main_t * vm, unformat_input_t * input, res = sfifo_test_fifo_grow (vm, input); else if (unformat (input, "shrink")) res = sfifo_test_fifo_shrink (vm, input); + else if (unformat (input, "indirect")) + res = sfifo_test_fifo_indirect (vm, input); else if (unformat (input, "segment")) res = sfifo_test_fifo_segment (vm, input); else if (unformat (input, "all")) @@ -2796,6 +2718,9 @@ svm_fifo_test (vlib_main_t * vm, unformat_input_t * input, if ((res = sfifo_test_fifo_shrink (vm, input))) goto done; + if ((res = sfifo_test_fifo_indirect (vm, input))) + goto done; + str = "all"; unformat_init_cstring (input, str); if ((res = sfifo_test_fifo_segment (vm, input))) |