dpdk: Add support for Mellanox ConnectX-4 devices
[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       u64 hash1 = clib_xxhash (tm->keys[0]);
115
116       for (i = 0; i < tm->nitems; i++)
117         {
118           if (i < (tm->nitems - 3))
119             {
120               clib_bihash_bucket_t *b;
121               BVT (clib_bihash_value) * v;
122               u64 hash2 = clib_xxhash (tm->keys[i + 3]);
123               u32 bucket_index = hash2 & (h->nbuckets - 1);
124               b = &h->buckets[bucket_index];
125               CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, LOAD);
126
127               bucket_index = hash1 & (h->nbuckets - 1);
128               b = &h->buckets[bucket_index];
129               v = BV (clib_bihash_get_value) (h, b->offset);
130               hash1 >>= h->log2_nbuckets;
131               hash1 = hash1 & ((1 << b->log2_pages) - 1);
132               v += hash1;
133               CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, LOAD);
134
135               hash1 = hash2;
136             }
137
138           kv.key = tm->keys[i];
139           if (BV (clib_bihash_search) (h, &kv, &kv) < 0)
140             clib_warning ("search for key %lld failed unexpectedly\n",
141                           tm->keys[i]);
142           if (kv.value != (u64) (i + 1))
143             clib_warning ("search for key %lld returned %lld, not %lld\n",
144                           tm->keys, kv.value, (u64) (i + 1));
145         }
146     }
147
148   delta = clib_time_now (&tm->clib_time) - before;
149   total_searches = (uword) tm->search_iter * (uword) tm->nitems;
150
151   if (delta > 0)
152     fformat (stdout, "%.f searches per second\n",
153              ((f64) total_searches) / delta);
154
155   fformat (stdout, "%lld searches in %.6f seconds\n", total_searches, delta);
156
157   fformat (stdout, "Standard E-hash search for items %d times...\n",
158            tm->search_iter);
159
160   before = clib_time_now (&tm->clib_time);
161
162   for (j = 0; j < tm->search_iter; j++)
163     {
164       for (i = 0; i < tm->nitems; i++)
165         {
166           p = hash_get (tm->key_hash, tm->keys[i]);
167           if (p == 0 || p[0] != (uword) (i + 1))
168             clib_warning ("ugh, couldn't find %lld\n", tm->keys[i]);
169         }
170     }
171
172   delta = clib_time_now (&tm->clib_time) - before;
173   total_searches = (uword) tm->search_iter * (uword) tm->nitems;
174
175   fformat (stdout, "%lld searches in %.6f seconds\n", total_searches, delta);
176
177   if (delta > 0)
178     fformat (stdout, "%.f searches per second\n",
179              ((f64) total_searches) / delta);
180
181   fformat (stdout, "Delete items...\n");
182
183   for (i = 0; i < tm->nitems; i++)
184     {
185       int j;
186       int rv;
187
188       kv.key = tm->keys[i];
189       kv.value = (u64) (i + 1);
190       rv = BV (clib_bihash_add_del) (h, &kv, 0 /* is_add */ );
191
192       if (rv < 0)
193         clib_warning ("delete key %lld not ok but should be", tm->keys[i]);
194
195       if (tm->careful_delete_tests)
196         {
197           for (j = 0; j < tm->nitems; j++)
198             {
199               kv.key = tm->keys[j];
200               rv = BV (clib_bihash_search) (h, &kv, &kv);
201               if (j <= i && rv >= 0)
202                 {
203                   clib_warning
204                     ("i %d j %d search ok but should not be, value %lld",
205                      i, j, kv.value);
206                 }
207               if (j > i && rv < 0)
208                 {
209                   clib_warning ("i %d j %d search not ok but should be",
210                                 i, j);
211                 }
212             }
213         }
214     }
215
216   fformat (stdout, "After deletions, should be empty...\n");
217
218   fformat (stdout, "%U", BV (format_bihash), h, 0 /* very verbose */ );
219   return 0;
220 }
221
222 clib_error_t *
223 test_bihash_main (test_main_t * tm)
224 {
225   unformat_input_t *i = tm->input;
226   clib_error_t *error;
227
228   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
229     {
230       if (unformat (i, "seed %u", &tm->seed))
231         ;
232
233       else if (unformat (i, "nbuckets %d", &tm->nbuckets))
234         ;
235       else if (unformat (i, "non-random-keys"))
236         tm->non_random_keys = 1;
237       else if (unformat (i, "nitems %d", &tm->nitems))
238         ;
239       else if (unformat (i, "careful %d", &tm->careful_delete_tests))
240         ;
241       else if (unformat (i, "verbose %d", &tm->verbose))
242         ;
243       else if (unformat (i, "search %d", &tm->search_iter))
244         ;
245       else if (unformat (i, "verbose"))
246         tm->verbose = 1;
247       else
248         return clib_error_return (0, "unknown input '%U'",
249                                   format_unformat_error, i);
250     }
251
252   error = test_bihash (tm);
253
254   return error;
255 }
256
257 #ifdef CLIB_UNIX
258 int
259 main (int argc, char *argv[])
260 {
261   unformat_input_t i;
262   clib_error_t *error;
263   test_main_t *tm = &test_main;
264
265   clib_mem_init (0, 3ULL << 30);
266
267   tm->input = &i;
268   tm->seed = 0xdeaddabe;
269
270   tm->nbuckets = 2;
271   tm->nitems = 5;
272   tm->verbose = 1;
273   tm->search_iter = 1;
274   tm->careful_delete_tests = 0;
275   tm->key_hash = hash_create (0, sizeof (uword));
276   clib_time_init (&tm->clib_time);
277
278   unformat_init_command_line (&i, argv);
279   error = test_bihash_main (tm);
280   unformat_free (&i);
281
282   if (error)
283     {
284       clib_error_report (error);
285       return 1;
286     }
287   return 0;
288 }
289 #endif /* CLIB_UNIX */
290
291 /*
292  * fd.io coding-style-patch-verification: ON
293  *
294  * Local Variables:
295  * eval: (c-set-style "gnu")
296  * End:
297  */