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