vppinfra: toeplitz hash four in parallel
[vpp.git] / src / vppinfra / vector / test / toeplitz.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright(c) 2021 Cisco Systems, Inc.
3  */
4
5 #include <vppinfra/format.h>
6 #include <vppinfra/vector/test/test.h>
7 #include <vppinfra/vector/toeplitz.h>
8
9 /* secret key and test cases taken from:
10  * https://docs.microsoft.com/en-us/windows-hardware/drivers/network/verifying-the-rss-hash-calculation
11  */
12
13 typedef struct
14 {
15   u32 sip, dip;
16   u16 sport, dport;
17 } __clib_packed ip4_key_t;
18
19 typedef struct
20 {
21   ip4_key_t key;
22   u32 hash_2t, hash_4t;
23 } ip4_test_t;
24
25 typedef struct
26 {
27   u16 sip[8], dip[8];
28   u16 sport, dport;
29 } __clib_packed ip6_key_t;
30
31 typedef struct
32 {
33   ip6_key_t key;
34   u32 hash_2t, hash_4t;
35 } ip6_test_t;
36
37 #define N_IP4_TESTS    5
38 #define N_IP6_TESTS    3
39 #define N_LENGTH_TESTS 240
40
41 #ifndef CLIB_MARCH_VARIANT
42 #define _IP4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a))
43 #define _IP6(a, b, c, d, e, f, g, h)                                          \
44   {                                                                           \
45     (u16) ((a) << 8) | (u8) ((a) >> 8), (u16) ((b) << 8) | (u8) ((b) >> 8),   \
46       (u16) ((c) << 8) | (u8) ((c) >> 8), (u16) ((d) << 8) | (u8) ((d) >> 8), \
47       (u16) ((e) << 8) | (u8) ((e) >> 8), (u16) ((f) << 8) | (u8) ((f) >> 8), \
48       (u16) ((g) << 8) | (u8) ((g) >> 8), (u16) ((h) << 8) | (u8) ((h) >> 8), \
49   }
50 #define _PORT(a) ((a) >> 8 | (((a) &0xff) << 8))
51
52 const ip4_test_t ip4_tests[N_IP4_TESTS] = {
53   /* ipv4 tests */
54   {
55     .key.sip = _IP4 (66, 9, 149, 187),
56     .key.dip = _IP4 (161, 142, 100, 80),
57     .key.sport = _PORT (2794),
58     .key.dport = _PORT (1766),
59     .hash_2t = 0x323e8fc2,
60     .hash_4t = 0x51ccc178,
61   },
62   {
63     .key.sip = _IP4 (199, 92, 111, 2),
64     .key.dip = _IP4 (65, 69, 140, 83),
65     .key.sport = _PORT (14230),
66     .key.dport = _PORT (4739),
67     .hash_2t = 0xd718262a,
68     .hash_4t = 0xc626b0ea,
69   },
70   {
71     .key.sip = _IP4 (24, 19, 198, 95),
72     .key.dip = _IP4 (12, 22, 207, 184),
73     .key.sport = _PORT (12898),
74     .key.dport = _PORT (38024),
75     .hash_2t = 0xd2d0a5de,
76     .hash_4t = 0x5c2b394a,
77   },
78   {
79     .key.sip = _IP4 (38, 27, 205, 30),
80     .key.dip = _IP4 (209, 142, 163, 6),
81     .key.sport = _PORT (48228),
82     .key.dport = _PORT (2217),
83     .hash_2t = 0x82989176,
84     .hash_4t = 0xafc7327f,
85   },
86   {
87     .key.sip = _IP4 (153, 39, 163, 191),
88     .key.dip = _IP4 (202, 188, 127, 2),
89     .key.sport = _PORT (44251),
90     .key.dport = _PORT (1303),
91     .hash_2t = 0x5d1809c5,
92     .hash_4t = 0x10e828a2,
93   }
94 };
95
96 const ip6_test_t ip6_tests[N_IP6_TESTS] = {
97   {
98     .key.sip = _IP6 (0x3ffe, 0x2501, 0x200, 0x1fff, 0, 0, 0, 7),
99     .key.dip = _IP6 (0x3ffe, 0x2501, 0x200, 3, 0, 0, 0, 1),
100     .key.sport = _PORT (2794),
101     .key.dport = _PORT (1766),
102     .hash_2t = 0x2cc18cd5,
103     .hash_4t = 0x40207d3d,
104   },
105   {
106     .key.sip = _IP6 (0x3ffe, 0x501, 8, 0, 0x260, 0x97ff, 0xfe40, 0xefab),
107     .key.dip = _IP6 (0xff02, 0, 0, 0, 0, 0, 0, 1),
108     .key.sport = _PORT (14230),
109     .key.dport = _PORT (4739),
110     .hash_2t = 0x0f0c461c,
111     .hash_4t = 0xdde51bbf,
112   },
113   {
114     .key.sip = _IP6 (0x3ffe, 0x1900, 0x4545, 3, 0x200, 0xf8ff, 0xfe21, 0x67cf),
115     .key.dip = _IP6 (0xfe80, 0, 0, 0, 0x200, 0xf8ff, 0xfe21, 0x67cf),
116     .key.sport = _PORT (44251),
117     .key.dport = _PORT (38024),
118     .hash_2t = 0x4b61e985,
119     .hash_4t = 0x02d1feef,
120   }
121 };
122
123 const u32 length_test_hashes[N_LENGTH_TESTS] = {
124   0x00000000, 0x00000000, 0x2b6d12ad, 0x9de4446e, 0x061f00bf, 0xad7ed8f7,
125   0x4bc7b068, 0x231fc545, 0xdbd97a33, 0xcdab29e7, 0x2d665c0c, 0x31e28ed7,
126   0x14e19218, 0x5aa89f0f, 0xd47de07f, 0x355ec712, 0x7e1cbfc0, 0xf84de19d,
127   0xbcf66bd3, 0x104086c6, 0x71900b34, 0xcd2f9819, 0xeae68ebb, 0x54d63b4c,
128   0x5f865a2c, 0x9d6ded08, 0xe00b0912, 0x3fcf07a6, 0x3bd9ca93, 0x3f4f3bbb,
129   0xd0b82624, 0xa28a08e1, 0xa585969f, 0x0c8f4a71, 0x5dce7bdd, 0x4fcf2a6d,
130   0x91c89ae9, 0xbef8a24d, 0x8e3d30fe, 0xc8027848, 0xc1e7e513, 0xa12bd3d9,
131   0x46700bb4, 0xc6339dab, 0x970805ad, 0xfcb50ac8, 0xc6db4f44, 0x792e2987,
132   0xacfb7836, 0xa25ec529, 0x957d7beb, 0x6732809a, 0x891836ed, 0xeefb83b2,
133   0xca96b40b, 0x93fd5abd, 0x9076f922, 0x59adb4eb, 0x9705aafb, 0x282719b1,
134   0xdda9cb8a, 0x3f499131, 0x47491130, 0x30ef0759, 0xad1cf855, 0x428aa312,
135   0x4200240a, 0x71a72857, 0x16b30c36, 0x10cca9a3, 0x166f091e, 0x30e00560,
136   0x8acd20ba, 0xfa633d76, 0x0fe32eb7, 0xdcc0122f, 0x20aa8ab0, 0x62b2a9af,
137   0x7a6c80a6, 0x27e87268, 0x95b797a8, 0x25d18ccd, 0x68a7fb00, 0xc54bcdad,
138   0x3bd0e717, 0xf0df54c9, 0x780daadf, 0x7b435605, 0x150c1e10, 0x8a892e54,
139   0x9d27cb25, 0xe23383a5, 0x57aac408, 0x83b8abf8, 0x560f33af, 0xd5cb3307,
140   0x79ae8edc, 0x9b127665, 0x320f18bd, 0x385d636b, 0xbd1b2dbf, 0x97679888,
141   0x738894a4, 0xeba2afb0, 0xfa7c2d50, 0xb6741aa1, 0x28922bba, 0x7783242b,
142   0xa694cca2, 0xa32781c0, 0x696cd670, 0xa714d72f, 0xea34d35a, 0xc5aed81e,
143   0x0438433a, 0xc1939ab2, 0xb51c123a, 0x121426b9, 0x1add93ba, 0x50c56b6a,
144   0x7e90902a, 0xae3abd85, 0x2f7a0088, 0xb45cf6f9, 0x80070094, 0x8bd46467,
145   0xdfd1b762, 0x0bb25856, 0x48eefe84, 0x0989dbb9, 0xfc32472b, 0x965fec6b,
146   0x5a256bd0, 0x6df7127a, 0x7856d0d6, 0xedc82bd3, 0x1b563b96, 0xc73eace7,
147   0xba4c0a93, 0xdfd6dd97, 0x923c41db, 0x14926ca6, 0x22e52ab1, 0x22852a66,
148   0x79606b9c, 0xb0f22b23, 0xb46354ba, 0x9c3cd931, 0x03a92bd6, 0x84000834,
149   0x5425df65, 0xf4dd3fc9, 0x391cc873, 0xa560b52e, 0x828037d9, 0x31323dd5,
150   0x5c6e3147, 0x28e21f85, 0xa431eb51, 0xf468c4a3, 0x9bea1d2e, 0x43d9109c,
151   0x5bb9b081, 0xe0825675, 0xc9c92591, 0xd29fc812, 0x03136bc9, 0x5e005a1f,
152   0x6d821ed8, 0x3f0bfcc4, 0x24774162, 0x893bde94, 0x6475efea, 0x6711538e,
153   0xc4755f6d, 0x9425ebe2, 0xacf471b4, 0xb947ab0c, 0x1f78c455, 0x372b3ed7,
154   0xb3ec24d7, 0x18c4459f, 0xa8ff3695, 0xe4aa2b85, 0x8a52ad7e, 0xe05e8177,
155   0x7aa348ed, 0x3e4ac6aa, 0x17dcf8a5, 0x93b933b0, 0x8f7413ec, 0xc77bfe61,
156   0xfdb72874, 0x4370f138, 0xdf3462ad, 0xc8970a59, 0xb4a9fed8, 0xa2ddc39b,
157   0xd61db62a, 0x95c5fc1b, 0x7b22e6e0, 0x1969702c, 0x7992aebb, 0x59d7c225,
158   0x0e16db0b, 0x9f2afc21, 0x246cf66b, 0xb3d6569d, 0x29c532d7, 0xe155747a,
159   0xe38d7872, 0xea704969, 0xb69095b0, 0x1b198efd, 0x55daab76, 0xa2a377b6,
160   0xb31aa2fa, 0x48b73c41, 0xf0cc501a, 0x9c9ca831, 0x1b591b99, 0xb2d8d22f,
161   0xab4b5f69, 0x4fe00e71, 0xdf5480bd, 0x982540d7, 0x7f34ea4f, 0xd7be66e1,
162   0x9d2ab1ba, 0x1ba62e12, 0xee3fb36c, 0xf28d7c5a, 0x756311eb, 0xc68567f2,
163   0x7b6ea177, 0xc398d9f3
164 };
165
166 #else
167 extern const ip4_test_t ip4_tests[N_IP4_TESTS];
168 extern const ip6_test_t ip6_tests[N_IP6_TESTS];
169 extern const u32 length_test_hashes[N_LENGTH_TESTS];
170 #endif
171
172 __test_funct_fn u32
173 wrapper (clib_toeplitz_hash_key_t *k, u8 *data, u32 n_bytes)
174 {
175   return clib_toeplitz_hash (k, data, n_bytes);
176 }
177
178 __test_funct_fn void
179 wrapper_x4 (clib_toeplitz_hash_key_t *k, u8 *d0, u8 *d1, u8 *d2, u8 *d3,
180             u32 *h0, u32 *h1, u32 *h2, u32 *h3, u32 n_bytes)
181 {
182   clib_toeplitz_hash_x4 (k, d0, d1, d2, d3, h0, h1, h2, h3, n_bytes);
183 }
184
185 static clib_error_t *
186 test_clib_toeplitz_hash (clib_error_t *err)
187 {
188   u32 r;
189   int n_key_copies, bigkey_len, bigdata_len;
190   u8 *bigkey, *bigdata;
191   clib_toeplitz_hash_key_t *k;
192
193   k = clib_toeplitz_hash_key_init (0, 0);
194
195   for (int i = 0; i < N_IP4_TESTS; i++)
196     {
197       r = wrapper (k, (u8 *) &ip4_tests[i].key, 8);
198       if (ip4_tests[i].hash_2t != r)
199         return clib_error_return (err,
200                                   "wrong IPv4 2 tuple hash for test %u, "
201                                   "calculated 0x%08x expected 0x%08x",
202                                   i, ip4_tests[i].hash_2t, r);
203
204       r = wrapper (k, (u8 *) &ip4_tests[i].key, 12);
205       if (ip4_tests[i].hash_4t != r)
206         return clib_error_return (err,
207                                   "wrong IPv4 4 tuple hash for test %u, "
208                                   "calculated 0x%08x expected 0x%08x",
209                                   i, ip4_tests[i].hash_4t, r);
210     }
211
212   for (int i = 0; i < N_IP6_TESTS; i++)
213     {
214       r = wrapper (k, (u8 *) &ip6_tests[i].key, 32);
215       if (ip6_tests[i].hash_2t != r)
216         return clib_error_return (err,
217                                   "wrong IPv6 2 tuple hash for test %u, "
218                                   "calculated 0x%08x expected 0x%08x",
219                                   i, ip6_tests[i].hash_2t, r);
220
221       r = wrapper (k, (u8 *) &ip6_tests[i].key, 36);
222       if (ip6_tests[i].hash_4t != r)
223         return clib_error_return (err,
224                                   "wrong IPv6 4 tuple hash for test %u, "
225                                   "calculated 0x%08x expected 0x%08x",
226                                   i, ip6_tests[i].hash_4t, r);
227     }
228
229   n_key_copies = 6;
230   bigkey_len = k->key_length * n_key_copies;
231   bigdata_len = bigkey_len - 4;
232   bigkey = test_mem_alloc_and_splat (k->key_length, n_key_copies, k->data);
233   bigdata = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
234   u32 key_len = k->key_length;
235
236   clib_toeplitz_hash_key_free (k);
237   k = clib_toeplitz_hash_key_init (bigkey, n_key_copies * key_len);
238
239   for (int i = 0; i < N_LENGTH_TESTS - 4; i++)
240     {
241       r = wrapper (k, bigdata, i);
242       if (length_test_hashes[i] != r)
243         {
244           err = clib_error_return (err,
245                                    "wrong length test hash for length %u, "
246                                    "calculated 0x%08x expected 0x%08x "
247                                    "xor 0x%08x",
248                                    i, r, length_test_hashes[i],
249                                    r ^ length_test_hashes[i]);
250           goto done;
251         }
252     }
253
254 done:
255   clib_toeplitz_hash_key_free (k);
256   test_mem_free (bigkey);
257   test_mem_free (bigdata);
258   return err;
259 }
260
261 void __test_perf_fn
262 perftest_fixed_12byte (int fd, test_perf_t *tp)
263 {
264   u32 n = tp->n_ops;
265   u8 *data = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[0].key);
266   u8 *res = test_mem_alloc (4 * n);
267   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
268
269   test_perf_event_enable (fd);
270   for (int i = 0; i < n; i++)
271     ((u32 *) res)[i] = clib_toeplitz_hash (k, data + i * 12, 12);
272   test_perf_event_disable (fd);
273
274   clib_toeplitz_hash_key_free (k);
275   test_mem_free (data);
276   test_mem_free (res);
277 }
278
279 void __test_perf_fn
280 perftest_fixed_36byte (int fd, test_perf_t *tp)
281 {
282   u32 n = tp->n_ops;
283   u8 *data = test_mem_alloc_and_splat (36, n, (void *) &ip6_tests[0].key);
284   u8 *res = test_mem_alloc (4 * n);
285   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
286
287   test_perf_event_enable (fd);
288   for (int i = 0; i < n; i++)
289     ((u32 *) res)[i] = clib_toeplitz_hash (k, data + i * 36, 36);
290   test_perf_event_disable (fd);
291
292   clib_toeplitz_hash_key_free (k);
293   test_mem_free (data);
294   test_mem_free (res);
295 }
296
297 void __test_perf_fn
298 perftest_variable_size (int fd, test_perf_t *tp)
299 {
300   u32 key_len, n_keys, n = tp->n_ops;
301   u8 *key, *data = test_mem_alloc (n);
302   u32 *res = test_mem_alloc (sizeof (u32));
303   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
304
305   k = clib_toeplitz_hash_key_init (0, 0);
306   key_len = k->key_length;
307   n_keys = ((n + 4) / k->key_length) + 1;
308   key = test_mem_alloc_and_splat (n_keys, key_len, k->data);
309   clib_toeplitz_hash_key_free (k);
310   k = clib_toeplitz_hash_key_init (key, key_len * n_keys);
311
312   test_perf_event_enable (fd);
313   res[0] = clib_toeplitz_hash (k, data, n);
314   test_perf_event_disable (fd);
315
316   clib_toeplitz_hash_key_free (k);
317   test_mem_free (data);
318   test_mem_free (res);
319   test_mem_free (key);
320 }
321
322 REGISTER_TEST (clib_toeplitz_hash) = {
323   .name = "clib_toeplitz_hash",
324   .fn = test_clib_toeplitz_hash,
325   .perf_tests = PERF_TESTS ({ .name = "fixed_12",
326                               .op_name = "12B Tuple",
327                               .n_ops = 1024,
328                               .fn = perftest_fixed_12byte },
329                             { .name = "fixed_36",
330                               .op_name = "36B Tuple",
331                               .n_ops = 1024,
332                               .fn = perftest_fixed_36byte },
333                             { .name = "variable_size",
334                               .op_name = "Byte",
335                               .n_ops = 16384,
336                               .fn = perftest_variable_size }),
337 };
338
339 static clib_error_t *
340 test_clib_toeplitz_hash_x4 (clib_error_t *err)
341 {
342   u32 r[4];
343   int n_key_copies, bigkey_len, bigdata_len;
344   u8 *bigkey, *bigdata0, *bigdata1, *bigdata2, *bigdata3;
345   clib_toeplitz_hash_key_t *k;
346
347   k = clib_toeplitz_hash_key_init (0, 0);
348
349   wrapper_x4 (k, (u8 *) &ip4_tests[0].key, (u8 *) &ip4_tests[1].key,
350               (u8 *) &ip4_tests[2].key, (u8 *) &ip4_tests[3].key, r, r + 1,
351               r + 2, r + 3, 8);
352
353   if (ip4_tests[0].hash_2t != r[0] || ip4_tests[1].hash_2t != r[1] ||
354       ip4_tests[2].hash_2t != r[2] || ip4_tests[3].hash_2t != r[3])
355     return clib_error_return (err,
356                               "wrong IPv4 2 tuple x4 hash "
357                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
358                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
359                               ip4_tests[0].hash_2t, ip4_tests[1].hash_2t,
360                               ip4_tests[2].hash_2t, ip4_tests[3].hash_2t, r[0],
361                               r[1], r[2], r[3]);
362
363   wrapper_x4 (k, (u8 *) &ip4_tests[0].key, (u8 *) &ip4_tests[1].key,
364               (u8 *) &ip4_tests[2].key, (u8 *) &ip4_tests[3].key, r, r + 1,
365               r + 2, r + 3, 12);
366
367   if (ip4_tests[0].hash_4t != r[0] || ip4_tests[1].hash_4t != r[1] ||
368       ip4_tests[2].hash_4t != r[2] || ip4_tests[3].hash_4t != r[3])
369     return clib_error_return (err,
370                               "wrong IPv4 4 tuple x4 hash "
371                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
372                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
373                               ip4_tests[0].hash_4t, ip4_tests[1].hash_4t,
374                               ip4_tests[2].hash_4t, ip4_tests[3].hash_4t, r[0],
375                               r[1], r[2], r[3]);
376
377   wrapper_x4 (k, (u8 *) &ip6_tests[0].key, (u8 *) &ip6_tests[1].key,
378               (u8 *) &ip6_tests[2].key, (u8 *) &ip6_tests[0].key, r, r + 1,
379               r + 2, r + 3, 32);
380
381   if (ip6_tests[0].hash_2t != r[0] || ip6_tests[1].hash_2t != r[1] ||
382       ip6_tests[2].hash_2t != r[2] || ip6_tests[0].hash_2t != r[3])
383     return clib_error_return (err,
384                               "wrong IPv6 2 tuple x4 hash "
385                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
386                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
387                               ip6_tests[0].hash_2t, ip6_tests[1].hash_2t,
388                               ip6_tests[2].hash_2t, ip6_tests[0].hash_2t, r[0],
389                               r[1], r[2], r[3]);
390
391   wrapper_x4 (k, (u8 *) &ip6_tests[0].key, (u8 *) &ip6_tests[1].key,
392               (u8 *) &ip6_tests[2].key, (u8 *) &ip6_tests[0].key, r, r + 1,
393               r + 2, r + 3, 36);
394
395   if (ip6_tests[0].hash_4t != r[0] || ip6_tests[1].hash_4t != r[1] ||
396       ip6_tests[2].hash_4t != r[2] || ip6_tests[0].hash_4t != r[3])
397     return clib_error_return (err,
398                               "wrong IPv6 4 tuple x4 hash "
399                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
400                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
401                               ip6_tests[0].hash_4t, ip6_tests[1].hash_4t,
402                               ip6_tests[2].hash_4t, ip6_tests[0].hash_4t, r[0],
403                               r[1], r[2], r[3]);
404
405   n_key_copies = 6;
406   bigkey_len = k->key_length * n_key_copies;
407   bigdata_len = bigkey_len - 4;
408   bigkey = test_mem_alloc_and_splat (k->key_length, n_key_copies, k->data);
409   bigdata0 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
410   bigdata1 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
411   bigdata2 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
412   bigdata3 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
413   u32 key_len = k->key_length;
414
415   clib_toeplitz_hash_key_free (k);
416   k = clib_toeplitz_hash_key_init (bigkey, n_key_copies * key_len);
417
418   for (int i = 0; i < N_LENGTH_TESTS - 4; i++)
419     {
420       wrapper_x4 (k, bigdata0, bigdata1, bigdata2, bigdata3, r, r + 1, r + 2,
421                   r + 3, i);
422       if (length_test_hashes[i] != r[0] || length_test_hashes[i] != r[1] ||
423           length_test_hashes[i] != r[2] || length_test_hashes[i] != r[3])
424         {
425           err = clib_error_return (
426             err,
427             "wrong length test hash x4 for length %u, "
428             "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x }, expected 0x%08x",
429             i, r[0], r[1], r[2], r[3], length_test_hashes[i]);
430           goto done;
431         }
432     }
433
434 done:
435   clib_toeplitz_hash_key_free (k);
436   test_mem_free (bigkey);
437   test_mem_free (bigdata0);
438   test_mem_free (bigdata1);
439   test_mem_free (bigdata2);
440   test_mem_free (bigdata3);
441   return err;
442 }
443
444 void __test_perf_fn
445 perftest_fixed_12byte_x4 (int fd, test_perf_t *tp)
446 {
447   u32 n = tp->n_ops / 4;
448   u8 *d0 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[0].key);
449   u8 *d1 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[1].key);
450   u8 *d2 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[2].key);
451   u8 *d3 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[3].key);
452   u32 *h0 = test_mem_alloc (4 * n);
453   u32 *h1 = test_mem_alloc (4 * n);
454   u32 *h2 = test_mem_alloc (4 * n);
455   u32 *h3 = test_mem_alloc (4 * n);
456   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
457
458   test_perf_event_enable (fd);
459   for (int i = 0; i < n; i++)
460     clib_toeplitz_hash_x4 (k, d0 + i * 12, d1 + i * 12, d2 + i * 12,
461                            d3 + i * 12, h0 + i, h1 + i, h2 + i, h3 + i, 12);
462   test_perf_event_disable (fd);
463
464   clib_toeplitz_hash_key_free (k);
465   test_mem_free (d0);
466   test_mem_free (d1);
467   test_mem_free (d2);
468   test_mem_free (d3);
469   test_mem_free (h0);
470   test_mem_free (h1);
471   test_mem_free (h2);
472   test_mem_free (h3);
473 }
474
475 void __test_perf_fn
476 perftest_fixed_36byte_x4 (int fd, test_perf_t *tp)
477 {
478   u32 n = tp->n_ops / 4;
479   u8 *d0 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[0].key);
480   u8 *d1 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[1].key);
481   u8 *d2 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[2].key);
482   u8 *d3 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[3].key);
483   u32 *h0 = test_mem_alloc (4 * n);
484   u32 *h1 = test_mem_alloc (4 * n);
485   u32 *h2 = test_mem_alloc (4 * n);
486   u32 *h3 = test_mem_alloc (4 * n);
487   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
488
489   test_perf_event_enable (fd);
490   for (int i = 0; i < n; i++)
491     clib_toeplitz_hash_x4 (k, d0 + i * 36, d1 + i * 36, d2 + i * 36,
492                            d3 + i * 36, h0 + i, h1 + i, h2 + i, h3 + i, 36);
493   test_perf_event_disable (fd);
494
495   clib_toeplitz_hash_key_free (k);
496   test_mem_free (d0);
497   test_mem_free (d1);
498   test_mem_free (d2);
499   test_mem_free (d3);
500   test_mem_free (h0);
501   test_mem_free (h1);
502   test_mem_free (h2);
503   test_mem_free (h3);
504 }
505
506 void __test_perf_fn
507 perftest_variable_size_x4 (int fd, test_perf_t *tp)
508 {
509   u32 key_len, n_keys, n = tp->n_ops / 4;
510   u8 *key;
511   u8 *d0 = test_mem_alloc (n);
512   u8 *d1 = test_mem_alloc (n);
513   u8 *d2 = test_mem_alloc (n);
514   u8 *d3 = test_mem_alloc (n);
515   u32 *h0 = test_mem_alloc (sizeof (u32));
516   u32 *h1 = test_mem_alloc (sizeof (u32));
517   u32 *h2 = test_mem_alloc (sizeof (u32));
518   u32 *h3 = test_mem_alloc (sizeof (u32));
519   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
520
521   k = clib_toeplitz_hash_key_init (0, 0);
522   key_len = k->key_length;
523   n_keys = ((n + 4) / k->key_length) + 1;
524   key = test_mem_alloc_and_splat (n_keys, key_len, k->data);
525   clib_toeplitz_hash_key_free (k);
526   k = clib_toeplitz_hash_key_init (key, key_len * n_keys);
527
528   test_perf_event_enable (fd);
529   clib_toeplitz_hash_x4 (k, d0, d1, d2, d3, h0, h1, h2, h3, n);
530   test_perf_event_disable (fd);
531
532   clib_toeplitz_hash_key_free (k);
533   test_mem_free (key);
534   test_mem_free (d0);
535   test_mem_free (d1);
536   test_mem_free (d2);
537   test_mem_free (d3);
538   test_mem_free (h0);
539   test_mem_free (h1);
540   test_mem_free (h2);
541   test_mem_free (h3);
542 }
543
544 REGISTER_TEST (clib_toeplitz_hash_x4) = {
545   .name = "clib_toeplitz_hash_x4",
546   .fn = test_clib_toeplitz_hash_x4,
547   .perf_tests = PERF_TESTS ({ .name = "fixed_12",
548                               .op_name = "12B Tuple",
549                               .n_ops = 1024,
550                               .fn = perftest_fixed_12byte_x4 },
551                             { .name = "fixed_36",
552                               .op_name = "36B Tuple",
553                               .n_ops = 1024,
554                               .fn = perftest_fixed_36byte_x4 },
555                             { .name = "variable_size",
556                               .op_name = "Byte",
557                               .n_ops = 16384,
558                               .fn = perftest_variable_size_x4 }),
559 };