xref: /dpdk/app/test/test_hash_perf.c (revision fc1f2750a3ec6da919e3c86e59d56f34ec97154b)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #include <sys/queue.h>
41 
42 #include <rte_common.h>
43 #include <rte_lcore.h>
44 #include <rte_malloc.h>
45 #include <rte_cycles.h>
46 #include <rte_random.h>
47 #include <rte_memory.h>
48 #include <rte_memzone.h>
49 #include <rte_tailq.h>
50 #include <rte_eal.h>
51 #include <rte_ip.h>
52 #include <rte_string_fns.h>
53 
54 #include "test.h"
55 
56 #include <rte_hash.h>
57 #include <rte_fbk_hash.h>
58 #include <rte_jhash.h>
59 
60 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
61 #include <rte_hash_crc.h>
62 #endif
63 
64 /* Types of hash table performance test that can be performed */
65 enum hash_test_t {
66 	ADD_ON_EMPTY,		/*< Add keys to empty table */
67 	DELETE_ON_EMPTY,	/*< Attempt to delete keys from empty table */
68 	LOOKUP_ON_EMPTY,	/*< Attempt to find keys in an empty table */
69 	ADD_UPDATE,		/*< Add/update keys in a full table */
70 	DELETE,			/*< Delete keys from a full table */
71 	LOOKUP			/*< Find keys in a full table */
72 };
73 
74 /* Function type for hash table operations. */
75 typedef int32_t (*hash_operation)(const struct rte_hash *h, const void *key);
76 
77 /* Structure to hold parameters used to run a hash table performance test */
78 struct tbl_perf_test_params {
79 	enum hash_test_t test_type;
80 	uint32_t num_iterations;
81 	uint32_t entries;
82 	uint32_t bucket_entries;
83 	uint32_t key_len;
84 	rte_hash_function hash_func;
85 	uint32_t hash_func_init_val;
86 };
87 
88 #define ITERATIONS 10000
89 #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
90 
91 /*******************************************************************************
92  * Hash function performance test configuration section. Each performance test
93  * will be performed HASHTEST_ITERATIONS times.
94  *
95  * The five arrays below control what tests are performed. Every combination
96  * from the array entries is tested.
97  */
98 #define HASHTEST_ITERATIONS 1000000
99 
100 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
101 static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
102 #else
103 static rte_hash_function hashtest_funcs[] = {rte_jhash};
104 #endif
105 static uint32_t hashtest_initvals[] = {0};
106 static uint32_t hashtest_key_lens[] = {2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64};
107 /******************************************************************************/
108 
109 /*******************************************************************************
110  * Hash table performance test configuration section.
111  */
112 struct tbl_perf_test_params tbl_perf_params[] =
113 {
114 /* Small table, add */
115 /*  Test type | Iterations | Entries | BucketSize | KeyLen |     HashFunc | InitVal */
116 { ADD_ON_EMPTY,        1024,     1024,           1,      16,     rte_jhash,  0},
117 { ADD_ON_EMPTY,        1024,     1024,           2,      16,     rte_jhash,  0},
118 { ADD_ON_EMPTY,        1024,     1024,           4,      16,     rte_jhash,  0},
119 { ADD_ON_EMPTY,        1024,     1024,           8,      16,     rte_jhash,  0},
120 { ADD_ON_EMPTY,        1024,     1024,          16,      16,     rte_jhash,  0},
121 { ADD_ON_EMPTY,        1024,     1024,           1,      32,     rte_jhash,  0},
122 { ADD_ON_EMPTY,        1024,     1024,           2,      32,     rte_jhash,  0},
123 { ADD_ON_EMPTY,        1024,     1024,           4,      32,     rte_jhash,  0},
124 { ADD_ON_EMPTY,        1024,     1024,           8,      32,     rte_jhash,  0},
125 { ADD_ON_EMPTY,        1024,     1024,          16,      32,     rte_jhash,  0},
126 { ADD_ON_EMPTY,        1024,     1024,           1,      48,     rte_jhash,  0},
127 { ADD_ON_EMPTY,        1024,     1024,           2,      48,     rte_jhash,  0},
128 { ADD_ON_EMPTY,        1024,     1024,           4,      48,     rte_jhash,  0},
129 { ADD_ON_EMPTY,        1024,     1024,           8,      48,     rte_jhash,  0},
130 { ADD_ON_EMPTY,        1024,     1024,          16,      48,     rte_jhash,  0},
131 { ADD_ON_EMPTY,        1024,     1024,           1,      64,     rte_jhash,  0},
132 { ADD_ON_EMPTY,        1024,     1024,           2,      64,     rte_jhash,  0},
133 { ADD_ON_EMPTY,        1024,     1024,           4,      64,     rte_jhash,  0},
134 { ADD_ON_EMPTY,        1024,     1024,           8,      64,     rte_jhash,  0},
135 { ADD_ON_EMPTY,        1024,     1024,          16,      64,     rte_jhash,  0},
136 /* Small table, update */
137 /*  Test type | Iterations | Entries | BucketSize | KeyLen |     HashFunc | InitVal */
138 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      16,     rte_jhash,  0},
139 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      16,     rte_jhash,  0},
140 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      16,     rte_jhash,  0},
141 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      16,     rte_jhash,  0},
142 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      16,     rte_jhash,  0},
143 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      32,     rte_jhash,  0},
144 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      32,     rte_jhash,  0},
145 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      32,     rte_jhash,  0},
146 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      32,     rte_jhash,  0},
147 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      32,     rte_jhash,  0},
148 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      48,     rte_jhash,  0},
149 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      48,     rte_jhash,  0},
150 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      48,     rte_jhash,  0},
151 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      48,     rte_jhash,  0},
152 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      48,     rte_jhash,  0},
153 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      64,     rte_jhash,  0},
154 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      64,     rte_jhash,  0},
155 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      64,     rte_jhash,  0},
156 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      64,     rte_jhash,  0},
157 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      64,     rte_jhash,  0},
158 /* Small table, lookup */
159 /*  Test type | Iterations | Entries | BucketSize | KeyLen |     HashFunc | InitVal */
160 {       LOOKUP,  ITERATIONS,     1024,           1,      16,     rte_jhash,  0},
161 {       LOOKUP,  ITERATIONS,     1024,           2,      16,     rte_jhash,  0},
162 {       LOOKUP,  ITERATIONS,     1024,           4,      16,     rte_jhash,  0},
163 {       LOOKUP,  ITERATIONS,     1024,           8,      16,     rte_jhash,  0},
164 {       LOOKUP,  ITERATIONS,     1024,          16,      16,     rte_jhash,  0},
165 {       LOOKUP,  ITERATIONS,     1024,           1,      32,     rte_jhash,  0},
166 {       LOOKUP,  ITERATIONS,     1024,           2,      32,     rte_jhash,  0},
167 {       LOOKUP,  ITERATIONS,     1024,           4,      32,     rte_jhash,  0},
168 {       LOOKUP,  ITERATIONS,     1024,           8,      32,     rte_jhash,  0},
169 {       LOOKUP,  ITERATIONS,     1024,          16,      32,     rte_jhash,  0},
170 {       LOOKUP,  ITERATIONS,     1024,           1,      48,     rte_jhash,  0},
171 {       LOOKUP,  ITERATIONS,     1024,           2,      48,     rte_jhash,  0},
172 {       LOOKUP,  ITERATIONS,     1024,           4,      48,     rte_jhash,  0},
173 {       LOOKUP,  ITERATIONS,     1024,           8,      48,     rte_jhash,  0},
174 {       LOOKUP,  ITERATIONS,     1024,          16,      48,     rte_jhash,  0},
175 {       LOOKUP,  ITERATIONS,     1024,           1,      64,     rte_jhash,  0},
176 {       LOOKUP,  ITERATIONS,     1024,           2,      64,     rte_jhash,  0},
177 {       LOOKUP,  ITERATIONS,     1024,           4,      64,     rte_jhash,  0},
178 {       LOOKUP,  ITERATIONS,     1024,           8,      64,     rte_jhash,  0},
179 {       LOOKUP,  ITERATIONS,     1024,          16,      64,     rte_jhash,  0},
180 /* Big table, add */
181 /* Test type  | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
182 { ADD_ON_EMPTY,     1048576,  1048576,           1,      16,    rte_jhash,   0},
183 { ADD_ON_EMPTY,     1048576,  1048576,           2,      16,    rte_jhash,   0},
184 { ADD_ON_EMPTY,     1048576,  1048576,           4,      16,    rte_jhash,   0},
185 { ADD_ON_EMPTY,     1048576,  1048576,           8,      16,    rte_jhash,   0},
186 { ADD_ON_EMPTY,     1048576,  1048576,          16,      16,    rte_jhash,   0},
187 { ADD_ON_EMPTY,     1048576,  1048576,           1,      32,    rte_jhash,   0},
188 { ADD_ON_EMPTY,     1048576,  1048576,           2,      32,    rte_jhash,   0},
189 { ADD_ON_EMPTY,     1048576,  1048576,           4,      32,    rte_jhash,   0},
190 { ADD_ON_EMPTY,     1048576,  1048576,           8,      32,    rte_jhash,   0},
191 { ADD_ON_EMPTY,     1048576,  1048576,          16,      32,    rte_jhash,   0},
192 { ADD_ON_EMPTY,     1048576,  1048576,           1,      48,    rte_jhash,   0},
193 { ADD_ON_EMPTY,     1048576,  1048576,           2,      48,    rte_jhash,   0},
194 { ADD_ON_EMPTY,     1048576,  1048576,           4,      48,    rte_jhash,   0},
195 { ADD_ON_EMPTY,     1048576,  1048576,           8,      48,    rte_jhash,   0},
196 { ADD_ON_EMPTY,     1048576,  1048576,          16,      48,    rte_jhash,   0},
197 { ADD_ON_EMPTY,     1048576,  1048576,           1,      64,    rte_jhash,   0},
198 { ADD_ON_EMPTY,     1048576,  1048576,           2,      64,    rte_jhash,   0},
199 { ADD_ON_EMPTY,     1048576,  1048576,           4,      64,    rte_jhash,   0},
200 { ADD_ON_EMPTY,     1048576,  1048576,           8,      64,    rte_jhash,   0},
201 { ADD_ON_EMPTY,     1048576,  1048576,          16,      64,    rte_jhash,   0},
202 /* Big table, update */
203 /* Test type  | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
204 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      16,    rte_jhash,   0},
205 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      16,    rte_jhash,   0},
206 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      16,    rte_jhash,   0},
207 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      16,    rte_jhash,   0},
208 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      16,    rte_jhash,   0},
209 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      32,    rte_jhash,   0},
210 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      32,    rte_jhash,   0},
211 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      32,    rte_jhash,   0},
212 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      32,    rte_jhash,   0},
213 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      32,    rte_jhash,   0},
214 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      48,    rte_jhash,   0},
215 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      48,    rte_jhash,   0},
216 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      48,    rte_jhash,   0},
217 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      48,    rte_jhash,   0},
218 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      48,    rte_jhash,   0},
219 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      64,    rte_jhash,   0},
220 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      64,    rte_jhash,   0},
221 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      64,    rte_jhash,   0},
222 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      64,    rte_jhash,   0},
223 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      64,    rte_jhash,   0},
224 /* Big table, lookup */
225 /* Test type  | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
226 {       LOOKUP,  ITERATIONS,  1048576,           1,      16,    rte_jhash,   0},
227 {       LOOKUP,  ITERATIONS,  1048576,           2,      16,    rte_jhash,   0},
228 {       LOOKUP,  ITERATIONS,  1048576,           4,      16,    rte_jhash,   0},
229 {       LOOKUP,  ITERATIONS,  1048576,           8,      16,    rte_jhash,   0},
230 {       LOOKUP,  ITERATIONS,  1048576,          16,      16,    rte_jhash,   0},
231 {       LOOKUP,  ITERATIONS,  1048576,           1,      32,    rte_jhash,   0},
232 {       LOOKUP,  ITERATIONS,  1048576,           2,      32,    rte_jhash,   0},
233 {       LOOKUP,  ITERATIONS,  1048576,           4,      32,    rte_jhash,   0},
234 {       LOOKUP,  ITERATIONS,  1048576,           8,      32,    rte_jhash,   0},
235 {       LOOKUP,  ITERATIONS,  1048576,          16,      32,    rte_jhash,   0},
236 {       LOOKUP,  ITERATIONS,  1048576,           1,      48,    rte_jhash,   0},
237 {       LOOKUP,  ITERATIONS,  1048576,           2,      48,    rte_jhash,   0},
238 {       LOOKUP,  ITERATIONS,  1048576,           4,      48,    rte_jhash,   0},
239 {       LOOKUP,  ITERATIONS,  1048576,           8,      48,    rte_jhash,   0},
240 {       LOOKUP,  ITERATIONS,  1048576,          16,      48,    rte_jhash,   0},
241 {       LOOKUP,  ITERATIONS,  1048576,           1,      64,    rte_jhash,   0},
242 {       LOOKUP,  ITERATIONS,  1048576,           2,      64,    rte_jhash,   0},
243 {       LOOKUP,  ITERATIONS,  1048576,           4,      64,    rte_jhash,   0},
244 {       LOOKUP,  ITERATIONS,  1048576,           8,      64,    rte_jhash,   0},
245 {       LOOKUP,  ITERATIONS,  1048576,          16,      64,    rte_jhash,   0},
246 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
247 /* Small table, add */
248 /*  Test type | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
249 { ADD_ON_EMPTY,        1024,     1024,           1,      16, rte_hash_crc,   0},
250 { ADD_ON_EMPTY,        1024,     1024,           2,      16, rte_hash_crc,   0},
251 { ADD_ON_EMPTY,        1024,     1024,           4,      16, rte_hash_crc,   0},
252 { ADD_ON_EMPTY,        1024,     1024,           8,      16, rte_hash_crc,   0},
253 { ADD_ON_EMPTY,        1024,     1024,          16,      16, rte_hash_crc,   0},
254 { ADD_ON_EMPTY,        1024,     1024,           1,      32, rte_hash_crc,   0},
255 { ADD_ON_EMPTY,        1024,     1024,           2,      32, rte_hash_crc,   0},
256 { ADD_ON_EMPTY,        1024,     1024,           4,      32, rte_hash_crc,   0},
257 { ADD_ON_EMPTY,        1024,     1024,           8,      32, rte_hash_crc,   0},
258 { ADD_ON_EMPTY,        1024,     1024,          16,      32, rte_hash_crc,   0},
259 { ADD_ON_EMPTY,        1024,     1024,           1,      48, rte_hash_crc,   0},
260 { ADD_ON_EMPTY,        1024,     1024,           2,      48, rte_hash_crc,   0},
261 { ADD_ON_EMPTY,        1024,     1024,           4,      48, rte_hash_crc,   0},
262 { ADD_ON_EMPTY,        1024,     1024,           8,      48, rte_hash_crc,   0},
263 { ADD_ON_EMPTY,        1024,     1024,          16,      48, rte_hash_crc,   0},
264 { ADD_ON_EMPTY,        1024,     1024,           1,      64, rte_hash_crc,   0},
265 { ADD_ON_EMPTY,        1024,     1024,           2,      64, rte_hash_crc,   0},
266 { ADD_ON_EMPTY,        1024,     1024,           4,      64, rte_hash_crc,   0},
267 { ADD_ON_EMPTY,        1024,     1024,           8,      64, rte_hash_crc,   0},
268 { ADD_ON_EMPTY,        1024,     1024,          16,      64, rte_hash_crc,   0},
269 /* Small table, update */
270 /*  Test type | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
271 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      16, rte_hash_crc,   0},
272 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      16, rte_hash_crc,   0},
273 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      16, rte_hash_crc,   0},
274 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      16, rte_hash_crc,   0},
275 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      16, rte_hash_crc,   0},
276 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      32, rte_hash_crc,   0},
277 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      32, rte_hash_crc,   0},
278 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      32, rte_hash_crc,   0},
279 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      32, rte_hash_crc,   0},
280 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      32, rte_hash_crc,   0},
281 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      48, rte_hash_crc,   0},
282 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      48, rte_hash_crc,   0},
283 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      48, rte_hash_crc,   0},
284 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      48, rte_hash_crc,   0},
285 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      48, rte_hash_crc,   0},
286 {   ADD_UPDATE,  ITERATIONS,     1024,           1,      64, rte_hash_crc,   0},
287 {   ADD_UPDATE,  ITERATIONS,     1024,           2,      64, rte_hash_crc,   0},
288 {   ADD_UPDATE,  ITERATIONS,     1024,           4,      64, rte_hash_crc,   0},
289 {   ADD_UPDATE,  ITERATIONS,     1024,           8,      64, rte_hash_crc,   0},
290 {   ADD_UPDATE,  ITERATIONS,     1024,          16,      64, rte_hash_crc,   0},
291 /* Small table, lookup */
292 /*  Test type | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
293 {       LOOKUP,  ITERATIONS,     1024,           1,      16, rte_hash_crc,   0},
294 {       LOOKUP,  ITERATIONS,     1024,           2,      16, rte_hash_crc,   0},
295 {       LOOKUP,  ITERATIONS,     1024,           4,      16, rte_hash_crc,   0},
296 {       LOOKUP,  ITERATIONS,     1024,           8,      16, rte_hash_crc,   0},
297 {       LOOKUP,  ITERATIONS,     1024,          16,      16, rte_hash_crc,   0},
298 {       LOOKUP,  ITERATIONS,     1024,           1,      32, rte_hash_crc,   0},
299 {       LOOKUP,  ITERATIONS,     1024,           2,      32, rte_hash_crc,   0},
300 {       LOOKUP,  ITERATIONS,     1024,           4,      32, rte_hash_crc,   0},
301 {       LOOKUP,  ITERATIONS,     1024,           8,      32, rte_hash_crc,   0},
302 {       LOOKUP,  ITERATIONS,     1024,          16,      32, rte_hash_crc,   0},
303 {       LOOKUP,  ITERATIONS,     1024,           1,      48, rte_hash_crc,   0},
304 {       LOOKUP,  ITERATIONS,     1024,           2,      48, rte_hash_crc,   0},
305 {       LOOKUP,  ITERATIONS,     1024,           4,      48, rte_hash_crc,   0},
306 {       LOOKUP,  ITERATIONS,     1024,           8,      48, rte_hash_crc,   0},
307 {       LOOKUP,  ITERATIONS,     1024,          16,      48, rte_hash_crc,   0},
308 {       LOOKUP,  ITERATIONS,     1024,           1,      64, rte_hash_crc,   0},
309 {       LOOKUP,  ITERATIONS,     1024,           2,      64, rte_hash_crc,   0},
310 {       LOOKUP,  ITERATIONS,     1024,           4,      64, rte_hash_crc,   0},
311 {       LOOKUP,  ITERATIONS,     1024,           8,      64, rte_hash_crc,   0},
312 {       LOOKUP,  ITERATIONS,     1024,          16,      64, rte_hash_crc,   0},
313 /* Big table, add */
314 /* Test type  | Iterations | Entries | BucketSize | KeyLen |    HashFunc | InitVal */
315 { ADD_ON_EMPTY,     1048576,  1048576,           1,      16, rte_hash_crc,   0},
316 { ADD_ON_EMPTY,     1048576,  1048576,           2,      16, rte_hash_crc,   0},
317 { ADD_ON_EMPTY,     1048576,  1048576,           4,      16, rte_hash_crc,   0},
318 { ADD_ON_EMPTY,     1048576,  1048576,           8,      16, rte_hash_crc,   0},
319 { ADD_ON_EMPTY,     1048576,  1048576,          16,      16, rte_hash_crc,   0},
320 { ADD_ON_EMPTY,     1048576,  1048576,           1,      32, rte_hash_crc,   0},
321 { ADD_ON_EMPTY,     1048576,  1048576,           2,      32, rte_hash_crc,   0},
322 { ADD_ON_EMPTY,     1048576,  1048576,           4,      32, rte_hash_crc,   0},
323 { ADD_ON_EMPTY,     1048576,  1048576,           8,      32, rte_hash_crc,   0},
324 { ADD_ON_EMPTY,     1048576,  1048576,          16,      32, rte_hash_crc,   0},
325 { ADD_ON_EMPTY,     1048576,  1048576,           1,      48, rte_hash_crc,   0},
326 { ADD_ON_EMPTY,     1048576,  1048576,           2,      48, rte_hash_crc,   0},
327 { ADD_ON_EMPTY,     1048576,  1048576,           4,      48, rte_hash_crc,   0},
328 { ADD_ON_EMPTY,     1048576,  1048576,           8,      48, rte_hash_crc,   0},
329 { ADD_ON_EMPTY,     1048576,  1048576,          16,      48, rte_hash_crc,   0},
330 { ADD_ON_EMPTY,     1048576,  1048576,           1,      64, rte_hash_crc,   0},
331 { ADD_ON_EMPTY,     1048576,  1048576,           2,      64, rte_hash_crc,   0},
332 { ADD_ON_EMPTY,     1048576,  1048576,           4,      64, rte_hash_crc,   0},
333 { ADD_ON_EMPTY,     1048576,  1048576,           8,      64, rte_hash_crc,   0},
334 { ADD_ON_EMPTY,     1048576,  1048576,          16,      64, rte_hash_crc,   0},
335 /* Big table, update */
336 /* Test type  | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
337 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      16, rte_hash_crc,   0},
338 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      16, rte_hash_crc,   0},
339 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      16, rte_hash_crc,   0},
340 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      16, rte_hash_crc,   0},
341 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      16, rte_hash_crc,   0},
342 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      32, rte_hash_crc,   0},
343 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      32, rte_hash_crc,   0},
344 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      32, rte_hash_crc,   0},
345 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      32, rte_hash_crc,   0},
346 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      32, rte_hash_crc,   0},
347 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      48, rte_hash_crc,   0},
348 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      48, rte_hash_crc,   0},
349 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      48, rte_hash_crc,   0},
350 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      48, rte_hash_crc,   0},
351 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      48, rte_hash_crc,   0},
352 {   ADD_UPDATE,  ITERATIONS,  1048576,           1,      64, rte_hash_crc,   0},
353 {   ADD_UPDATE,  ITERATIONS,  1048576,           2,      64, rte_hash_crc,   0},
354 {   ADD_UPDATE,  ITERATIONS,  1048576,           4,      64, rte_hash_crc,   0},
355 {   ADD_UPDATE,  ITERATIONS,  1048576,           8,      64, rte_hash_crc,   0},
356 {   ADD_UPDATE,  ITERATIONS,  1048576,          16,      64, rte_hash_crc,   0},
357 /* Big table, lookup */
358 /* Test type  | Iterations | Entries | BucketSize | KeyLen | HashFunc | InitVal */
359 {       LOOKUP,  ITERATIONS,  1048576,           1,      16, rte_hash_crc,   0},
360 {       LOOKUP,  ITERATIONS,  1048576,           2,      16, rte_hash_crc,   0},
361 {       LOOKUP,  ITERATIONS,  1048576,           4,      16, rte_hash_crc,   0},
362 {       LOOKUP,  ITERATIONS,  1048576,           8,      16, rte_hash_crc,   0},
363 {       LOOKUP,  ITERATIONS,  1048576,          16,      16, rte_hash_crc,   0},
364 {       LOOKUP,  ITERATIONS,  1048576,           1,      32, rte_hash_crc,   0},
365 {       LOOKUP,  ITERATIONS,  1048576,           2,      32, rte_hash_crc,   0},
366 {       LOOKUP,  ITERATIONS,  1048576,           4,      32, rte_hash_crc,   0},
367 {       LOOKUP,  ITERATIONS,  1048576,           8,      32, rte_hash_crc,   0},
368 {       LOOKUP,  ITERATIONS,  1048576,          16,      32, rte_hash_crc,   0},
369 {       LOOKUP,  ITERATIONS,  1048576,           1,      48, rte_hash_crc,   0},
370 {       LOOKUP,  ITERATIONS,  1048576,           2,      48, rte_hash_crc,   0},
371 {       LOOKUP,  ITERATIONS,  1048576,           4,      48, rte_hash_crc,   0},
372 {       LOOKUP,  ITERATIONS,  1048576,           8,      48, rte_hash_crc,   0},
373 {       LOOKUP,  ITERATIONS,  1048576,          16,      48, rte_hash_crc,   0},
374 {       LOOKUP,  ITERATIONS,  1048576,           1,      64, rte_hash_crc,   0},
375 {       LOOKUP,  ITERATIONS,  1048576,           2,      64, rte_hash_crc,   0},
376 {       LOOKUP,  ITERATIONS,  1048576,           4,      64, rte_hash_crc,   0},
377 {       LOOKUP,  ITERATIONS,  1048576,           8,      64, rte_hash_crc,   0},
378 {       LOOKUP,  ITERATIONS,  1048576,          16,      64, rte_hash_crc,   0},
379 #endif
380 };
381 
382 /******************************************************************************/
383 
384 /*
385  * Check condition and return an error if true. Assumes that "handle" is the
386  * name of the hash structure pointer to be freed.
387  */
388 #define RETURN_IF_ERROR(cond, str, ...) do {				\
389 	if (cond) {							\
390 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
391 		if (handle) rte_hash_free(handle);			\
392 		return -1;						\
393 	}								\
394 } while(0)
395 
396 #define RETURN_IF_ERROR_FBK(cond, str, ...) do {				\
397 	if (cond) {							\
398 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
399 		if (handle) rte_fbk_hash_free(handle);			\
400 		if (keys) rte_free(keys);				\
401 		return -1;						\
402 	}								\
403 } while(0)
404 
405 /*
406  * Find average of array of numbers.
407  */
408 static double
409 get_avg(const uint32_t *array, uint32_t size)
410 {
411 	double sum = 0;
412 	unsigned i;
413 	for (i = 0; i < size; i++)
414 		sum += array[i];
415 	return sum / (double)size;
416 }
417 
418 /*
419  * To help print out name of hash functions.
420  */
421 static const char *get_hash_name(rte_hash_function f)
422 {
423 	if (f == rte_jhash)
424 		return "jhash";
425 
426 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
427 	if (f == rte_hash_crc)
428 		return "rte_hash_crc";
429 #endif
430 
431 	return "UnknownHash";
432 }
433 
434 /*
435  * Do a single performance test, of one type of operation.
436  *
437  * @param h
438  *   hash table to run test on
439  * @param func
440  *   function to call (add, delete or lookup function)
441  * @param avg_occupancy
442  *   The average number of entries in each bucket of the hash table
443  * @param invalid_pos_count
444  *   The amount of errors (e.g. due to a full bucket).
445  * @return
446  *   The average number of ticks per hash function call. A negative number
447  *   signifies failure.
448  */
449 static double
450 run_single_tbl_perf_test(const struct rte_hash *h, hash_operation func,
451 		const struct tbl_perf_test_params *params, double *avg_occupancy,
452 		uint32_t *invalid_pos_count)
453 {
454 	uint64_t begin, end, ticks = 0;
455 	uint8_t *key = NULL;
456 	uint32_t *bucket_occupancies = NULL;
457 	uint32_t num_buckets, i, j;
458 	int32_t pos;
459 
460 	/* Initialise */
461 	num_buckets = params->entries / params->bucket_entries;
462 	key = (uint8_t *) rte_zmalloc("hash key",
463 			params->key_len * sizeof(uint8_t), 16);
464 	if (key == NULL)
465 		return -1;
466 
467 	bucket_occupancies = (uint32_t *) rte_zmalloc("bucket occupancies",
468 			num_buckets * sizeof(uint32_t), 16);
469 	if (bucket_occupancies == NULL) {
470 		rte_free(key);
471 		return -1;
472 	}
473 
474 	ticks = 0;
475 	*invalid_pos_count = 0;
476 
477 	for (i = 0; i < params->num_iterations; i++) {
478 		/* Prepare inputs for the current iteration */
479 		for (j = 0; j < params->key_len; j++)
480 			key[j] = (uint8_t) rte_rand();
481 
482 		/* Perform operation, and measure time it takes */
483 		begin = rte_rdtsc();
484 		pos = func(h, key);
485 		end = rte_rdtsc();
486 		ticks += end - begin;
487 
488 		/* Other work per iteration */
489 		if (pos < 0)
490 			*invalid_pos_count += 1;
491 		else
492 			bucket_occupancies[pos / params->bucket_entries]++;
493 	}
494 	*avg_occupancy = get_avg(bucket_occupancies, num_buckets);
495 
496 	rte_free(bucket_occupancies);
497 	rte_free(key);
498 
499 	return (double)ticks / params->num_iterations;
500 }
501 
502 /*
503  * To help print out what tests are being done.
504  */
505 static const char *
506 get_tbl_perf_test_desc(enum hash_test_t type)
507 {
508 	switch (type){
509 	case ADD_ON_EMPTY: return "Add on Empty";
510 	case DELETE_ON_EMPTY: return "Delete on Empty";
511 	case LOOKUP_ON_EMPTY: return "Lookup on Empty";
512 	case ADD_UPDATE: return "Add Update";
513 	case DELETE: return "Delete";
514 	case LOOKUP: return "Lookup";
515 	default: return "UNKNOWN";
516 	}
517 }
518 
519 /*
520  * Run a hash table performance test based on params.
521  */
522 static int
523 run_tbl_perf_test(struct tbl_perf_test_params *params)
524 {
525 	static unsigned calledCount = 5;
526 	struct rte_hash_parameters hash_params = {
527 		.entries = params->entries,
528 		.bucket_entries = params->bucket_entries,
529 		.key_len = params->key_len,
530 		.hash_func = params->hash_func,
531 		.hash_func_init_val = params->hash_func_init_val,
532 		.socket_id = rte_socket_id(),
533 	};
534 	struct rte_hash *handle;
535 	double avg_occupancy = 0, ticks = 0;
536 	uint32_t num_iterations, invalid_pos;
537 	char name[RTE_HASH_NAMESIZE];
538 	char hashname[RTE_HASH_NAMESIZE];
539 
540 	snprintf(name, 32, "test%u", calledCount++);
541 	hash_params.name = name;
542 
543 	handle = rte_hash_create(&hash_params);
544 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
545 
546 	switch (params->test_type){
547 	case ADD_ON_EMPTY:
548 		ticks = run_single_tbl_perf_test(handle, rte_hash_add_key,
549 				params, &avg_occupancy, &invalid_pos);
550 		break;
551 	case DELETE_ON_EMPTY:
552 		ticks = run_single_tbl_perf_test(handle, rte_hash_del_key,
553 				params, &avg_occupancy, &invalid_pos);
554 		break;
555 	case LOOKUP_ON_EMPTY:
556 		ticks = run_single_tbl_perf_test(handle, rte_hash_lookup,
557 				params, &avg_occupancy, &invalid_pos);
558 		break;
559 	case ADD_UPDATE:
560 		num_iterations = params->num_iterations;
561 		params->num_iterations = params->entries;
562 		run_single_tbl_perf_test(handle, rte_hash_add_key, params,
563 				&avg_occupancy, &invalid_pos);
564 		params->num_iterations = num_iterations;
565 		ticks = run_single_tbl_perf_test(handle, rte_hash_add_key,
566 				params, &avg_occupancy, &invalid_pos);
567 		break;
568 	case DELETE:
569 		num_iterations = params->num_iterations;
570 		params->num_iterations = params->entries;
571 		run_single_tbl_perf_test(handle, rte_hash_add_key, params,
572 				&avg_occupancy, &invalid_pos);
573 
574 		params->num_iterations = num_iterations;
575 		ticks = run_single_tbl_perf_test(handle, rte_hash_del_key,
576 				params, &avg_occupancy, &invalid_pos);
577 		break;
578 	case LOOKUP:
579 		num_iterations = params->num_iterations;
580 		params->num_iterations = params->entries;
581 		run_single_tbl_perf_test(handle, rte_hash_add_key, params,
582 				&avg_occupancy, &invalid_pos);
583 
584 		params->num_iterations = num_iterations;
585 		ticks = run_single_tbl_perf_test(handle, rte_hash_lookup,
586 				params, &avg_occupancy, &invalid_pos);
587 		break;
588 	default: return -1;
589 	}
590 
591 	snprintf(hashname, RTE_HASH_NAMESIZE, "%s", get_hash_name(params->hash_func));
592 
593 	printf("%-12s, %-15s, %-16u, %-7u, %-18u, %-8u, %-19.2f, %.2f\n",
594 		hashname,
595 		get_tbl_perf_test_desc(params->test_type),
596 		(unsigned) params->key_len,
597 		(unsigned) params->entries,
598 		(unsigned) params->bucket_entries,
599 		(unsigned) invalid_pos,
600 		avg_occupancy,
601 		ticks
602 	);
603 
604 	/* Free */
605 	rte_hash_free(handle);
606 	return 0;
607 }
608 
609 /*
610  * Run all hash table performance tests.
611  */
612 static int run_all_tbl_perf_tests(void)
613 {
614 	unsigned i;
615 
616 	printf(" *** Hash table performance test results ***\n");
617 	printf("Hash Func.  , Operation      , Key size (bytes), Entries, "
618 	       "Entries per bucket, Errors  , Avg. bucket entries, Ticks/Op.\n");
619 
620 	/* Loop through every combination of test parameters */
621 	for (i = 0;
622 	     i < sizeof(tbl_perf_params) / sizeof(struct tbl_perf_test_params);
623 	     i++) {
624 
625 		/* Perform test */
626 		if (run_tbl_perf_test(&tbl_perf_params[i]) < 0)
627 			return -1;
628 	}
629 	return 0;
630 }
631 
632 /*
633  * Test a hash function.
634  */
635 static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
636 		uint32_t key_len)
637 {
638 	static uint8_t key[RTE_HASH_KEY_LENGTH_MAX];
639 	uint64_t ticks = 0, start, end;
640 	unsigned i, j;
641 
642 	for (i = 0; i < HASHTEST_ITERATIONS; i++) {
643 
644 		for (j = 0; j < key_len; j++)
645 			key[j] = (uint8_t) rte_rand();
646 
647 		start = rte_rdtsc();
648 		f(key, key_len, init_val);
649 		end = rte_rdtsc();
650 		ticks += end - start;
651 	}
652 
653 	printf("%-12s, %-18u, %-13u, %.02f\n", get_hash_name(f), (unsigned) key_len,
654 			(unsigned) init_val, (double)ticks / HASHTEST_ITERATIONS);
655 }
656 
657 /*
658  * Test all hash functions.
659  */
660 static void run_hash_func_tests(void)
661 {
662 	unsigned i, j, k;
663 
664 	printf("\n\n *** Hash function performance test results ***\n");
665 	printf(" Number of iterations for each test = %d\n",
666 			HASHTEST_ITERATIONS);
667 	printf("Hash Func.  , Key Length (bytes), Initial value, Ticks/Op.\n");
668 
669 	for (i = 0;
670 	     i < sizeof(hashtest_funcs) / sizeof(rte_hash_function);
671 	     i++) {
672 		for (j = 0;
673 		     j < sizeof(hashtest_initvals) / sizeof(uint32_t);
674 		     j++) {
675 			for (k = 0;
676 			     k < sizeof(hashtest_key_lens) / sizeof(uint32_t);
677 			     k++) {
678 				run_hash_func_test(hashtest_funcs[i],
679 						hashtest_initvals[j],
680 						hashtest_key_lens[k]);
681 			}
682 		}
683 	}
684 }
685 
686 /* Control operation of performance testing of fbk hash. */
687 #define LOAD_FACTOR 0.667	/* How full to make the hash table. */
688 #define TEST_SIZE 1000000	/* How many operations to time. */
689 #define TEST_ITERATIONS 30	/* How many measurements to take. */
690 #define ENTRIES (1 << 15)	/* How many entries. */
691 
692 static int
693 fbk_hash_perf_test(void)
694 {
695 	struct rte_fbk_hash_params params = {
696 		.name = "fbk_hash_test",
697 		.entries = ENTRIES,
698 		.entries_per_bucket = 4,
699 		.socket_id = rte_socket_id(),
700 	};
701 	struct rte_fbk_hash_table *handle = NULL;
702 	uint32_t *keys = NULL;
703 	unsigned indexes[TEST_SIZE];
704 	uint64_t lookup_time = 0;
705 	unsigned added = 0;
706 	unsigned value = 0;
707 	unsigned i, j;
708 
709 	handle = rte_fbk_hash_create(&params);
710 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
711 
712 	keys = rte_zmalloc(NULL, ENTRIES * sizeof(*keys), 0);
713 	RETURN_IF_ERROR_FBK(keys == NULL,
714 		"fbk hash: memory allocation for key store failed");
715 
716 	/* Generate random keys and values. */
717 	for (i = 0; i < ENTRIES; i++) {
718 		uint32_t key = (uint32_t)rte_rand();
719 		key = ((uint64_t)key << 32) | (uint64_t)rte_rand();
720 		uint16_t val = (uint16_t)rte_rand();
721 
722 		if (rte_fbk_hash_add_key(handle, key, val) == 0) {
723 			keys[added] = key;
724 			added++;
725 		}
726 		if (added > (LOAD_FACTOR * ENTRIES)) {
727 			break;
728 		}
729 	}
730 
731 	for (i = 0; i < TEST_ITERATIONS; i++) {
732 		uint64_t begin;
733 		uint64_t end;
734 
735 		/* Generate random indexes into keys[] array. */
736 		for (j = 0; j < TEST_SIZE; j++) {
737 			indexes[j] = rte_rand() % added;
738 		}
739 
740 		begin = rte_rdtsc();
741 		/* Do lookups */
742 		for (j = 0; j < TEST_SIZE; j++) {
743 			value += rte_fbk_hash_lookup(handle, keys[indexes[j]]);
744 		}
745 		end = rte_rdtsc();
746 		lookup_time += (double)(end - begin);
747 	}
748 
749 	printf("\n\n *** FBK Hash function performance test results ***\n");
750 	/*
751 	 * The use of the 'value' variable ensures that the hash lookup is not
752 	 * being optimised out by the compiler.
753 	 */
754 	if (value != 0)
755 		printf("Number of ticks per lookup = %g\n",
756 			(double)lookup_time /
757 			((double)TEST_ITERATIONS * (double)TEST_SIZE));
758 
759 	rte_fbk_hash_free(handle);
760 
761 	return 0;
762 }
763 
764 /*
765  * Do all unit and performance tests.
766  */
767 static int
768 test_hash_perf(void)
769 {
770 	if (run_all_tbl_perf_tests() < 0)
771 		return -1;
772 	run_hash_func_tests();
773 
774 	if (fbk_hash_perf_test() < 0)
775 		return -1;
776 	return 0;
777 }
778 
779 static struct test_command hash_perf_cmd = {
780 	.command = "hash_perf_autotest",
781 	.callback = test_hash_perf,
782 };
783 REGISTER_TEST_COMMAND(hash_perf_cmd);
784