blob: 95ced448c13d108cc12d118ef45de4fc990b4086 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15/*
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
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:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
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.
36*/
37
38#ifdef CLIB_LINUX_KERNEL
39#include <linux/unistd.h>
40#endif
41
42#ifdef CLIB_UNIX
43#include <unistd.h>
44#include <stdlib.h>
45#include <stdio.h>
46#include <vppinfra/time.h>
47#endif
48
49#include <vppinfra/random.h>
50#include <vppinfra/mem.h>
51#include <vppinfra/hash.h>
52#include <vppinfra/error.h>
53#include <vppinfra/format.h>
54#include <vppinfra/bitmap.h>
55
56static int verbose;
57#define if_verbose(format,args...) \
58 if (verbose) { clib_warning(format, ## args); }
59
Dave Barachc3799992016-08-15 11:12:27 -040060typedef struct
61{
Ed Warnickecb9cada2015-12-08 15:45:58 -070062 int n_iterations;
63
64 int n_iterations_per_print;
65
66 /* Number of pairs to insert into hash. */
67 int n_pairs;
68
69 /* True to validate correctness of hash functions. */
70 int n_iterations_per_validate;
71
72 /* Non-zero if hash table size is to be fixed. */
73 int fixed_hash_size;
74
75 /* Verbosity level for hash formats. */
76 int verbose;
77
78 /* Random number seed. */
79 u32 seed;
80} hash_test_t;
81
Dave Barachc3799992016-08-15 11:12:27 -040082static clib_error_t *
83hash_next_test (word * h)
Ed Warnickecb9cada2015-12-08 15:45:58 -070084{
Dave Barachc3799992016-08-15 11:12:27 -040085 hash_next_t hn = { 0 };
86 hash_pair_t *p0, *p1;
87 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070088
Dave Barachc3799992016-08-15 11:12:27 -040089 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 hash_foreach_pair (p0, h, {
91 p1 = hash_next (h, &hn);
92 error = CLIB_ERROR_ASSERT (p0 == p1);
93 if (error)
94 break;
95 });
Dave Barachc3799992016-08-15 11:12:27 -040096 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070097
Dave Barachc3799992016-08-15 11:12:27 -040098 if (!error)
99 error = CLIB_ERROR_ASSERT (!hash_next (h, &hn));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
101 return error;
102}
103
Dave Barachc3799992016-08-15 11:12:27 -0400104static u8 *
105test1_format (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106{
Dave Barachc3799992016-08-15 11:12:27 -0400107 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
108 void *v = va_arg (*args, void *);
109 hash_pair_t *p = va_arg (*args, hash_pair_t *);
110 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111
112 return format (s, "0x%8U -> 0x%8U",
113 format_hex_bytes, &p->key, sizeof (p->key),
114 format_hex_bytes, &p->value[0], hash_value_bytes (h));
115}
116
Dave Barachc3799992016-08-15 11:12:27 -0400117static clib_error_t *
118test_word_key (hash_test_t * ht)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119{
Dave Barachc3799992016-08-15 11:12:27 -0400120 word *h = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121 word i, j;
122
Dave Barachc3799992016-08-15 11:12:27 -0400123 word *keys = 0, *vals = 0;
124 uword *is_inserted = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125
Dave Barachc3799992016-08-15 11:12:27 -0400126 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127
128 vec_resize (keys, ht->n_pairs);
129 vec_resize (vals, vec_len (keys));
130
131 h = hash_create (ht->fixed_hash_size, sizeof (vals[0]));
132
133 hash_set_pair_format (h, test1_format, 0);
134 if (ht->fixed_hash_size)
135 hash_set_flags (h, HASH_FLAG_NO_AUTO_GROW | HASH_FLAG_NO_AUTO_SHRINK);
136
137 {
Dave Barachc3799992016-08-15 11:12:27 -0400138 uword *unique = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139 u32 k;
140
141 for (i = 0; i < vec_len (keys); i++)
142 {
Dave Barachc3799992016-08-15 11:12:27 -0400143 do
144 {
145 k = random_u32 (&ht->seed) & 0xfffff;
146 }
147 while (clib_bitmap_get (unique, k));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148 unique = clib_bitmap_ori (unique, k);
149 keys[i] = k;
150 vals[i] = i;
151 }
152
153 clib_bitmap_free (unique);
154 }
155
156 for (i = 0; i < ht->n_iterations; i++)
157 {
158 u32 vi = random_u32 (&ht->seed) % vec_len (keys);
159
160 if (clib_bitmap_get (is_inserted, vi))
161 hash_unset (h, keys[vi]);
162 else
163 hash_set (h, keys[vi], vals[vi]);
164
165 is_inserted = clib_bitmap_xori (is_inserted, vi);
166
167 if (ht->n_iterations_per_print > 0
168 && ((i + 1) % ht->n_iterations_per_print) == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400169 if_verbose ("iteration %d\n %U", i + 1, format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170
171 if (ht->n_iterations_per_validate == 0
172 || (i + 1) % ht->n_iterations_per_validate)
173 continue;
174
175 {
Dave Barachc3799992016-08-15 11:12:27 -0400176 hash_pair_t *p;
177 uword ki;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178
Dave Barachc3799992016-08-15 11:12:27 -0400179 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180 hash_foreach_pair (p, h, {
181 ki = p->value[0];
182 ASSERT (keys[ki] == p->key);
183 });
Dave Barachc3799992016-08-15 11:12:27 -0400184 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185 }
186
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 if ((error = hash_validate (h)))
188 goto done;
189
190 for (j = 0; j < vec_len (keys); j++)
191 {
Dave Barachc3799992016-08-15 11:12:27 -0400192 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 v = hash_get (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400194 if ((error =
195 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
196 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400198 if (v)
199 {
200 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
201 goto done;
202 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 }
204 }
205
206 if ((error = hash_next_test (h)))
207 goto done;
208
Dave Barachc3799992016-08-15 11:12:27 -0400209 if_verbose ("%U", format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210
211 for (i = 0; i < vec_len (keys); i++)
212 {
Dave Barachc3799992016-08-15 11:12:27 -0400213 if (!clib_bitmap_get (is_inserted, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214 continue;
215
216 hash_unset (h, keys[i]);
217 is_inserted = clib_bitmap_xori (is_inserted, i);
218
219 if (ht->n_iterations_per_validate == 0
220 || (i + 1) % ht->n_iterations_per_validate)
221 continue;
222
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223 if ((error = hash_validate (h)))
224 goto done;
225
226 for (j = 0; j < vec_len (keys); j++)
227 {
Dave Barachc3799992016-08-15 11:12:27 -0400228 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229 v = hash_get (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400230 if ((error =
231 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
232 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400234 if (v)
235 {
236 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
237 goto done;
238 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 }
240 }
241
Dave Barachc3799992016-08-15 11:12:27 -0400242done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 hash_free (h);
244 vec_free (keys);
245 vec_free (vals);
246 clib_bitmap_free (is_inserted);
247
Dave Barachc3799992016-08-15 11:12:27 -0400248 if (verbose)
249 fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250
251 return error;
252}
253
Dave Barachc3799992016-08-15 11:12:27 -0400254static u8 *
255test2_format (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256{
Dave Barachc3799992016-08-15 11:12:27 -0400257 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
258 void *v = va_arg (*args, void *);
259 hash_pair_t *p = va_arg (*args, hash_pair_t *);
260 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
262 return format (s, "0x%8U <- %v",
263 format_hex_bytes, &p->value[0], hash_value_bytes (h),
264 p->key);
265}
266
Dave Barachc3799992016-08-15 11:12:27 -0400267static clib_error_t *
268test_string_key (hash_test_t * ht)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269{
270 word i, j;
271
Dave Barachc3799992016-08-15 11:12:27 -0400272 u8 **keys = 0;
273 word *vals = 0;
274 uword *is_inserted = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275
Dave Barachc3799992016-08-15 11:12:27 -0400276 word *h = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277
Dave Barachc3799992016-08-15 11:12:27 -0400278 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
280 vec_resize (keys, ht->n_pairs);
281 vec_resize (vals, vec_len (keys));
282
Dave Barachc3799992016-08-15 11:12:27 -0400283 h =
284 hash_create_vec (ht->fixed_hash_size, sizeof (keys[0][0]),
285 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286 hash_set_pair_format (h, test2_format, 0);
287 if (ht->fixed_hash_size)
288 hash_set_flags (h, HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_NO_AUTO_GROW);
289
290 for (i = 0; i < vec_len (keys); i++)
291 {
Dave Barachc3799992016-08-15 11:12:27 -0400292 keys[i] = random_string (&ht->seed, 5 + (random_u32 (&ht->seed) & 0xf));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 keys[i] = format (keys[i], "%x", i);
294 vals[i] = random_u32 (&ht->seed);
295 }
296
297 for (i = 0; i < ht->n_iterations; i++)
298 {
299 u32 vi = random_u32 (&ht->seed) % vec_len (keys);
300
301 if (clib_bitmap_get (is_inserted, vi))
302 hash_unset_mem (h, keys[vi]);
303 else
304 hash_set_mem (h, keys[vi], vals[vi]);
305
306 is_inserted = clib_bitmap_xori (is_inserted, vi);
307
308 if (ht->n_iterations_per_print > 0
309 && ((i + 1) % ht->n_iterations_per_print) == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400310 if_verbose ("iteration %d\n %U", i + 1, format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311
312 if (ht->n_iterations_per_validate == 0
313 || (i + 1) % ht->n_iterations_per_validate)
314 continue;
315
Ed Warnickecb9cada2015-12-08 15:45:58 -0700316 if ((error = hash_validate (h)))
317 goto done;
318
319 for (j = 0; j < vec_len (keys); j++)
320 {
Dave Barachc3799992016-08-15 11:12:27 -0400321 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700322 v = hash_get_mem (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400323 if ((error =
324 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
325 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400327 if (v)
328 {
329 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
330 goto done;
331 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332 }
333 }
334
335 if ((error = hash_next_test (h)))
336 goto done;
337
Dave Barachc3799992016-08-15 11:12:27 -0400338 if_verbose ("%U", format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
340 for (i = 0; i < vec_len (keys); i++)
341 {
Dave Barachc3799992016-08-15 11:12:27 -0400342 if (!clib_bitmap_get (is_inserted, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 continue;
344
345 hash_unset_mem (h, keys[i]);
346 is_inserted = clib_bitmap_xori (is_inserted, i);
347
348 if (ht->n_iterations_per_validate == 0
349 || (i + 1) % ht->n_iterations_per_validate)
350 continue;
351
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 if ((error = hash_validate (h)))
353 goto done;
354
355 for (j = 0; j < vec_len (keys); j++)
356 {
Dave Barachc3799992016-08-15 11:12:27 -0400357 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358 v = hash_get_mem (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400359 if ((error =
360 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
361 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400363 if (v)
364 {
365 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
366 goto done;
367 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 }
369 }
370
Dave Barachc3799992016-08-15 11:12:27 -0400371done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700372 hash_free (h);
373 vec_free (vals);
374 clib_bitmap_free (is_inserted);
375
376 for (i = 0; i < vec_len (keys); i++)
377 vec_free (keys[i]);
378 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -0400379
380 if (verbose)
381 fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
383 return error;
384}
385
Dave Barachc3799992016-08-15 11:12:27 -0400386int
387test_hash_main (unformat_input_t * input)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388{
Dave Barachc3799992016-08-15 11:12:27 -0400389 hash_test_t _ht = { 0 }, *ht = &_ht;
390 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391
392 ht->n_iterations = 100;
393 ht->n_pairs = 10;
394 ht->fixed_hash_size = 0; /* zero means non-fixed size */
395
396 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
397 {
398 if (0 == unformat (input, "iter %d", &ht->n_iterations)
399 && 0 == unformat (input, "print %d", &ht->n_iterations_per_print)
400 && 0 == unformat (input, "elts %d", &ht->n_pairs)
401 && 0 == unformat (input, "size %d", &ht->fixed_hash_size)
402 && 0 == unformat (input, "seed %d", &ht->seed)
403 && 0 == unformat (input, "verbose %=", &ht->verbose, 1)
Dave Barachc3799992016-08-15 11:12:27 -0400404 && 0 == unformat (input, "valid %d",
405 &ht->n_iterations_per_validate))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406 {
407 clib_warning ("unknown input `%U'", format_unformat_error, input);
408 return 1;
409 }
410 }
411
Dave Barachc3799992016-08-15 11:12:27 -0400412 if (!ht->seed)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413 ht->seed = random_default_seed ();
414
Dave Barachc3799992016-08-15 11:12:27 -0400415 if_verbose ("testing %d iterations, seed %d", ht->n_iterations, ht->seed);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700416
417 error = test_word_key (ht);
418 if (error)
419 clib_error_report (error);
420
421 error = test_string_key (ht);
422 if (error)
423 clib_error_report (error);
424
425 return 0;
426}
427
428#ifdef CLIB_UNIX
Dave Barachc3799992016-08-15 11:12:27 -0400429int
430main (int argc, char *argv[])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431{
432 unformat_input_t i;
433 int ret;
434
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200435 clib_mem_init (0, 3ULL << 30);
436
Ed Warnickecb9cada2015-12-08 15:45:58 -0700437 verbose = (argc > 1);
438 unformat_init_command_line (&i, argv);
439 ret = test_hash_main (&i);
440 unformat_free (&i);
441
442 return ret;
443}
444#endif /* CLIB_UNIX */
Dave Barachc3799992016-08-15 11:12:27 -0400445
446/*
447 * fd.io coding-style-patch-verification: ON
448 *
449 * Local Variables:
450 * eval: (c-set-style "gnu")
451 * End:
452 */