Reorganize source tree to use single autotools instance
[vpp.git] / src / vppinfra / test_vhash.c
diff --git a/src/vppinfra/test_vhash.c b/src/vppinfra/test_vhash.c
new file mode 100644 (file)
index 0000000..7293fdd
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+  Copyright (c) 2010 Eliot Dresselhaus
+
+  Permission is hereby granted, free of charge, to any person obtaining
+  a copy of this software and associated documentation files (the
+  "Software"), to deal in the Software without restriction, including
+  without limitation the rights to use, copy, modify, merge, publish,
+  distribute, sublicense, and/or sell copies of the Software, and to
+  permit persons to whom the Software is furnished to do so, subject to
+  the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#if 0
+#ifdef __OPTIMIZE__
+#undef CLIB_DEBUG
+#endif
+#endif
+
+#include <vppinfra/bitmap.h>
+#include <vppinfra/error.h>
+#include <vppinfra/os.h>
+#include <vppinfra/random.h>
+#include <vppinfra/time.h>
+#include <vppinfra/vhash.h>
+
+#ifdef CLIB_HAVE_VEC128
+
+typedef struct
+{
+  u32 n_iter;
+  u32 seed;
+  u32 verbose;
+  u32 n_keys;
+  u32 log2_size;
+  u32 n_key_u32;
+
+  u32 n_vectors_div_4;
+  u32 n_vectors_mod_4;
+
+  u32 *keys;
+  u32 *results;
+
+  u32 *vhash_get_key_indices;
+  u32 *vhash_get_results;
+
+  u32 *vhash_key_indices;
+  u32 *vhash_results;
+
+  vhash_t vhash;
+
+  uword **key_hash;
+
+  struct
+  {
+    u64 n_clocks;
+    u64 n_vectors;
+    u64 n_calls;
+  } get_stats, set_stats, unset_stats;
+} test_vhash_main_t;
+
+always_inline u32
+test_vhash_key_gather (void *_tm, u32 vi, u32 wi, u32 n_key_u32s)
+{
+  test_vhash_main_t *tm = _tm;
+  ASSERT (n_key_u32s == tm->n_key_u32);
+  ASSERT (wi < n_key_u32s);
+  vi = vec_elt (tm->vhash_key_indices, vi);
+  return vec_elt (tm->keys, vi * n_key_u32s + wi);
+}
+
+always_inline u32x4
+test_vhash_4key_gather (void *_tm, u32 vi, u32 wi, u32 n_key_u32s)
+{
+  test_vhash_main_t *tm = _tm;
+  u32 *p;
+  u32x4_union_t x;
+
+  ASSERT (n_key_u32s == tm->n_key_u32);
+  ASSERT (wi < n_key_u32s);
+
+  p = vec_elt_at_index (tm->vhash_key_indices, vi + 0);
+  x.as_u32[0] = tm->keys[p[0] * n_key_u32s + wi];
+  x.as_u32[1] = tm->keys[p[1] * n_key_u32s + wi];
+  x.as_u32[2] = tm->keys[p[2] * n_key_u32s + wi];
+  x.as_u32[3] = tm->keys[p[3] * n_key_u32s + wi];
+  return x.as_u32x4;
+}
+
+always_inline u32
+test_vhash_get_result (void *_tm,
+                      u32 vector_index, u32 result_index, u32 n_key_u32s)
+{
+  test_vhash_main_t *tm = _tm;
+  u32 *p = vec_elt_at_index (tm->vhash_results, vector_index);
+  p[0] = result_index;
+  return result_index;
+}
+
+always_inline u32x4
+test_vhash_get_4result (void *_tm,
+                       u32 vector_index, u32x4 results, u32 n_key_u32s)
+{
+  test_vhash_main_t *tm = _tm;
+  u32 *p = vec_elt_at_index (tm->vhash_results, vector_index);
+  *(u32x4 *) p = results;
+  return results;
+}
+
+always_inline u32
+test_vhash_set_result (void *_tm,
+                      u32 vector_index, u32 old_result, u32 n_key_u32s)
+{
+  test_vhash_main_t *tm = _tm;
+  u32 *p = vec_elt_at_index (tm->vhash_results, vector_index);
+  u32 new_result = p[0];
+  p[0] = old_result;
+  return new_result;
+}
+
+always_inline u32
+test_vhash_unset_result (void *_tm, u32 i, u32 old_result, u32 n_key_u32s)
+{
+  test_vhash_main_t *tm = _tm;
+  u32 *p = vec_elt_at_index (tm->vhash_results, i);
+  p[0] = old_result;
+  return 0;
+}
+
+#define _(N_KEY_U32)                                                   \
+  always_inline u32                                                    \
+  test_vhash_key_gather_##N_KEY_U32 (void * _tm, u32 vi, u32 i)                \
+  { return test_vhash_key_gather (_tm, vi, i, N_KEY_U32); }            \
+                                                                       \
+  always_inline u32x4                                                  \
+  test_vhash_key_gather_4_##N_KEY_U32 (void * _tm, u32 vi, u32 i)      \
+  {  return test_vhash_4key_gather (_tm, vi, i, N_KEY_U32); }          \
+                                                                       \
+  clib_pipeline_stage                                                  \
+  (test_vhash_gather_keys_stage_##N_KEY_U32,                           \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_gather_4key_stage                                           \
+       (&tm->vhash,                                                    \
+       /* vector_index */ i,                                           \
+       test_vhash_key_gather_4_##N_KEY_U32,                            \
+       tm,                                                             \
+       N_KEY_U32);                                                     \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage_no_inline                                                \
+  (test_vhash_gather_keys_mod_stage_##N_KEY_U32,                       \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_gather_key_stage                                            \
+       (&tm->vhash,                                                    \
+       /* vector_index */ tm->n_vectors_div_4,                         \
+       /* n_vectors */ tm->n_vectors_mod_4,                            \
+       test_vhash_key_gather_##N_KEY_U32,                              \
+       tm,                                                             \
+       N_KEY_U32);                                                     \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage                                                  \
+  (test_vhash_hash_finalize_stage_##N_KEY_U32,                         \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_finalize_stage (&tm->vhash, i, N_KEY_U32);                  \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage_no_inline                                                \
+  (test_vhash_hash_finalize_mod_stage_##N_KEY_U32,                     \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_finalize_stage (&tm->vhash, tm->n_vectors_div_4, N_KEY_U32);        \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage                                                  \
+  (test_vhash_get_stage_##N_KEY_U32,                                   \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_get_4_stage (&tm->vhash,                                    \
+                       /* vector_index */ i,                           \
+                       test_vhash_get_4result,                         \
+                       tm, N_KEY_U32);                                 \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage_no_inline                                                \
+  (test_vhash_get_mod_stage_##N_KEY_U32,                               \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_get_stage (&tm->vhash,                                      \
+                     /* vector_index */ tm->n_vectors_div_4,           \
+                     /* n_vectors */ tm->n_vectors_mod_4,              \
+                     test_vhash_get_result,                            \
+                     tm, N_KEY_U32);                                   \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage                                                  \
+  (test_vhash_set_stage_##N_KEY_U32,                                   \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_set_stage (&tm->vhash,                                      \
+                     /* vector_index */ i,                             \
+                     /* n_vectors */ VECTOR_WORD_TYPE_LEN (u32),       \
+                     test_vhash_set_result,                            \
+                     tm, N_KEY_U32);                                   \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage_no_inline                                                \
+  (test_vhash_set_mod_stage_##N_KEY_U32,                               \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_set_stage (&tm->vhash,                                      \
+                     /* vector_index */ tm->n_vectors_div_4,           \
+                     /* n_vectors */ tm->n_vectors_mod_4,              \
+                     test_vhash_set_result,                            \
+                     tm, N_KEY_U32);                                   \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage                                                  \
+  (test_vhash_unset_stage_##N_KEY_U32,                                 \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_unset_stage (&tm->vhash,                                    \
+                       /* vector_index */ i,                           \
+                       /* n_vectors */ VECTOR_WORD_TYPE_LEN (u32),     \
+                       test_vhash_unset_result,                        \
+                       tm, N_KEY_U32);                                 \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage_no_inline                                                \
+  (test_vhash_unset_mod_stage_##N_KEY_U32,                             \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_unset_stage (&tm->vhash,                                    \
+                       /* vector_index */ tm->n_vectors_div_4,         \
+                       /* n_vectors */ tm->n_vectors_mod_4,            \
+                       test_vhash_unset_result,                        \
+                       tm, N_KEY_U32);                                 \
+   })
+
+_(1);
+_(2);
+_(3);
+_(4);
+_(5);
+_(6);
+
+#undef _
+
+#define _(N_KEY_U32)                                                   \
+  clib_pipeline_stage                                                  \
+  (test_vhash_hash_mix_stage_##N_KEY_U32,                              \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_mix_stage (&tm->vhash, i, N_KEY_U32);                       \
+   })                                                                  \
+                                                                       \
+  clib_pipeline_stage_no_inline                                                \
+  (test_vhash_hash_mix_mod_stage_##N_KEY_U32,                          \
+   test_vhash_main_t *, tm, i,                                         \
+   {                                                                   \
+     vhash_mix_stage (&tm->vhash, tm->n_vectors_div_4, N_KEY_U32);     \
+   })
+
+_(4);
+_(5);
+_(6);
+
+#undef _
+
+typedef enum
+{
+  GET, SET, UNSET,
+} test_vhash_op_t;
+
+static void
+test_vhash_op (test_vhash_main_t * tm,
+              u32 * key_indices,
+              u32 * results, uword n_keys, test_vhash_op_t op)
+{
+  vhash_validate_sizes (&tm->vhash, tm->n_key_u32, n_keys);
+
+  tm->vhash_results = results;
+  tm->vhash_key_indices = key_indices;
+  tm->n_vectors_div_4 = n_keys / 4;
+  tm->n_vectors_mod_4 = n_keys % 4;
+
+  if (tm->n_vectors_div_4 > 0)
+    {
+      switch (tm->n_key_u32)
+       {
+       default:
+         ASSERT (0);
+         break;
+
+#define _(N_KEY_U32)                                           \
+       case N_KEY_U32:                                         \
+         if (op == GET)                                        \
+           clib_pipeline_run_3_stage                           \
+             (tm->n_vectors_div_4,                             \
+              tm,                                              \
+              test_vhash_gather_keys_stage_##N_KEY_U32,        \
+              test_vhash_hash_finalize_stage_##N_KEY_U32,      \
+              test_vhash_get_stage_##N_KEY_U32);               \
+         else if (op == SET)                                   \
+           clib_pipeline_run_3_stage                           \
+             (tm->n_vectors_div_4,                             \
+              tm,                                              \
+              test_vhash_gather_keys_stage_##N_KEY_U32,        \
+              test_vhash_hash_finalize_stage_##N_KEY_U32,      \
+              test_vhash_set_stage_##N_KEY_U32);               \
+         else                                                  \
+           clib_pipeline_run_3_stage                           \
+             (tm->n_vectors_div_4,                             \
+              tm,                                              \
+              test_vhash_gather_keys_stage_##N_KEY_U32,        \
+              test_vhash_hash_finalize_stage_##N_KEY_U32,      \
+              test_vhash_unset_stage_##N_KEY_U32);             \
+         break;
+
+         _(1);
+         _(2);
+         _(3);
+
+#undef _
+
+#define _(N_KEY_U32)                                           \
+       case N_KEY_U32:                                         \
+         if (op == GET)                                        \
+           clib_pipeline_run_4_stage                           \
+             (tm->n_vectors_div_4,                             \
+              tm,                                              \
+              test_vhash_gather_keys_stage_##N_KEY_U32,        \
+              test_vhash_hash_mix_stage_##N_KEY_U32,           \
+              test_vhash_hash_finalize_stage_##N_KEY_U32,      \
+              test_vhash_get_stage_##N_KEY_U32);               \
+         else if (op == SET)                                   \
+           clib_pipeline_run_4_stage                           \
+             (tm->n_vectors_div_4,                             \
+              tm,                                              \
+              test_vhash_gather_keys_stage_##N_KEY_U32,        \
+              test_vhash_hash_mix_stage_##N_KEY_U32,           \
+              test_vhash_hash_finalize_stage_##N_KEY_U32,      \
+              test_vhash_set_stage_##N_KEY_U32);               \
+         else                                                  \
+           clib_pipeline_run_4_stage                           \
+             (tm->n_vectors_div_4,                             \
+              tm,                                              \
+              test_vhash_gather_keys_stage_##N_KEY_U32,        \
+              test_vhash_hash_mix_stage_##N_KEY_U32,           \
+              test_vhash_hash_finalize_stage_##N_KEY_U32,      \
+              test_vhash_unset_stage_##N_KEY_U32);             \
+         break;
+
+         _(4);
+         _(5);
+         _(6);
+
+#undef _
+       }
+    }
+
+
+  if (tm->n_vectors_mod_4 > 0)
+    {
+      switch (tm->n_key_u32)
+       {
+       default:
+         ASSERT (0);
+         break;
+
+#define _(N_KEY_U32)                                           \
+       case N_KEY_U32:                                         \
+         if (op == GET)                                        \
+           clib_pipeline_run_3_stage                           \
+             (1,                                               \
+              tm,                                              \
+              test_vhash_gather_keys_mod_stage_##N_KEY_U32,    \
+              test_vhash_hash_finalize_mod_stage_##N_KEY_U32,  \
+              test_vhash_get_mod_stage_##N_KEY_U32);           \
+         else if (op == SET)                                   \
+           clib_pipeline_run_3_stage                           \
+             (1,                                               \
+              tm,                                              \
+              test_vhash_gather_keys_mod_stage_##N_KEY_U32,    \
+              test_vhash_hash_finalize_mod_stage_##N_KEY_U32,  \
+              test_vhash_set_mod_stage_##N_KEY_U32);           \
+         else                                                  \
+           clib_pipeline_run_3_stage                           \
+             (1,                                               \
+              tm,                                              \
+              test_vhash_gather_keys_mod_stage_##N_KEY_U32,    \
+              test_vhash_hash_finalize_mod_stage_##N_KEY_U32,  \
+              test_vhash_unset_mod_stage_##N_KEY_U32);         \
+       break;
+
+         _(1);
+         _(2);
+         _(3);
+
+#undef _
+
+#define _(N_KEY_U32)                                           \
+       case N_KEY_U32:                                         \
+         if (op == GET)                                        \
+           clib_pipeline_run_4_stage                           \
+             (1,                                               \
+              tm,                                              \
+              test_vhash_gather_keys_mod_stage_##N_KEY_U32,    \
+              test_vhash_hash_mix_mod_stage_##N_KEY_U32,       \
+              test_vhash_hash_finalize_mod_stage_##N_KEY_U32,  \
+              test_vhash_get_mod_stage_##N_KEY_U32);           \
+         else if (op == SET)                                   \
+           clib_pipeline_run_4_stage                           \
+             (1,                                               \
+              tm,                                              \
+              test_vhash_gather_keys_mod_stage_##N_KEY_U32,    \
+              test_vhash_hash_mix_mod_stage_##N_KEY_U32,       \
+              test_vhash_hash_finalize_mod_stage_##N_KEY_U32,  \
+              test_vhash_set_mod_stage_##N_KEY_U32);           \
+         else                                                  \
+           clib_pipeline_run_4_stage                           \
+             (1,                                               \
+              tm,                                              \
+              test_vhash_gather_keys_mod_stage_##N_KEY_U32,    \
+              test_vhash_hash_mix_mod_stage_##N_KEY_U32,       \
+              test_vhash_hash_finalize_mod_stage_##N_KEY_U32,  \
+              test_vhash_unset_mod_stage_##N_KEY_U32);         \
+         break;
+
+         _(4);
+         _(5);
+         _(6);
+
+#undef _
+       }
+    }
+}
+
+int
+test_vhash_main (unformat_input_t * input)
+{
+  clib_error_t *error = 0;
+  test_vhash_main_t _tm, *tm = &_tm;
+  vhash_t *vh = &tm->vhash;
+  uword i, j;
+
+  memset (tm, 0, sizeof (tm[0]));
+  tm->n_iter = 100;
+  tm->seed = 1;
+  tm->n_keys = 1;
+  tm->n_key_u32 = 1;
+  tm->log2_size = 8;
+  tm->verbose = 0;
+
+  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (input, "iter %d", &tm->n_iter))
+       ;
+      else if (unformat (input, "seed %d", &tm->seed))
+       ;
+      else if (unformat (input, "n-keys %d", &tm->n_keys))
+       ;
+      else if (unformat (input, "log2-size %d", &tm->log2_size))
+       ;
+      else if (unformat (input, "key-words %d", &tm->n_key_u32))
+       ;
+      else if (unformat (input, "verbose %=", &tm->verbose, 1))
+       ;
+      else
+       {
+         error = clib_error_create ("unknown input `%U'\n",
+                                    format_unformat_error, input);
+         goto done;
+       }
+    }
+
+  if (tm->seed == 0)
+    tm->seed = random_default_seed ();
+
+  clib_warning ("iter %d seed %d n-keys %d log2-size %d key-words %d",
+               tm->n_iter, tm->seed, tm->n_keys, tm->log2_size,
+               tm->n_key_u32);
+
+  {
+    u32 seeds[3];
+    seeds[0] = seeds[1] = seeds[2] = 0xdeadbeef;
+    vhash_init (vh, tm->log2_size, tm->n_key_u32, seeds);
+  }
+
+  /* Choose unique keys. */
+  vec_resize (tm->keys, tm->n_keys * tm->n_key_u32);
+  vec_resize (tm->key_hash, tm->n_key_u32);
+  for (i = j = 0; i < vec_len (tm->keys); i++, j++)
+    {
+      j = j == tm->n_key_u32 ? 0 : j;
+      do
+       {
+         tm->keys[i] = random_u32 (&tm->seed);
+       }
+      while (hash_get (tm->key_hash[j], tm->keys[i]));
+      hash_set (tm->key_hash[j], tm->keys[i], 0);
+    }
+
+  vec_resize (tm->results, tm->n_keys);
+  for (i = 0; i < vec_len (tm->results); i++)
+    {
+      do
+       {
+         tm->results[i] = random_u32 (&tm->seed);
+       }
+      while (tm->results[i] == ~0);
+    }
+
+  vec_resize_aligned (tm->vhash_get_results, tm->n_keys,
+                     CLIB_CACHE_LINE_BYTES);
+  vec_clone (tm->vhash_get_key_indices, tm->results);
+  for (i = 0; i < vec_len (tm->vhash_get_key_indices); i++)
+    tm->vhash_get_key_indices[i] = i;
+
+  {
+    uword *is_set_bitmap = 0;
+    uword *to_set_bitmap = 0;
+    uword *to_unset_bitmap = 0;
+    u32 *to_set = 0, *to_unset = 0;
+    u32 *to_set_results = 0, *to_unset_results = 0;
+    u64 t[2];
+
+    for (i = 0; i < tm->n_iter; i++)
+      {
+       vec_reset_length (to_set);
+       vec_reset_length (to_unset);
+       vec_reset_length (to_set_results);
+       vec_reset_length (to_unset_results);
+
+       do
+         {
+           to_set_bitmap = clib_bitmap_random (to_set_bitmap,
+                                               tm->n_keys, &tm->seed);
+         }
+       while (clib_bitmap_is_zero (to_set_bitmap));
+       to_unset_bitmap = clib_bitmap_dup_and (to_set_bitmap, is_set_bitmap);
+       to_set_bitmap = clib_bitmap_andnot (to_set_bitmap, to_unset_bitmap);
+
+       /* *INDENT-OFF* */
+       clib_bitmap_foreach (j, to_set_bitmap, ({
+             vec_add1 (to_set, j);
+             vec_add1 (to_set_results, tm->results[j]);
+       }));
+       /* *INDENT-ON* */
+       /* *INDENT-OFF* */
+       clib_bitmap_foreach (j, to_unset_bitmap, ({
+             vec_add1 (to_unset, j);
+             vec_add1 (to_unset_results, 0xdeadbeef);
+       }));
+       /* *INDENT-ON* */
+
+       if (vec_len (to_set) > 0)
+         {
+           t[0] = clib_cpu_time_now ();
+           test_vhash_op (tm, to_set, to_set_results, vec_len (to_set), SET);
+           t[1] = clib_cpu_time_now ();
+           tm->set_stats.n_clocks += t[1] - t[0];
+           tm->set_stats.n_vectors += vec_len (to_set);
+           tm->set_stats.n_calls += 1;
+           is_set_bitmap = clib_bitmap_or (is_set_bitmap, to_set_bitmap);
+         }
+
+       t[0] = clib_cpu_time_now ();
+       test_vhash_op (tm, tm->vhash_get_key_indices,
+                      tm->vhash_get_results,
+                      vec_len (tm->vhash_get_key_indices), GET);
+       t[1] = clib_cpu_time_now ();
+       tm->get_stats.n_clocks += t[1] - t[0];
+       tm->get_stats.n_vectors += vec_len (tm->vhash_get_key_indices);
+       tm->get_stats.n_calls += 1;
+
+       for (j = 0; j < vec_len (tm->vhash_get_results); j++)
+         {
+           u32 r0 = tm->vhash_get_results[j];
+           u32 r1 = tm->results[j];
+           if (clib_bitmap_get (is_set_bitmap, j))
+             {
+               if (r0 != r1)
+                 os_panic ();
+             }
+           else
+             {
+               if (r0 != ~0)
+                 os_panic ();
+             }
+         }
+
+       if (vh->n_elts != clib_bitmap_count_set_bits (is_set_bitmap))
+         os_panic ();
+
+       if (vec_len (to_unset) > 0)
+         {
+           t[0] = clib_cpu_time_now ();
+           test_vhash_op (tm, to_unset, to_unset_results,
+                          vec_len (to_unset), UNSET);
+           t[1] = clib_cpu_time_now ();
+           tm->unset_stats.n_clocks += t[1] - t[0];
+           tm->unset_stats.n_vectors += vec_len (to_unset);
+           tm->unset_stats.n_calls += 1;
+           is_set_bitmap =
+             clib_bitmap_andnot (is_set_bitmap, to_unset_bitmap);
+         }
+
+       t[0] = clib_cpu_time_now ();
+       test_vhash_op (tm, tm->vhash_get_key_indices,
+                      tm->vhash_get_results,
+                      vec_len (tm->vhash_get_key_indices), GET);
+       t[1] = clib_cpu_time_now ();
+       tm->get_stats.n_clocks += t[1] - t[0];
+       tm->get_stats.n_vectors += vec_len (tm->vhash_get_key_indices);
+       tm->get_stats.n_calls += 1;
+
+       for (j = 0; j < vec_len (tm->vhash_get_results); j++)
+         {
+           u32 r0 = tm->vhash_get_results[j];
+           u32 r1 = tm->results[j];
+           if (clib_bitmap_get (is_set_bitmap, j))
+             {
+               if (r0 != r1)
+                 os_panic ();
+             }
+           else
+             {
+               if (r0 != ~0)
+                 os_panic ();
+             }
+         }
+
+       if (vh->n_elts != clib_bitmap_count_set_bits (is_set_bitmap))
+         os_panic ();
+      }
+
+    vhash_resize (vh, tm->log2_size + 1);
+
+    test_vhash_op (tm, tm->vhash_get_key_indices,
+                  tm->vhash_get_results,
+                  vec_len (tm->vhash_get_key_indices), GET);
+
+    for (j = 0; j < vec_len (tm->vhash_get_results); j++)
+      {
+       u32 r0 = tm->vhash_get_results[j];
+       u32 r1 = tm->results[j];
+       if (clib_bitmap_get (is_set_bitmap, j))
+         {
+           if (r0 != r1)
+             os_panic ();
+         }
+       else
+         {
+           if (r0 != ~0)
+             os_panic ();
+         }
+      }
+
+    if (vh->n_elts != clib_bitmap_count_set_bits (is_set_bitmap))
+      os_panic ();
+  }
+
+  {
+    clib_time_t ct;
+
+    clib_time_init (&ct);
+
+    clib_warning ("%.4e clocks/get %.4e gets/call %.4e gets/sec",
+                 (f64) tm->get_stats.n_clocks /
+                 (f64) tm->get_stats.n_vectors,
+                 (f64) tm->get_stats.n_vectors / (f64) tm->get_stats.n_calls,
+                 (f64) tm->get_stats.n_vectors /
+                 (f64) (tm->get_stats.n_clocks * ct.seconds_per_clock));
+    if (tm->set_stats.n_calls > 0)
+      clib_warning ("%.4e clocks/set %.4e sets/call %.4e sets/sec",
+                   (f64) tm->set_stats.n_clocks /
+                   (f64) tm->set_stats.n_vectors,
+                   (f64) tm->set_stats.n_vectors /
+                   (f64) tm->set_stats.n_calls,
+                   (f64) tm->set_stats.n_vectors /
+                   (f64) (tm->set_stats.n_clocks * ct.seconds_per_clock));
+    if (tm->unset_stats.n_calls > 0)
+      clib_warning ("%.4e clocks/unset %.4e unsets/call %.4e unsets/sec",
+                   (f64) tm->unset_stats.n_clocks /
+                   (f64) tm->unset_stats.n_vectors,
+                   (f64) tm->unset_stats.n_vectors /
+                   (f64) tm->unset_stats.n_calls,
+                   (f64) tm->unset_stats.n_vectors /
+                   (f64) (tm->unset_stats.n_clocks * ct.seconds_per_clock));
+  }
+
+done:
+  if (error)
+    clib_error_report (error);
+  return 0;
+}
+
+#endif /* CLIB_HAVE_VEC128 */
+
+#ifndef CLIB_HAVE_VEC128
+int
+test_vhash_main (unformat_input_t * input)
+{
+  clib_error ("compiled without vector support");
+  return 0;
+}
+#endif
+
+#ifdef CLIB_UNIX
+int
+main (int argc, char *argv[])
+{
+  unformat_input_t i;
+  int r;
+
+  unformat_init_command_line (&i, argv);
+  r = test_vhash_main (&i);
+  unformat_free (&i);
+  return r;
+}
+#endif
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */