blob: 7f047d9ec7865168e24408bd0962dd74b948ffcb [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
187 clib_mem_validate ();
188
189 if ((error = hash_validate (h)))
190 goto done;
191
192 for (j = 0; j < vec_len (keys); j++)
193 {
Dave Barachc3799992016-08-15 11:12:27 -0400194 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 v = hash_get (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400196 if ((error =
197 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
198 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400200 if (v)
201 {
202 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
203 goto done;
204 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 }
206 }
207
208 if ((error = hash_next_test (h)))
209 goto done;
210
Dave Barachc3799992016-08-15 11:12:27 -0400211 if_verbose ("%U", format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
213 for (i = 0; i < vec_len (keys); i++)
214 {
Dave Barachc3799992016-08-15 11:12:27 -0400215 if (!clib_bitmap_get (is_inserted, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216 continue;
217
218 hash_unset (h, keys[i]);
219 is_inserted = clib_bitmap_xori (is_inserted, i);
220
221 if (ht->n_iterations_per_validate == 0
222 || (i + 1) % ht->n_iterations_per_validate)
223 continue;
224
225 clib_mem_validate ();
226
227 if ((error = hash_validate (h)))
228 goto done;
229
230 for (j = 0; j < vec_len (keys); j++)
231 {
Dave Barachc3799992016-08-15 11:12:27 -0400232 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233 v = hash_get (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400234 if ((error =
235 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
236 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400238 if (v)
239 {
240 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
241 goto done;
242 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 }
244 }
245
Dave Barachc3799992016-08-15 11:12:27 -0400246done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 hash_free (h);
248 vec_free (keys);
249 vec_free (vals);
250 clib_bitmap_free (is_inserted);
251
Dave Barachc3799992016-08-15 11:12:27 -0400252 if (verbose)
253 fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
255 return error;
256}
257
Dave Barachc3799992016-08-15 11:12:27 -0400258static u8 *
259test2_format (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260{
Dave Barachc3799992016-08-15 11:12:27 -0400261 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
262 void *v = va_arg (*args, void *);
263 hash_pair_t *p = va_arg (*args, hash_pair_t *);
264 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
266 return format (s, "0x%8U <- %v",
267 format_hex_bytes, &p->value[0], hash_value_bytes (h),
268 p->key);
269}
270
Dave Barachc3799992016-08-15 11:12:27 -0400271static clib_error_t *
272test_string_key (hash_test_t * ht)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273{
274 word i, j;
275
Dave Barachc3799992016-08-15 11:12:27 -0400276 u8 **keys = 0;
277 word *vals = 0;
278 uword *is_inserted = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700279
Dave Barachc3799992016-08-15 11:12:27 -0400280 word *h = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281
Dave Barachc3799992016-08-15 11:12:27 -0400282 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283
284 vec_resize (keys, ht->n_pairs);
285 vec_resize (vals, vec_len (keys));
286
Dave Barachc3799992016-08-15 11:12:27 -0400287 h =
288 hash_create_vec (ht->fixed_hash_size, sizeof (keys[0][0]),
289 sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290 hash_set_pair_format (h, test2_format, 0);
291 if (ht->fixed_hash_size)
292 hash_set_flags (h, HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_NO_AUTO_GROW);
293
294 for (i = 0; i < vec_len (keys); i++)
295 {
Dave Barachc3799992016-08-15 11:12:27 -0400296 keys[i] = random_string (&ht->seed, 5 + (random_u32 (&ht->seed) & 0xf));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297 keys[i] = format (keys[i], "%x", i);
298 vals[i] = random_u32 (&ht->seed);
299 }
300
301 for (i = 0; i < ht->n_iterations; i++)
302 {
303 u32 vi = random_u32 (&ht->seed) % vec_len (keys);
304
305 if (clib_bitmap_get (is_inserted, vi))
306 hash_unset_mem (h, keys[vi]);
307 else
308 hash_set_mem (h, keys[vi], vals[vi]);
309
310 is_inserted = clib_bitmap_xori (is_inserted, vi);
311
312 if (ht->n_iterations_per_print > 0
313 && ((i + 1) % ht->n_iterations_per_print) == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400314 if_verbose ("iteration %d\n %U", i + 1, format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315
316 if (ht->n_iterations_per_validate == 0
317 || (i + 1) % ht->n_iterations_per_validate)
318 continue;
319
320 clib_mem_validate ();
321
322 if ((error = hash_validate (h)))
323 goto done;
324
325 for (j = 0; j < vec_len (keys); j++)
326 {
Dave Barachc3799992016-08-15 11:12:27 -0400327 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328 v = hash_get_mem (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400329 if ((error =
330 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
331 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400333 if (v)
334 {
335 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
336 goto done;
337 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338 }
339 }
340
341 if ((error = hash_next_test (h)))
342 goto done;
343
Dave Barachc3799992016-08-15 11:12:27 -0400344 if_verbose ("%U", format_hash, h, ht->verbose);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345
346 for (i = 0; i < vec_len (keys); i++)
347 {
Dave Barachc3799992016-08-15 11:12:27 -0400348 if (!clib_bitmap_get (is_inserted, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 continue;
350
351 hash_unset_mem (h, keys[i]);
352 is_inserted = clib_bitmap_xori (is_inserted, i);
353
354 if (ht->n_iterations_per_validate == 0
355 || (i + 1) % ht->n_iterations_per_validate)
356 continue;
357
358 clib_mem_validate ();
359
360 if ((error = hash_validate (h)))
361 goto done;
362
363 for (j = 0; j < vec_len (keys); j++)
364 {
Dave Barachc3799992016-08-15 11:12:27 -0400365 uword *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366 v = hash_get_mem (h, keys[j]);
Dave Barachc3799992016-08-15 11:12:27 -0400367 if ((error =
368 CLIB_ERROR_ASSERT (clib_bitmap_get (is_inserted, j) ==
369 (v != 0))))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370 goto done;
Dave Barachc3799992016-08-15 11:12:27 -0400371 if (v)
372 {
373 if ((error = CLIB_ERROR_ASSERT (v[0] == vals[j])))
374 goto done;
375 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 }
377 }
378
Dave Barachc3799992016-08-15 11:12:27 -0400379done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380 hash_free (h);
381 vec_free (vals);
382 clib_bitmap_free (is_inserted);
383
384 for (i = 0; i < vec_len (keys); i++)
385 vec_free (keys[i]);
386 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -0400387
388 if (verbose)
389 fformat (stderr, "%U\n", format_clib_mem_usage, /* verbose */ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390
391 return error;
392}
393
Dave Barachc3799992016-08-15 11:12:27 -0400394int
395test_hash_main (unformat_input_t * input)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396{
Dave Barachc3799992016-08-15 11:12:27 -0400397 hash_test_t _ht = { 0 }, *ht = &_ht;
398 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399
400 ht->n_iterations = 100;
401 ht->n_pairs = 10;
402 ht->fixed_hash_size = 0; /* zero means non-fixed size */
403
404 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
405 {
406 if (0 == unformat (input, "iter %d", &ht->n_iterations)
407 && 0 == unformat (input, "print %d", &ht->n_iterations_per_print)
408 && 0 == unformat (input, "elts %d", &ht->n_pairs)
409 && 0 == unformat (input, "size %d", &ht->fixed_hash_size)
410 && 0 == unformat (input, "seed %d", &ht->seed)
411 && 0 == unformat (input, "verbose %=", &ht->verbose, 1)
Dave Barachc3799992016-08-15 11:12:27 -0400412 && 0 == unformat (input, "valid %d",
413 &ht->n_iterations_per_validate))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700414 {
415 clib_warning ("unknown input `%U'", format_unformat_error, input);
416 return 1;
417 }
418 }
419
Dave Barachc3799992016-08-15 11:12:27 -0400420 if (!ht->seed)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 ht->seed = random_default_seed ();
422
Dave Barachc3799992016-08-15 11:12:27 -0400423 if_verbose ("testing %d iterations, seed %d", ht->n_iterations, ht->seed);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700424
425 error = test_word_key (ht);
426 if (error)
427 clib_error_report (error);
428
429 error = test_string_key (ht);
430 if (error)
431 clib_error_report (error);
432
433 return 0;
434}
435
436#ifdef CLIB_UNIX
Dave Barachc3799992016-08-15 11:12:27 -0400437int
438main (int argc, char *argv[])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439{
440 unformat_input_t i;
441 int ret;
442
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200443 clib_mem_init (0, 3ULL << 30);
444
Ed Warnickecb9cada2015-12-08 15:45:58 -0700445 verbose = (argc > 1);
446 unformat_init_command_line (&i, argv);
447 ret = test_hash_main (&i);
448 unformat_free (&i);
449
450 return ret;
451}
452#endif /* CLIB_UNIX */
Dave Barachc3799992016-08-15 11:12:27 -0400453
454/*
455 * fd.io coding-style-patch-verification: ON
456 *
457 * Local Variables:
458 * eval: (c-set-style "gnu")
459 * End:
460 */