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