1 /* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2023 Yandex LLC.
5 #ifdef CLIB_LINUX_KERNEL
6 #include <linux/unistd.h>
13 #include <vppinfra/time.h>
16 #include <vppinfra/random.h>
17 #include <vppinfra/mem.h>
18 #include <vppinfra/hash.h>
19 #include <vppinfra/mhash.h>
20 #include <vppinfra/error.h>
21 #include <vppinfra/format.h>
22 #include <vppinfra/bitmap.h>
25 #define if_verbose(format, args...) \
28 clib_warning (format, ##args); \
35 int n_iterations_per_print;
37 /* Number of pairs to insert into mhash. */
40 /* True to validate correctness of mhash functions. */
41 int n_iterations_per_validate;
43 /* Verbosity level for mhash formats. */
46 /* Random number seed. */
51 mhash_next_test (mhash_t *h)
53 hash_next_t hn = { 0 };
55 clib_error_t *error = 0;
57 hash_foreach_pair (p0, h->hash, {
58 p1 = hash_next (h->hash, &hn);
59 error = CLIB_ERROR_ASSERT (p0 == p1);
65 error = CLIB_ERROR_ASSERT (!hash_next (h->hash, &hn));
71 test_word_key (mhash_test_t *ht)
73 mhash_t _h = { 0 }, *h = &_h;
76 word *keys = 0, *vals = 0;
77 uword *is_inserted = 0;
79 clib_error_t *error = 0;
81 vec_resize (keys, ht->n_pairs);
82 vec_resize (vals, vec_len (keys));
84 mhash_init (h, sizeof (vals[0]), sizeof (keys[0]));
85 /* borrow 0 elt to make index keys non-zero */
86 vec_validate (h->key_vector_or_heap, 0);
92 for (i = 0; i < vec_len (keys); i++)
96 k = random_u32 (&ht->seed) & 0xfffff;
98 while (clib_bitmap_get (unique, k));
99 unique = clib_bitmap_ori (unique, k);
104 clib_bitmap_free (unique);
107 for (i = 0; i < ht->n_iterations; i++)
109 u32 vi = random_u32 (&ht->seed) % vec_len (keys);
111 if (clib_bitmap_get (is_inserted, vi))
113 mhash_unset (h, &keys[vi], 0);
114 mhash_unset (h, &keys[vi], 0);
118 mhash_set (h, &keys[vi], vals[vi], 0);
119 mhash_set (h, &keys[vi], vals[vi], 0);
122 is_inserted = clib_bitmap_xori (is_inserted, vi);
124 if (ht->n_iterations_per_print > 0 &&
125 ((i + 1) % ht->n_iterations_per_print) == 0)
126 if_verbose ("iteration %d\n %U", i + 1, format_mhash, h, ht->verbose);
128 if (ht->n_iterations_per_validate == 0 ||
129 (i + 1) % ht->n_iterations_per_validate)
135 mhash_foreach (k, v, h, {
137 ASSERT (keys[ki] == k[0]);
141 if ((error = hash_validate (h->hash)))
144 for (j = 0; j < vec_len (keys); j++)
147 v = mhash_get (h, &keys[j]);
148 if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
153 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
159 if ((error = mhash_next_test (h)))
162 if_verbose ("%U", format_mhash, h, ht->verbose);
164 for (i = 0; i < vec_len (keys); i++)
166 if (!clib_bitmap_get (is_inserted, i))
169 mhash_unset (h, &keys[i], 0);
170 mhash_unset (h, &keys[i], 0);
171 is_inserted = clib_bitmap_xori (is_inserted, i);
173 if (ht->n_iterations_per_validate == 0 ||
174 (i + 1) % ht->n_iterations_per_validate)
177 if ((error = hash_validate (h->hash)))
180 for (j = 0; j < vec_len (keys); j++)
183 v = mhash_get (h, &keys[j]);
184 if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
189 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
199 clib_bitmap_free (is_inserted);
202 fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0);
208 test2_format (u8 *s, va_list *args)
210 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
211 void *v = va_arg (*args, void *);
212 hash_pair_t *p = va_arg (*args, hash_pair_t *);
213 hash_t *h = hash_header (v);
214 mhash_t *mh = uword_to_pointer (h->user, mhash_t *);
216 return format (s, "0x%8U <- %U", format_hex_bytes, &p->value[0],
217 hash_value_bytes (h), format_mhash_key, mh, (u32) p->key);
220 static clib_error_t *
221 test_string_key (mhash_test_t *ht, uword is_c_string)
223 mhash_t _h = { 0 }, *h = &_h;
228 uword *is_inserted = 0;
230 clib_error_t *error = 0;
232 vec_resize (keys, ht->n_pairs);
233 vec_resize (vals, vec_len (keys));
236 mhash_init_c_string (h, sizeof (vals[0]));
238 mhash_init_vec_string (h, sizeof (vals[0]));
239 hash_set_pair_format (h->hash, test2_format, 0);
241 for (i = 0; i < vec_len (keys); i++)
243 keys[i] = random_string (&ht->seed, 5 + (random_u32 (&ht->seed) & 0xf));
244 keys[i] = format (keys[i], "%x", i);
246 vec_terminate_c_string (keys[i]);
247 vals[i] = random_u32 (&ht->seed);
250 for (i = 0; i < ht->n_iterations; i++)
252 u32 vi = random_u32 (&ht->seed) % vec_len (keys);
254 if (clib_bitmap_get (is_inserted, vi))
256 mhash_unset (h, keys[vi], 0);
257 mhash_unset (h, keys[vi], 0);
261 mhash_set (h, keys[vi], vals[vi], 0);
262 mhash_set (h, keys[vi], vals[vi], 0);
265 is_inserted = clib_bitmap_xori (is_inserted, vi);
267 if (ht->n_iterations_per_print > 0 &&
268 ((i + 1) % ht->n_iterations_per_print) == 0)
269 if_verbose ("iteration %d\n %U", i + 1, format_mhash, h, ht->verbose);
271 if (ht->n_iterations_per_validate == 0 ||
272 (i + 1) % ht->n_iterations_per_validate)
275 if ((error = hash_validate (h->hash)))
278 for (j = 0; j < vec_len (keys); j++)
281 v = mhash_get (h, keys[j]);
282 if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
287 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
293 if ((error = mhash_next_test (h)))
296 if_verbose ("%U", format_mhash, h, ht->verbose);
298 for (i = 0; i < vec_len (keys); i++)
300 if (!clib_bitmap_get (is_inserted, i))
303 mhash_unset (h, keys[i], 0);
304 mhash_unset (h, keys[i], 0);
305 is_inserted = clib_bitmap_xori (is_inserted, i);
307 if (ht->n_iterations_per_validate == 0 ||
308 (i + 1) % ht->n_iterations_per_validate)
311 if ((error = hash_validate (h->hash)))
314 for (j = 0; j < vec_len (keys); j++)
317 v = mhash_get (h, keys[j]);
318 if ((error = CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
323 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
332 clib_bitmap_free (is_inserted);
334 for (i = 0; i < vec_len (keys); i++)
339 fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0);
345 test_mhash_main (unformat_input_t *input)
347 mhash_test_t _ht = { 0 }, *ht = &_ht;
350 ht->n_iterations = 100;
353 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
355 if (0 == unformat (input, "iter %d", &ht->n_iterations) &&
356 0 == unformat (input, "print %d", &ht->n_iterations_per_print) &&
357 0 == unformat (input, "elts %d", &ht->n_pairs) &&
358 0 == unformat (input, "seed %d", &ht->seed) &&
359 0 == unformat (input, "verbose %=", &ht->verbose, 1) &&
360 0 == unformat (input, "valid %d", &ht->n_iterations_per_validate))
362 clib_warning ("unknown input `%U'", format_unformat_error, input);
368 ht->seed = random_default_seed ();
370 if_verbose ("testing %d iterations, seed %d", ht->n_iterations, ht->seed);
372 error = test_word_key (ht);
374 clib_error_report (error);
376 error = test_string_key (ht, 0);
378 clib_error_report (error);
380 error = test_string_key (ht, 1);
382 clib_error_report (error);
389 main (int argc, char *argv[])
394 clib_mem_init (0, 3ULL << 30);
396 verbose = (argc > 1);
397 unformat_init_command_line (&i, argv);
398 ret = test_mhash_main (&i);
403 #endif /* CLIB_UNIX */