Add more svm fifo unit tests 48/6248/2
authorFlorin Coras <fcoras@cisco.com>
Wed, 19 Apr 2017 05:07:29 +0000 (22:07 -0700)
committerNeale Ranns <nranns@cisco.com>
Wed, 19 Apr 2017 09:05:28 +0000 (09:05 +0000)
Change-Id: Ifc07b3f90ac155c26c3a216e073b474b499ebd44
Signed-off-by: Florin Coras <fcoras@cisco.com>
src/svm/svm_fifo.c
src/vnet/tcp/tcp_test.c

index bd968ae..f428d3e 100644 (file)
@@ -38,13 +38,37 @@ format_ooo_list (u8 * s, va_list * args)
   while (ooo_segment_index != OOO_SEGMENT_INVALID_INDEX)
     {
       seg = pool_elt_at_index (f->ooo_segments, ooo_segment_index);
-      s = format (s, "\n  %U", format_ooo_segment, seg);
-
+      s = format (s, "  %U\n", format_ooo_segment, seg);
       ooo_segment_index = seg->next;
     }
   return s;
 }
 
+u8 *
+format_svm_fifo (u8 * s, va_list * args)
+{
+  svm_fifo_t *f = va_arg (*args, svm_fifo_t *);
+  int verbose = va_arg (*args, int);
+
+  s = format (s, "cursize %u nitems %u has_event %d\n",
+             f->cursize, f->nitems, f->has_event);
+  s = format (s, "head %d tail %d\n", f->head, f->tail);
+
+  if (verbose > 1)
+    s = format
+      (s, "server session %d thread %d client session %d thread %d\n",
+       f->server_session_index, f->server_thread_index,
+       f->client_session_index, f->client_thread_index);
+
+  if (verbose)
+    {
+      s = format (s, "ooo pool %d active elts\n",
+                 pool_elts (f->ooo_segments));
+      s = format (s, "%U", format_ooo_list, f);
+    }
+  return s;
+}
+
 /** create an svm fifo, in the current heap. Fails vs blow up the process */
 svm_fifo_t *
 svm_fifo_create (u32 data_size_in_bytes)
@@ -274,33 +298,41 @@ ooo_segment_try_collect (svm_fifo_t * f, u32 n_bytes_enqueued)
   u32 index, bytes = 0, diff;
   u32 cursize;
 
-  /* read cursize, which can only increase while we're working */
-  cursize = svm_fifo_max_dequeue (f);
+  /* current size has not yet been updated */
+  cursize = svm_fifo_max_dequeue (f) + n_bytes_enqueued;
 
   s = pool_elt_at_index (f->ooo_segments, f->ooos_list_head);
 
+  diff = (f->nitems + (i32) (f->tail - s->start)) % f->nitems;
+  if (diff > cursize)
+    return 0;
+
   /* If last tail update overlaps one/multiple ooo segments, remove them */
-  diff = (f->nitems + ((int) s->start - f->tail)) % f->nitems;
-  while (0 < diff && diff < n_bytes_enqueued)
+  while (0 < diff && diff < cursize)
     {
-      /* Segment end is beyond the tail. Advance tail and be done */
+      index = s - f->ooo_segments;
+
+      /* Segment end is beyond the tail. Advance tail and remove segment */
       if (diff < s->length)
        {
          f->tail += s->length - diff;
          f->tail %= f->nitems;
+         bytes = s->length - diff;
+         ooo_segment_del (f, index);
          break;
        }
+
       /* If we have next go on */
-      else if (s->next != OOO_SEGMENT_INVALID_INDEX)
+      if (s->next != OOO_SEGMENT_INVALID_INDEX)
        {
-         index = s - f->ooo_segments;
          s = pool_elt_at_index (f->ooo_segments, s->next);
-         diff = (f->nitems + ((int) s->start - f->tail)) % f->nitems;
+         diff = (f->nitems + (i32) (f->tail - s->start)) % f->nitems;
          ooo_segment_del (f, index);
        }
       /* End of search */
       else
        {
+         ooo_segment_del (f, index);
          break;
        }
     }
@@ -404,10 +436,7 @@ svm_fifo_enqueue_with_offset_internal (svm_fifo_t * f,
   u32 normalized_offset;
   int rv;
 
-  /* Safety: don't wrap more than nitems/2 */
-  ASSERT ((f->nitems + offset - f->tail) % f->nitems < f->nitems / 2);
-
-  /* Users would do do well to avoid this */
+  /* Users would do well to avoid this */
   if (PREDICT_FALSE (f->tail == (offset % f->nitems)))
     {
       rv = svm_fifo_enqueue_internal (f, pid, required_bytes, copy_from_here);
@@ -421,7 +450,7 @@ svm_fifo_enqueue_with_offset_internal (svm_fifo_t * f,
   nitems = f->nitems;
 
   /* Will this request fit? */
-  if ((required_bytes + offset) > (nitems - cursize))
+  if ((required_bytes + (offset - f->tail) % nitems) > (nitems - cursize))
     return -1;
 
   ooo_segment_add (f, offset, required_bytes);
@@ -523,7 +552,7 @@ svm_fifo_dequeue_nowait (svm_fifo_t * f,
 }
 
 int
-svm_fifo_peek (svm_fifo_t * f, int pid, u32 offset, u32 max_bytes,
+svm_fifo_peek (svm_fifo_t * f, int pid, u32 relative_offset, u32 max_bytes,
               u8 * copy_here)
 {
   u32 total_copy_bytes, first_copy_bytes, second_copy_bytes;
@@ -535,7 +564,7 @@ svm_fifo_peek (svm_fifo_t * f, int pid, u32 offset, u32 max_bytes,
     return -2;                 /* nothing in the fifo */
 
   nitems = f->nitems;
-  real_head = f->head + offset;
+  real_head = f->head + relative_offset;
   real_head = real_head >= nitems ? real_head - nitems : real_head;
 
   /* Number of bytes we're going to copy */
@@ -596,43 +625,6 @@ svm_fifo_dequeue_drop (svm_fifo_t * f, int pid, u32 max_bytes)
   return total_drop_bytes;
 }
 
-u8 *
-format_svm_fifo (u8 * s, va_list * args)
-{
-  svm_fifo_t *f = va_arg (*args, svm_fifo_t *);
-  int verbose = va_arg (*args, int);
-
-  s = format (s, "cursize %u nitems %u has_event %d\n",
-             f->cursize, f->nitems, f->has_event);
-  s = format (s, "head %d tail %d\n", f->head, f->tail);
-
-  if (verbose > 1)
-    s = format
-      (s, "server session %d thread %d client session %d thread %d\n",
-       f->server_session_index, f->server_thread_index,
-       f->client_session_index, f->client_thread_index);
-
-  if (verbose)
-    {
-      ooo_segment_t *seg;
-      u32 seg_index;
-
-      s = format (s, "ooo pool %d active elts\n",
-                 pool_elts (f->ooo_segments));
-
-      seg_index = f->ooos_list_head;
-
-      while (seg_index != OOO_SEGMENT_INVALID_INDEX)
-       {
-         seg = pool_elt_at_index (f->ooo_segments, seg_index);
-         s = format (s, "  pos %u, len %u next %d\n",
-                     seg->start, seg->length, seg->next);
-         seg_index = seg->next;
-       }
-    }
-  return s;
-}
-
 u32
 svm_fifo_number_ooo_segments (svm_fifo_t * f)
 {
index 1257963..890e50b 100644 (file)
@@ -294,6 +294,34 @@ fifo_get_validate_pattern (vlib_main_t * vm, test_pattern_t * test_data,
   return validate_pattern;
 }
 
+static svm_fifo_t *
+fifo_prepare (u32 fifo_size)
+{
+  svm_fifo_t *f;
+  f = svm_fifo_create (fifo_size);
+
+  /* Paint fifo data vector with -1's */
+  memset (f->data, 0xFF, fifo_size);
+
+  return f;
+}
+
+static int
+compare_data (u8 * data1, u8 * data2, u32 start, u32 len, u32 * index)
+{
+  int i;
+
+  for (i = start; i < len; i++)
+    {
+      if (data1[i] != data2[i])
+       {
+         *index = i;
+         return 1;
+       }
+    }
+  return 0;
+}
+
 int
 tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
 {
@@ -302,9 +330,9 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
   u32 *test_data = 0;
   u32 offset;
   int i, rv, verbose = 0;
-  u32 data_word, test_data_len;
+  u32 data_word, test_data_len, j;
   ooo_segment_t *ooo_seg;
-  u8 *data;
+  u8 *data, *s, *data_buf = 0;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -318,12 +346,11 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
   for (i = 0; i < vec_len (test_data); i++)
     test_data[i] = i;
 
-  f = svm_fifo_create (fifo_size);
-
-  /* Paint fifo data vector with -1's */
-  memset (f->data, 0xFF, test_data_len);
+  f = fifo_prepare (fifo_size);
 
-  /* Enqueue an initial (un-dequeued) chunk */
+  /*
+   * Enqueue an initial (un-dequeued) chunk
+   */
   rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ ,
                                sizeof (u32), (u8 *) test_data);
   TCP_TEST ((rv == sizeof (u32)), "enqueued %d", rv);
@@ -337,9 +364,7 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
     {
       offset = (2 * i + 1) * sizeof (u32);
       data = (u8 *) (test_data + (2 * i + 1));
-      rv =
-       svm_fifo_enqueue_with_offset (f, 0 /* pid */ , offset, sizeof (u32),
-                                     data);
+      rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data);
       if (verbose)
        vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
                         offset + sizeof (u32));
@@ -352,16 +377,23 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
 
   if (verbose)
     vlib_cli_output (vm, "fifo after odd segs: %U", format_svm_fifo, f, 1);
+
   TCP_TEST ((f->tail == 8), "fifo tail %u", f->tail);
 
-  /* Paint some of missing data backwards */
+  /*
+   * Make sure format functions are not buggy
+   */
+  s = format (0, "%U", format_svm_fifo, f, 2);
+  vec_free (s);
+
+  /*
+   * Paint some of missing data backwards
+   */
   for (i = 3; i > 1; i--)
     {
       offset = (2 * i + 0) * sizeof (u32);
       data = (u8 *) (test_data + (2 * i + 0));
-      rv =
-       svm_fifo_enqueue_with_offset (f, 0 /* pid */ , offset, sizeof (u32),
-                                     data);
+      rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data);
       if (verbose)
        vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i, offset,
                         offset + sizeof (u32));
@@ -383,7 +415,9 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
   TCP_TEST ((ooo_seg->length == 16),
            "first ooo seg length %u", ooo_seg->length);
 
-  /* Enqueue the missing u32 */
+  /*
+   * Enqueue the missing u32
+   */
   rv = svm_fifo_enqueue_nowait (f, 0 /* pid */ , sizeof (u32),
                                (u8 *) (test_data + 2));
   if (verbose)
@@ -393,7 +427,9 @@ tcp_test_fifo1 (vlib_main_t * vm, unformat_input_t * input)
   TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
            "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
 
-  /* Collect results */
+  /*
+   * Collect results
+   */
   for (i = 0; i < 7; i++)
     {
       rv = svm_fifo_dequeue_nowait (f, 0 /* pid */ , sizeof (u32),
@@ -411,8 +447,77 @@ tcp_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);
+
+  for (i = 0; i < 4; i++)
+    {
+      offset = (2 * i + 1) * sizeof (u32);
+      data = (u8 *) (test_data + (2 * i + 1));
+      rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data);
+      if (verbose)
+       vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
+                        offset + sizeof (u32));
+      if (rv)
+       {
+         clib_warning ("enqueue returned %d", rv);
+         goto err;
+       }
+    }
+
+  rv = svm_fifo_enqueue_with_offset (f, 0, 8, 21, data);
+  TCP_TEST ((rv == 0), "ooo enqueued %u", rv);
+  TCP_TEST ((svm_fifo_number_ooo_segments (f) == 1),
+           "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
+
+  vec_validate (data_buf, vec_len (data));
+  svm_fifo_peek (f, 0, 0, vec_len (data), data_buf);
+  if (compare_data (data_buf, data, 8, vec_len (data), &j))
+    {
+      TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
+    }
+  vec_reset_length (data_buf);
+
+  /*
+   * Test segment overlaps: enqueue and overlap ooo segments
+   */
+  svm_fifo_free (f);
+  f = fifo_prepare (fifo_size);
+
+  for (i = 0; i < 4; i++)
+    {
+      offset = (2 * i + 1) * sizeof (u32);
+      data = (u8 *) (test_data + (2 * i + 1));
+      rv = svm_fifo_enqueue_with_offset (f, 0, offset, sizeof (u32), data);
+      if (verbose)
+       vlib_cli_output (vm, "add [%d] [%d, %d]", 2 * i + 1, offset,
+                        offset + sizeof (u32));
+      if (rv)
+       {
+         clib_warning ("enqueue returned %d", rv);
+         goto err;
+       }
+    }
+
+  rv = svm_fifo_enqueue_nowait (f, 0, 29, data);
+  TCP_TEST ((rv == 32), "ooo enqueued %u", rv);
+  TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
+           "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
+
+  vec_validate (data_buf, vec_len (data));
+  svm_fifo_peek (f, 0, 0, vec_len (data), data_buf);
+  if (compare_data (data_buf, data, 0, vec_len (data), &j))
+    {
+      TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j], data[j]);
+    }
+
+  vec_free (data_buf);
   svm_fifo_free (f);
   vec_free (test_data);
+
   return 0;
 
 err:
@@ -437,10 +542,7 @@ tcp_test_fifo2 (vlib_main_t * vm)
   vp = fifo_get_validate_pattern (vm, test_data, test_data_len);
 
   /* Create a fifo */
-  f = svm_fifo_create (fifo_size);
-
-  /* Paint the fifo data vector with -1's */
-  memset (f->data, 0xFF, 1 << 20);
+  f = fifo_prepare (fifo_size);
 
   /*
    * Try with sorted data
@@ -473,10 +575,7 @@ tcp_test_fifo2 (vlib_main_t * vm)
    * Now try it again w/ unsorted data...
    */
 
-  f = svm_fifo_create (fifo_size);
-
-  /* Paint fifo data vector with -1's */
-  memset (f->data, 0xFF, 1 << 20);
+  f = fifo_prepare (fifo_size);
 
   for (i = 0; i < test_data_len; i++)
     {
@@ -516,16 +615,13 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
   u32 fifo_size = 4 << 10;
   u32 fifo_initial_offset = 0;
   u32 total_size = 2 << 10;
-  int overlap = 0;
-  int i, rv;
-  u8 *data_pattern = 0;
+  int overlap = 0, verbose = 0, randomize = 1, drop = 0, in_seq_all = 0;
+  u8 *data_pattern = 0, *data_buf = 0;
   test_pattern_t *tp, *generate = 0;
-  u32 nsegs = 2;
-  u32 seg_size, length_so_far;
+  u32 nsegs = 2, seg_size, length_so_far;
   u32 current_offset, offset_increment, len_this_chunk;
-  u32 seed = 0xdeaddabe;
-  int verbose = 0;
-  int randomize = 1;
+  u32 seed = 0xdeaddabe, j;
+  int i, rv;
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -545,6 +641,10 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
        ;
       else if (unformat (input, "no-randomize"))
        randomize = 0;
+      else if (unformat (input, "in-seq-all"))
+       in_seq_all = 1;
+      else if (unformat (input, "drop"))
+       drop = 1;
       else
        {
          clib_error_t *e = clib_error_return
@@ -554,6 +654,18 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
        }
     }
 
+  if (total_size > fifo_size)
+    {
+      clib_warning ("total_size %d greater than fifo size %d", total_size,
+                   fifo_size);
+      return -1;
+    }
+  if (overlap && randomize == 0)
+    {
+      clib_warning ("Can't enqueue in-order with overlap");
+      return -1;
+    }
+
   /*
    * Generate data
    */
@@ -561,9 +673,12 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
   for (i = 0; i < vec_len (data_pattern); i++)
     data_pattern[i] = i & 0xff;
 
+  /*
+   * Generate segments
+   */
   seg_size = total_size / nsegs;
   length_so_far = 0;
-  current_offset = 1;
+  current_offset = randomize;
   while (length_so_far < total_size)
     {
       vec_add2 (generate, tp, 1);
@@ -616,51 +731,100 @@ tcp_test_fifo3 (vlib_main_t * vm, unformat_input_t * input)
          generate[dst_index] = generate[src_index];
          generate[src_index] = tmp[0];
        }
-    }
-
-  if (verbose)
-    {
-      vlib_cli_output (vm, "randomized data pattern:");
-      for (i = 0; i < vec_len (generate); i++)
+      if (verbose)
        {
-         vlib_cli_output (vm, "[%d] offset %u len %u", i,
-                          generate[i].offset, generate[i].len);
+         vlib_cli_output (vm, "randomized data pattern:");
+         for (i = 0; i < vec_len (generate); i++)
+           {
+             vlib_cli_output (vm, "[%d] offset %u len %u", i,
+                              generate[i].offset, generate[i].len);
+           }
        }
     }
 
-  /* Create a fifo */
-  f = svm_fifo_create (fifo_size);
-
-  /* Paint the fifo data vector with -1's */
-  memset (f->data, 0xFF, fifo_size);
+  /*
+   * Create a fifo and add segments
+   */
+  f = fifo_prepare (fifo_size);
 
   /* manually set head and tail pointers to validate modular arithmetic */
-  f->head = fifo_initial_offset % fifo_size;
-  f->tail = fifo_initial_offset % fifo_size;
+  fifo_initial_offset = fifo_initial_offset % fifo_size;
+  f->head = fifo_initial_offset;
+  f->tail = fifo_initial_offset;
 
   for (i = 0; i < vec_len (generate); i++)
     {
       tp = generate + i;
-      rv = svm_fifo_enqueue_with_offset (f, 0, tp->offset, tp->len,
+      rv = svm_fifo_enqueue_with_offset (f, 0, fifo_initial_offset
+                                        + tp->offset, tp->len,
                                         (u8 *) data_pattern + tp->offset);
     }
 
-  /* Expected result: one big fat chunk at offset 1 */
+  /*
+   * Expected result: one big fat chunk at offset 1 if randomize == 1
+   */
 
   if (verbose)
     vlib_cli_output (vm, "fifo before missing link: %U",
                     format_svm_fifo, f, 1 /* verbose */ );
 
-  rv = svm_fifo_enqueue_nowait (f, 0, 1 /* count */ , data_pattern + 0);
+  /*
+   * Add the missing byte if segments were randomized
+   */
+  if (randomize)
+    {
+      u32 bytes_to_enq = 1;
+      if (in_seq_all)
+       bytes_to_enq = total_size;
+      rv = svm_fifo_enqueue_nowait (f, 0, bytes_to_enq, data_pattern + 0);
+
+      if (verbose)
+       vlib_cli_output (vm, "in-order enqueue returned %d", rv);
 
-  if (verbose)
-    vlib_cli_output (vm, "in-order enqueue returned %d", rv);
+      TCP_TEST ((rv == total_size), "enqueued %u expected %u", rv,
+               total_size);
+
+    }
+
+  TCP_TEST ((svm_fifo_has_ooo_data (f) == 0), "number of ooo segments %u",
+           svm_fifo_number_ooo_segments (f));
+
+  /*
+   * Test if peeked data is the same as original data
+   */
+  vec_validate (data_buf, vec_len (data_pattern));
+  svm_fifo_peek (f, 0, 0, vec_len (data_pattern), data_buf);
+  if (compare_data (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
+    {
+      TCP_TEST (0, "[%d] peeked %u expected %u", j, data_buf[j],
+               data_pattern[j]);
+    }
+  vec_reset_length (data_buf);
+
+  /*
+   * Dequeue or drop all data
+   */
+  if (drop)
+    {
+      svm_fifo_dequeue_drop (f, 0, vec_len (data_pattern));
+    }
+  else
+    {
+      svm_fifo_dequeue_nowait (f, 0, vec_len (data_pattern), data_buf);
+      if (compare_data
+         (data_buf, data_pattern, 0, vec_len (data_pattern), &j))
+       {
+         TCP_TEST (0, "[%d] dequeued %u expected %u", j, data_buf[j],
+                   data_pattern[j]);
+       }
+    }
+
+  TCP_TEST ((svm_fifo_max_dequeue (f) == 0), "fifo has %d bytes",
+           svm_fifo_max_dequeue (f));
 
-  TCP_TEST ((rv == total_size), "retrieved %u expected %u", rv, total_size);
-  TCP_TEST ((svm_fifo_number_ooo_segments (f) == 0),
-           "number of ooo segments %u", svm_fifo_number_ooo_segments (f));
   svm_fifo_free (f);
   vec_free (data_pattern);
+  vec_free (data_buf);
 
   return 0;
 }
@@ -669,6 +833,7 @@ static int
 tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
 {
   int res = 0;
+  char *str;
 
   /* Run all tests */
   if (unformat_check_input (input) == UNFORMAT_END_OF_INPUT)
@@ -681,13 +846,35 @@ tcp_test_fifo (vlib_main_t * vm, unformat_input_t * input)
       if (res)
        return res;
 
-      /* Run a number of fifo3 configs */
-      unformat_init_cstring (input, "nsegs 3 overlap seed 123");
+      /*
+       * Run a number of fifo3 configs
+       */
+      str = "nsegs 10 overlap seed 123";
+      unformat_init_cstring (input, str);
+      if (tcp_test_fifo3 (vm, input))
+       return -1;
+      unformat_free (input);
+
+      str = "nsegs 10 overlap seed 123 in-seq-all";
+      unformat_init_cstring (input, str);
+      if (tcp_test_fifo3 (vm, input))
+       return -1;
+      unformat_free (input);
+
+      str = "nsegs 10 overlap seed 123 initial-offset 3917";
+      unformat_init_cstring (input, str);
+      if (tcp_test_fifo3 (vm, input))
+       return -1;
+      unformat_free (input);
+
+      str = "nsegs 10 overlap seed 123 initial-offset 3917 drop";
+      unformat_init_cstring (input, str);
       if (tcp_test_fifo3 (vm, input))
        return -1;
       unformat_free (input);
 
-      unformat_init_cstring (input, "nsegs 10");
+      str = "nsegs 10 seed 123 initial-offset 3917 drop no-randomize";
+      unformat_init_cstring (input, str);
       if (tcp_test_fifo3 (vm, input))
        return -1;
       unformat_free (input);