API refactoring : l2, mpls, sr
[vpp.git] / src / vppinfra / test_bihash_template.c
1 /*
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 #include <vppinfra/time.h>
16 #include <vppinfra/cache.h>
17 #include <vppinfra/error.h>
18
19 #include <vppinfra/bihash_8_8.h>
20 #include <vppinfra/bihash_template.h>
21
22 #include <vppinfra/bihash_template.c>
23
24 typedef struct
25 {
26   u64 seed;
27   u32 nbuckets;
28   u32 nitems;
29   u32 search_iter;
30   int careful_delete_tests;
31   int verbose;
32   int non_random_keys;
33   uword *key_hash;
34   u64 *keys;
35     BVT (clib_bihash) hash;
36   clib_time_t clib_time;
37
38   unformat_input_t *input;
39
40 } test_main_t;
41
42 test_main_t test_main;
43
44 uword
45 vl (void *v)
46 {
47   return vec_len (v);
48 }
49
50 static clib_error_t *
51 test_bihash (test_main_t * tm)
52 {
53   int i, j;
54   uword *p;
55   uword total_searches;
56   f64 before, delta;
57   BVT (clib_bihash) * h;
58   BVT (clib_bihash_kv) kv;
59
60   h = &tm->hash;
61
62   BV (clib_bihash_init) (h, "test", tm->nbuckets, 3ULL << 30);
63
64   fformat (stdout, "Pick %lld unique %s keys...\n",
65            tm->nitems, tm->non_random_keys ? "non-random" : "random");
66
67   for (i = 0; i < tm->nitems; i++)
68     {
69       u64 rndkey;
70
71       if (tm->non_random_keys == 0)
72         {
73
74         again:
75           rndkey = random_u64 (&tm->seed);
76
77           p = hash_get (tm->key_hash, rndkey);
78           if (p)
79             goto again;
80         }
81       else
82         rndkey = (u64) (i + 1) << 16;
83
84       hash_set (tm->key_hash, rndkey, i + 1);
85       vec_add1 (tm->keys, rndkey);
86     }
87
88   fformat (stdout, "Add items...\n");
89   for (i = 0; i < tm->nitems; i++)
90     {
91       kv.key = tm->keys[i];
92       kv.value = i + 1;
93
94       BV (clib_bihash_add_del) (h, &kv, 1 /* is_add */ );
95
96       if (tm->verbose > 1)
97         {
98           fformat (stdout, "--------------------\n");
99           fformat (stdout, "After adding key %llu value %lld...\n",
100                    tm->keys[i], (u64) (i + 1));
101           fformat (stdout, "%U", BV (format_bihash), h,
102                    2 /* very verbose */ );
103         }
104     }
105
106   fformat (stdout, "%U", BV (format_bihash), h, 0 /* very verbose */ );
107
108   fformat (stdout, "Search for items %d times...\n", tm->search_iter);
109
110   before = clib_time_now (&tm->clib_time);
111
112   for (j = 0; j < tm->search_iter; j++)
113     {
114       for (i = 0; i < tm->nitems; i++)
115         {
116           kv.key = tm->keys[i];
117           if (BV (clib_bihash_search) (h, &kv, &kv) < 0)
118             if (BV (clib_bihash_search) (h, &kv, &kv) < 0)
119               clib_warning ("[%d] search for key %lld failed unexpectedly\n",
120                             i, tm->keys[i]);
121           if (kv.value != (u64) (i + 1))
122             clib_warning
123               ("[%d] search for key %lld returned %lld, not %lld\n", i,
124                tm->keys, kv.value, (u64) (i + 1));
125         }
126     }
127
128   delta = clib_time_now (&tm->clib_time) - before;
129   total_searches = (uword) tm->search_iter * (uword) tm->nitems;
130
131   if (delta > 0)
132     fformat (stdout, "%.f searches per second\n",
133              ((f64) total_searches) / delta);
134
135   fformat (stdout, "%lld searches in %.6f seconds\n", total_searches, delta);
136
137   fformat (stdout, "Standard E-hash search for items %d times...\n",
138            tm->search_iter);
139
140   before = clib_time_now (&tm->clib_time);
141
142   for (j = 0; j < tm->search_iter; j++)
143     {
144       for (i = 0; i < tm->nitems; i++)
145         {
146           p = hash_get (tm->key_hash, tm->keys[i]);
147           if (p == 0 || p[0] != (uword) (i + 1))
148             clib_warning ("ugh, couldn't find %lld\n", tm->keys[i]);
149         }
150     }
151
152   delta = clib_time_now (&tm->clib_time) - before;
153   total_searches = (uword) tm->search_iter * (uword) tm->nitems;
154
155   fformat (stdout, "%lld searches in %.6f seconds\n", total_searches, delta);
156
157   if (delta > 0)
158     fformat (stdout, "%.f searches per second\n",
159              ((f64) total_searches) / delta);
160
161   fformat (stdout, "Delete items...\n");
162
163   for (i = 0; i < tm->nitems; i++)
164     {
165       int j;
166       int rv;
167
168       kv.key = tm->keys[i];
169       kv.value = (u64) (i + 1);
170       rv = BV (clib_bihash_add_del) (h, &kv, 0 /* is_add */ );
171
172       if (rv < 0)
173         clib_warning ("delete key %lld not ok but should be", tm->keys[i]);
174
175       if (tm->careful_delete_tests)
176         {
177           for (j = 0; j < tm->nitems; j++)
178             {
179               kv.key = tm->keys[j];
180               rv = BV (clib_bihash_search) (h, &kv, &kv);
181               if (j <= i && rv >= 0)
182                 {
183                   clib_warning
184                     ("i %d j %d search ok but should not be, value %lld",
185                      i, j, kv.value);
186                 }
187               if (j > i && rv < 0)
188                 {
189                   clib_warning ("i %d j %d search not ok but should be",
190                                 i, j);
191                 }
192             }
193         }
194     }
195
196   fformat (stdout, "After deletions, should be empty...\n");
197
198   fformat (stdout, "%U", BV (format_bihash), h, 0 /* very verbose */ );
199   return 0;
200 }
201
202 clib_error_t *
203 test_bihash_main (test_main_t * tm)
204 {
205   unformat_input_t *i = tm->input;
206   clib_error_t *error;
207
208   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
209     {
210       if (unformat (i, "seed %u", &tm->seed))
211         ;
212
213       else if (unformat (i, "nbuckets %d", &tm->nbuckets))
214         ;
215       else if (unformat (i, "non-random-keys"))
216         tm->non_random_keys = 1;
217       else if (unformat (i, "nitems %d", &tm->nitems))
218         ;
219       else if (unformat (i, "careful %d", &tm->careful_delete_tests))
220         ;
221       else if (unformat (i, "verbose %d", &tm->verbose))
222         ;
223       else if (unformat (i, "search %d", &tm->search_iter))
224         ;
225       else if (unformat (i, "verbose"))
226         tm->verbose = 1;
227       else
228         return clib_error_return (0, "unknown input '%U'",
229                                   format_unformat_error, i);
230     }
231
232   error = test_bihash (tm);
233
234   return error;
235 }
236
237 #ifdef CLIB_UNIX
238 int
239 main (int argc, char *argv[])
240 {
241   unformat_input_t i;
242   clib_error_t *error;
243   test_main_t *tm = &test_main;
244
245   clib_mem_init (0, 3ULL << 30);
246
247   tm->input = &i;
248   tm->seed = 0xdeaddabe;
249
250   tm->nbuckets = 2;
251   tm->nitems = 5;
252   tm->verbose = 1;
253   tm->search_iter = 1;
254   tm->careful_delete_tests = 0;
255   tm->key_hash = hash_create (0, sizeof (uword));
256   clib_time_init (&tm->clib_time);
257
258   unformat_init_command_line (&i, argv);
259   error = test_bihash_main (tm);
260   unformat_free (&i);
261
262   if (error)
263     {
264       clib_error_report (error);
265       return 1;
266     }
267   return 0;
268 }
269 #endif /* CLIB_UNIX */
270
271 /*
272  * fd.io coding-style-patch-verification: ON
273  *
274  * Local Variables:
275  * eval: (c-set-style "gnu")
276  * End:
277  */