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