2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
16 Copyright (c) 2010 Eliot Dresselhaus
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
44 #include <vppinfra/bitmap.h>
45 #include <vppinfra/error.h>
46 #include <vppinfra/os.h>
47 #include <vppinfra/random.h>
48 #include <vppinfra/time.h>
49 #include <vppinfra/vhash.h>
51 #ifdef CLIB_HAVE_VEC128
68 u32 *vhash_get_key_indices;
69 u32 *vhash_get_results;
71 u32 *vhash_key_indices;
83 } get_stats, set_stats, unset_stats;
87 test_vhash_key_gather (void *_tm, u32 vi, u32 wi, u32 n_key_u32s)
89 test_vhash_main_t *tm = _tm;
90 ASSERT (n_key_u32s == tm->n_key_u32);
91 ASSERT (wi < n_key_u32s);
92 vi = vec_elt (tm->vhash_key_indices, vi);
93 return vec_elt (tm->keys, vi * n_key_u32s + wi);
97 test_vhash_4key_gather (void *_tm, u32 vi, u32 wi, u32 n_key_u32s)
99 test_vhash_main_t *tm = _tm;
103 ASSERT (n_key_u32s == tm->n_key_u32);
104 ASSERT (wi < n_key_u32s);
106 p = vec_elt_at_index (tm->vhash_key_indices, vi + 0);
107 x.as_u32[0] = tm->keys[p[0] * n_key_u32s + wi];
108 x.as_u32[1] = tm->keys[p[1] * n_key_u32s + wi];
109 x.as_u32[2] = tm->keys[p[2] * n_key_u32s + wi];
110 x.as_u32[3] = tm->keys[p[3] * n_key_u32s + wi];
115 test_vhash_get_result (void *_tm,
116 u32 vector_index, u32 result_index, u32 n_key_u32s)
118 test_vhash_main_t *tm = _tm;
119 u32 *p = vec_elt_at_index (tm->vhash_results, vector_index);
125 test_vhash_get_4result (void *_tm,
126 u32 vector_index, u32x4 results, u32 n_key_u32s)
128 test_vhash_main_t *tm = _tm;
129 u32 *p = vec_elt_at_index (tm->vhash_results, vector_index);
130 *(u32x4 *) p = results;
135 test_vhash_set_result (void *_tm,
136 u32 vector_index, u32 old_result, u32 n_key_u32s)
138 test_vhash_main_t *tm = _tm;
139 u32 *p = vec_elt_at_index (tm->vhash_results, vector_index);
140 u32 new_result = p[0];
146 test_vhash_unset_result (void *_tm, u32 i, u32 old_result, u32 n_key_u32s)
148 test_vhash_main_t *tm = _tm;
149 u32 *p = vec_elt_at_index (tm->vhash_results, i);
154 #define _(N_KEY_U32) \
156 test_vhash_key_gather_##N_KEY_U32 (void * _tm, u32 vi, u32 i) \
157 { return test_vhash_key_gather (_tm, vi, i, N_KEY_U32); } \
159 always_inline u32x4 \
160 test_vhash_key_gather_4_##N_KEY_U32 (void * _tm, u32 vi, u32 i) \
161 { return test_vhash_4key_gather (_tm, vi, i, N_KEY_U32); } \
163 clib_pipeline_stage \
164 (test_vhash_gather_keys_stage_##N_KEY_U32, \
165 test_vhash_main_t *, tm, i, \
167 vhash_gather_4key_stage \
169 /* vector_index */ i, \
170 test_vhash_key_gather_4_##N_KEY_U32, \
175 clib_pipeline_stage_no_inline \
176 (test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
177 test_vhash_main_t *, tm, i, \
179 vhash_gather_key_stage \
181 /* vector_index */ tm->n_vectors_div_4, \
182 /* n_vectors */ tm->n_vectors_mod_4, \
183 test_vhash_key_gather_##N_KEY_U32, \
188 clib_pipeline_stage \
189 (test_vhash_hash_finalize_stage_##N_KEY_U32, \
190 test_vhash_main_t *, tm, i, \
192 vhash_finalize_stage (&tm->vhash, i, N_KEY_U32); \
195 clib_pipeline_stage_no_inline \
196 (test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
197 test_vhash_main_t *, tm, i, \
199 vhash_finalize_stage (&tm->vhash, tm->n_vectors_div_4, N_KEY_U32); \
202 clib_pipeline_stage \
203 (test_vhash_get_stage_##N_KEY_U32, \
204 test_vhash_main_t *, tm, i, \
206 vhash_get_4_stage (&tm->vhash, \
207 /* vector_index */ i, \
208 test_vhash_get_4result, \
212 clib_pipeline_stage_no_inline \
213 (test_vhash_get_mod_stage_##N_KEY_U32, \
214 test_vhash_main_t *, tm, i, \
216 vhash_get_stage (&tm->vhash, \
217 /* vector_index */ tm->n_vectors_div_4, \
218 /* n_vectors */ tm->n_vectors_mod_4, \
219 test_vhash_get_result, \
223 clib_pipeline_stage \
224 (test_vhash_set_stage_##N_KEY_U32, \
225 test_vhash_main_t *, tm, i, \
227 vhash_set_stage (&tm->vhash, \
228 /* vector_index */ i, \
229 /* n_vectors */ VECTOR_WORD_TYPE_LEN (u32), \
230 test_vhash_set_result, \
234 clib_pipeline_stage_no_inline \
235 (test_vhash_set_mod_stage_##N_KEY_U32, \
236 test_vhash_main_t *, tm, i, \
238 vhash_set_stage (&tm->vhash, \
239 /* vector_index */ tm->n_vectors_div_4, \
240 /* n_vectors */ tm->n_vectors_mod_4, \
241 test_vhash_set_result, \
245 clib_pipeline_stage \
246 (test_vhash_unset_stage_##N_KEY_U32, \
247 test_vhash_main_t *, tm, i, \
249 vhash_unset_stage (&tm->vhash, \
250 /* vector_index */ i, \
251 /* n_vectors */ VECTOR_WORD_TYPE_LEN (u32), \
252 test_vhash_unset_result, \
256 clib_pipeline_stage_no_inline \
257 (test_vhash_unset_mod_stage_##N_KEY_U32, \
258 test_vhash_main_t *, tm, i, \
260 vhash_unset_stage (&tm->vhash, \
261 /* vector_index */ tm->n_vectors_div_4, \
262 /* n_vectors */ tm->n_vectors_mod_4, \
263 test_vhash_unset_result, \
276 #define _(N_KEY_U32) \
277 clib_pipeline_stage \
278 (test_vhash_hash_mix_stage_##N_KEY_U32, \
279 test_vhash_main_t *, tm, i, \
281 vhash_mix_stage (&tm->vhash, i, N_KEY_U32); \
284 clib_pipeline_stage_no_inline \
285 (test_vhash_hash_mix_mod_stage_##N_KEY_U32, \
286 test_vhash_main_t *, tm, i, \
288 vhash_mix_stage (&tm->vhash, tm->n_vectors_div_4, N_KEY_U32); \
303 test_vhash_op (test_vhash_main_t * tm,
305 u32 * results, uword n_keys, test_vhash_op_t op)
307 vhash_validate_sizes (&tm->vhash, tm->n_key_u32, n_keys);
309 tm->vhash_results = results;
310 tm->vhash_key_indices = key_indices;
311 tm->n_vectors_div_4 = n_keys / 4;
312 tm->n_vectors_mod_4 = n_keys % 4;
314 if (tm->n_vectors_div_4 > 0)
316 switch (tm->n_key_u32)
322 #define _(N_KEY_U32) \
325 clib_pipeline_run_3_stage \
326 (tm->n_vectors_div_4, \
328 test_vhash_gather_keys_stage_##N_KEY_U32, \
329 test_vhash_hash_finalize_stage_##N_KEY_U32, \
330 test_vhash_get_stage_##N_KEY_U32); \
331 else if (op == SET) \
332 clib_pipeline_run_3_stage \
333 (tm->n_vectors_div_4, \
335 test_vhash_gather_keys_stage_##N_KEY_U32, \
336 test_vhash_hash_finalize_stage_##N_KEY_U32, \
337 test_vhash_set_stage_##N_KEY_U32); \
339 clib_pipeline_run_3_stage \
340 (tm->n_vectors_div_4, \
342 test_vhash_gather_keys_stage_##N_KEY_U32, \
343 test_vhash_hash_finalize_stage_##N_KEY_U32, \
344 test_vhash_unset_stage_##N_KEY_U32); \
353 #define _(N_KEY_U32) \
356 clib_pipeline_run_4_stage \
357 (tm->n_vectors_div_4, \
359 test_vhash_gather_keys_stage_##N_KEY_U32, \
360 test_vhash_hash_mix_stage_##N_KEY_U32, \
361 test_vhash_hash_finalize_stage_##N_KEY_U32, \
362 test_vhash_get_stage_##N_KEY_U32); \
363 else if (op == SET) \
364 clib_pipeline_run_4_stage \
365 (tm->n_vectors_div_4, \
367 test_vhash_gather_keys_stage_##N_KEY_U32, \
368 test_vhash_hash_mix_stage_##N_KEY_U32, \
369 test_vhash_hash_finalize_stage_##N_KEY_U32, \
370 test_vhash_set_stage_##N_KEY_U32); \
372 clib_pipeline_run_4_stage \
373 (tm->n_vectors_div_4, \
375 test_vhash_gather_keys_stage_##N_KEY_U32, \
376 test_vhash_hash_mix_stage_##N_KEY_U32, \
377 test_vhash_hash_finalize_stage_##N_KEY_U32, \
378 test_vhash_unset_stage_##N_KEY_U32); \
390 if (tm->n_vectors_mod_4 > 0)
392 switch (tm->n_key_u32)
398 #define _(N_KEY_U32) \
401 clib_pipeline_run_3_stage \
404 test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
405 test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
406 test_vhash_get_mod_stage_##N_KEY_U32); \
407 else if (op == SET) \
408 clib_pipeline_run_3_stage \
411 test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
412 test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
413 test_vhash_set_mod_stage_##N_KEY_U32); \
415 clib_pipeline_run_3_stage \
418 test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
419 test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
420 test_vhash_unset_mod_stage_##N_KEY_U32); \
429 #define _(N_KEY_U32) \
432 clib_pipeline_run_4_stage \
435 test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
436 test_vhash_hash_mix_mod_stage_##N_KEY_U32, \
437 test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
438 test_vhash_get_mod_stage_##N_KEY_U32); \
439 else if (op == SET) \
440 clib_pipeline_run_4_stage \
443 test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
444 test_vhash_hash_mix_mod_stage_##N_KEY_U32, \
445 test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
446 test_vhash_set_mod_stage_##N_KEY_U32); \
448 clib_pipeline_run_4_stage \
451 test_vhash_gather_keys_mod_stage_##N_KEY_U32, \
452 test_vhash_hash_mix_mod_stage_##N_KEY_U32, \
453 test_vhash_hash_finalize_mod_stage_##N_KEY_U32, \
454 test_vhash_unset_mod_stage_##N_KEY_U32); \
467 test_vhash_main (unformat_input_t * input)
469 clib_error_t *error = 0;
470 test_vhash_main_t _tm, *tm = &_tm;
471 vhash_t *vh = &tm->vhash;
474 memset (tm, 0, sizeof (tm[0]));
482 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
484 if (unformat (input, "iter %d", &tm->n_iter))
486 else if (unformat (input, "seed %d", &tm->seed))
488 else if (unformat (input, "n-keys %d", &tm->n_keys))
490 else if (unformat (input, "log2-size %d", &tm->log2_size))
492 else if (unformat (input, "key-words %d", &tm->n_key_u32))
494 else if (unformat (input, "verbose %=", &tm->verbose, 1))
498 error = clib_error_create ("unknown input `%U'\n",
499 format_unformat_error, input);
505 tm->seed = random_default_seed ();
507 clib_warning ("iter %d seed %d n-keys %d log2-size %d key-words %d",
508 tm->n_iter, tm->seed, tm->n_keys, tm->log2_size,
513 seeds[0] = seeds[1] = seeds[2] = 0xdeadbeef;
514 vhash_init (vh, tm->log2_size, tm->n_key_u32, seeds);
517 /* Choose unique keys. */
518 vec_resize (tm->keys, tm->n_keys * tm->n_key_u32);
519 vec_resize (tm->key_hash, tm->n_key_u32);
520 for (i = j = 0; i < vec_len (tm->keys); i++, j++)
522 j = j == tm->n_key_u32 ? 0 : j;
525 tm->keys[i] = random_u32 (&tm->seed);
527 while (hash_get (tm->key_hash[j], tm->keys[i]));
528 hash_set (tm->key_hash[j], tm->keys[i], 0);
531 vec_resize (tm->results, tm->n_keys);
532 for (i = 0; i < vec_len (tm->results); i++)
536 tm->results[i] = random_u32 (&tm->seed);
538 while (tm->results[i] == ~0);
541 vec_resize_aligned (tm->vhash_get_results, tm->n_keys,
542 CLIB_CACHE_LINE_BYTES);
543 vec_clone (tm->vhash_get_key_indices, tm->results);
544 for (i = 0; i < vec_len (tm->vhash_get_key_indices); i++)
545 tm->vhash_get_key_indices[i] = i;
548 uword *is_set_bitmap = 0;
549 uword *to_set_bitmap = 0;
550 uword *to_unset_bitmap = 0;
551 u32 *to_set = 0, *to_unset = 0;
552 u32 *to_set_results = 0, *to_unset_results = 0;
555 for (i = 0; i < tm->n_iter; i++)
557 vec_reset_length (to_set);
558 vec_reset_length (to_unset);
559 vec_reset_length (to_set_results);
560 vec_reset_length (to_unset_results);
564 to_set_bitmap = clib_bitmap_random (to_set_bitmap,
565 tm->n_keys, &tm->seed);
567 while (clib_bitmap_is_zero (to_set_bitmap));
568 to_unset_bitmap = clib_bitmap_dup_and (to_set_bitmap, is_set_bitmap);
569 to_set_bitmap = clib_bitmap_andnot (to_set_bitmap, to_unset_bitmap);
572 clib_bitmap_foreach (j, to_set_bitmap, ({
573 vec_add1 (to_set, j);
574 vec_add1 (to_set_results, tm->results[j]);
578 clib_bitmap_foreach (j, to_unset_bitmap, ({
579 vec_add1 (to_unset, j);
580 vec_add1 (to_unset_results, 0xdeadbeef);
584 if (vec_len (to_set) > 0)
586 t[0] = clib_cpu_time_now ();
587 test_vhash_op (tm, to_set, to_set_results, vec_len (to_set), SET);
588 t[1] = clib_cpu_time_now ();
589 tm->set_stats.n_clocks += t[1] - t[0];
590 tm->set_stats.n_vectors += vec_len (to_set);
591 tm->set_stats.n_calls += 1;
592 is_set_bitmap = clib_bitmap_or (is_set_bitmap, to_set_bitmap);
595 t[0] = clib_cpu_time_now ();
596 test_vhash_op (tm, tm->vhash_get_key_indices,
597 tm->vhash_get_results,
598 vec_len (tm->vhash_get_key_indices), GET);
599 t[1] = clib_cpu_time_now ();
600 tm->get_stats.n_clocks += t[1] - t[0];
601 tm->get_stats.n_vectors += vec_len (tm->vhash_get_key_indices);
602 tm->get_stats.n_calls += 1;
604 for (j = 0; j < vec_len (tm->vhash_get_results); j++)
606 u32 r0 = tm->vhash_get_results[j];
607 u32 r1 = tm->results[j];
608 if (clib_bitmap_get (is_set_bitmap, j))
620 if (vh->n_elts != clib_bitmap_count_set_bits (is_set_bitmap))
623 if (vec_len (to_unset) > 0)
625 t[0] = clib_cpu_time_now ();
626 test_vhash_op (tm, to_unset, to_unset_results,
627 vec_len (to_unset), UNSET);
628 t[1] = clib_cpu_time_now ();
629 tm->unset_stats.n_clocks += t[1] - t[0];
630 tm->unset_stats.n_vectors += vec_len (to_unset);
631 tm->unset_stats.n_calls += 1;
633 clib_bitmap_andnot (is_set_bitmap, to_unset_bitmap);
636 t[0] = clib_cpu_time_now ();
637 test_vhash_op (tm, tm->vhash_get_key_indices,
638 tm->vhash_get_results,
639 vec_len (tm->vhash_get_key_indices), GET);
640 t[1] = clib_cpu_time_now ();
641 tm->get_stats.n_clocks += t[1] - t[0];
642 tm->get_stats.n_vectors += vec_len (tm->vhash_get_key_indices);
643 tm->get_stats.n_calls += 1;
645 for (j = 0; j < vec_len (tm->vhash_get_results); j++)
647 u32 r0 = tm->vhash_get_results[j];
648 u32 r1 = tm->results[j];
649 if (clib_bitmap_get (is_set_bitmap, j))
661 if (vh->n_elts != clib_bitmap_count_set_bits (is_set_bitmap))
665 vhash_resize (vh, tm->log2_size + 1);
667 test_vhash_op (tm, tm->vhash_get_key_indices,
668 tm->vhash_get_results,
669 vec_len (tm->vhash_get_key_indices), GET);
671 for (j = 0; j < vec_len (tm->vhash_get_results); j++)
673 u32 r0 = tm->vhash_get_results[j];
674 u32 r1 = tm->results[j];
675 if (clib_bitmap_get (is_set_bitmap, j))
687 if (vh->n_elts != clib_bitmap_count_set_bits (is_set_bitmap))
694 clib_time_init (&ct);
696 clib_warning ("%.4e clocks/get %.4e gets/call %.4e gets/sec",
697 (f64) tm->get_stats.n_clocks /
698 (f64) tm->get_stats.n_vectors,
699 (f64) tm->get_stats.n_vectors / (f64) tm->get_stats.n_calls,
700 (f64) tm->get_stats.n_vectors /
701 (f64) (tm->get_stats.n_clocks * ct.seconds_per_clock));
702 if (tm->set_stats.n_calls > 0)
703 clib_warning ("%.4e clocks/set %.4e sets/call %.4e sets/sec",
704 (f64) tm->set_stats.n_clocks /
705 (f64) tm->set_stats.n_vectors,
706 (f64) tm->set_stats.n_vectors /
707 (f64) tm->set_stats.n_calls,
708 (f64) tm->set_stats.n_vectors /
709 (f64) (tm->set_stats.n_clocks * ct.seconds_per_clock));
710 if (tm->unset_stats.n_calls > 0)
711 clib_warning ("%.4e clocks/unset %.4e unsets/call %.4e unsets/sec",
712 (f64) tm->unset_stats.n_clocks /
713 (f64) tm->unset_stats.n_vectors,
714 (f64) tm->unset_stats.n_vectors /
715 (f64) tm->unset_stats.n_calls,
716 (f64) tm->unset_stats.n_vectors /
717 (f64) (tm->unset_stats.n_clocks * ct.seconds_per_clock));
722 clib_error_report (error);
726 #endif /* CLIB_HAVE_VEC128 */
728 #ifndef CLIB_HAVE_VEC128
730 test_vhash_main (unformat_input_t * input)
732 clib_error ("compiled without vector support");
739 main (int argc, char *argv[])
744 unformat_init_command_line (&i, argv);
745 r = test_vhash_main (&i);
752 * fd.io coding-style-patch-verification: ON
755 * eval: (c-set-style "gnu")