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