708fd0e60fc384c1222621b379c1a9f2124c052d
[vpp.git] / src / vppinfra / 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/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   return err;
257 }
258
259 void __test_perf_fn
260 perftest_fixed_12byte (test_perf_t *tp)
261 {
262   u32 n = tp->n_ops;
263   u8 *data = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[0].key);
264   u8 *res = test_mem_alloc (4 * n);
265   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
266
267   test_perf_event_enable (tp);
268   for (int i = 0; i < n; i++)
269     ((u32 *) res)[i] = clib_toeplitz_hash (k, data + i * 12, 12);
270   test_perf_event_disable (tp);
271
272   clib_toeplitz_hash_key_free (k);
273 }
274
275 void __test_perf_fn
276 perftest_fixed_36byte (test_perf_t *tp)
277 {
278   u32 n = tp->n_ops;
279   u8 *data = test_mem_alloc_and_splat (36, n, (void *) &ip6_tests[0].key);
280   u8 *res = test_mem_alloc (4 * n);
281   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
282
283   test_perf_event_enable (tp);
284   for (int i = 0; i < n; i++)
285     ((u32 *) res)[i] = clib_toeplitz_hash (k, data + i * 36, 36);
286   test_perf_event_disable (tp);
287
288   clib_toeplitz_hash_key_free (k);
289 }
290
291 void __test_perf_fn
292 perftest_variable_size (test_perf_t *tp)
293 {
294   u32 key_len, n_keys, n = tp->n_ops;
295   u8 *key, *data = test_mem_alloc (n);
296   u32 *res = test_mem_alloc (sizeof (u32));
297   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
298
299   k = clib_toeplitz_hash_key_init (0, 0);
300   key_len = k->key_length;
301   n_keys = ((n + 4) / k->key_length) + 1;
302   key = test_mem_alloc_and_splat (n_keys, key_len, k->data);
303   clib_toeplitz_hash_key_free (k);
304   k = clib_toeplitz_hash_key_init (key, key_len * n_keys);
305
306   test_perf_event_enable (tp);
307   res[0] = clib_toeplitz_hash (k, data, n);
308   test_perf_event_disable (tp);
309
310   clib_toeplitz_hash_key_free (k);
311 }
312
313 REGISTER_TEST (clib_toeplitz_hash) = {
314   .name = "clib_toeplitz_hash",
315   .fn = test_clib_toeplitz_hash,
316   .perf_tests = PERF_TESTS ({ .name = "fixed (per 12 byte tuple)",
317                               .n_ops = 1024,
318                               .fn = perftest_fixed_12byte },
319                             { .name = "fixed (per 36 byte tuple)",
320                               .n_ops = 1024,
321                               .fn = perftest_fixed_36byte },
322                             { .name = "variable size (per byte)",
323                               .n_ops = 16384,
324                               .fn = perftest_variable_size }),
325 };
326
327 static clib_error_t *
328 test_clib_toeplitz_hash_x4 (clib_error_t *err)
329 {
330   u32 r[4];
331   int n_key_copies, bigkey_len, bigdata_len;
332   u8 *bigkey, *bigdata0, *bigdata1, *bigdata2, *bigdata3;
333   clib_toeplitz_hash_key_t *k;
334
335   k = clib_toeplitz_hash_key_init (0, 0);
336
337   wrapper_x4 (k, (u8 *) &ip4_tests[0].key, (u8 *) &ip4_tests[1].key,
338               (u8 *) &ip4_tests[2].key, (u8 *) &ip4_tests[3].key, r, r + 1,
339               r + 2, r + 3, 8);
340
341   if (ip4_tests[0].hash_2t != r[0] || ip4_tests[1].hash_2t != r[1] ||
342       ip4_tests[2].hash_2t != r[2] || ip4_tests[3].hash_2t != r[3])
343     return clib_error_return (err,
344                               "wrong IPv4 2 tuple x4 hash "
345                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
346                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
347                               ip4_tests[0].hash_2t, ip4_tests[1].hash_2t,
348                               ip4_tests[2].hash_2t, ip4_tests[3].hash_2t, r[0],
349                               r[1], r[2], r[3]);
350
351   wrapper_x4 (k, (u8 *) &ip4_tests[0].key, (u8 *) &ip4_tests[1].key,
352               (u8 *) &ip4_tests[2].key, (u8 *) &ip4_tests[3].key, r, r + 1,
353               r + 2, r + 3, 12);
354
355   if (ip4_tests[0].hash_4t != r[0] || ip4_tests[1].hash_4t != r[1] ||
356       ip4_tests[2].hash_4t != r[2] || ip4_tests[3].hash_4t != r[3])
357     return clib_error_return (err,
358                               "wrong IPv4 4 tuple x4 hash "
359                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
360                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
361                               ip4_tests[0].hash_4t, ip4_tests[1].hash_4t,
362                               ip4_tests[2].hash_4t, ip4_tests[3].hash_4t, r[0],
363                               r[1], r[2], r[3]);
364
365   wrapper_x4 (k, (u8 *) &ip6_tests[0].key, (u8 *) &ip6_tests[1].key,
366               (u8 *) &ip6_tests[2].key, (u8 *) &ip6_tests[0].key, r, r + 1,
367               r + 2, r + 3, 32);
368
369   if (ip6_tests[0].hash_2t != r[0] || ip6_tests[1].hash_2t != r[1] ||
370       ip6_tests[2].hash_2t != r[2] || ip6_tests[0].hash_2t != r[3])
371     return clib_error_return (err,
372                               "wrong IPv6 2 tuple x4 hash "
373                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
374                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
375                               ip6_tests[0].hash_2t, ip6_tests[1].hash_2t,
376                               ip6_tests[2].hash_2t, ip6_tests[0].hash_2t, r[0],
377                               r[1], r[2], r[3]);
378
379   wrapper_x4 (k, (u8 *) &ip6_tests[0].key, (u8 *) &ip6_tests[1].key,
380               (u8 *) &ip6_tests[2].key, (u8 *) &ip6_tests[0].key, r, r + 1,
381               r + 2, r + 3, 36);
382
383   if (ip6_tests[0].hash_4t != r[0] || ip6_tests[1].hash_4t != r[1] ||
384       ip6_tests[2].hash_4t != r[2] || ip6_tests[0].hash_4t != r[3])
385     return clib_error_return (err,
386                               "wrong IPv6 4 tuple x4 hash "
387                               "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x } "
388                               "expected { 0x%08x, 0x%08x, 0x%08x, 0x%08x }",
389                               ip6_tests[0].hash_4t, ip6_tests[1].hash_4t,
390                               ip6_tests[2].hash_4t, ip6_tests[0].hash_4t, r[0],
391                               r[1], r[2], r[3]);
392
393   n_key_copies = 6;
394   bigkey_len = k->key_length * n_key_copies;
395   bigdata_len = bigkey_len - 4;
396   bigkey = test_mem_alloc_and_splat (k->key_length, n_key_copies, k->data);
397   bigdata0 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
398   bigdata1 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
399   bigdata2 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
400   bigdata3 = test_mem_alloc_and_fill_inc_u8 (bigdata_len, 0, 0);
401   u32 key_len = k->key_length;
402
403   clib_toeplitz_hash_key_free (k);
404   k = clib_toeplitz_hash_key_init (bigkey, n_key_copies * key_len);
405
406   for (int i = 0; i < N_LENGTH_TESTS - 4; i++)
407     {
408       wrapper_x4 (k, bigdata0, bigdata1, bigdata2, bigdata3, r, r + 1, r + 2,
409                   r + 3, i);
410       if (length_test_hashes[i] != r[0] || length_test_hashes[i] != r[1] ||
411           length_test_hashes[i] != r[2] || length_test_hashes[i] != r[3])
412         {
413           err = clib_error_return (
414             err,
415             "wrong length test hash x4 for length %u, "
416             "calculated { 0x%08x, 0x%08x, 0x%08x, 0x%08x }, expected 0x%08x",
417             i, r[0], r[1], r[2], r[3], length_test_hashes[i]);
418           goto done;
419         }
420     }
421
422 done:
423   clib_toeplitz_hash_key_free (k);
424   return err;
425 }
426
427 void __test_perf_fn
428 perftest_fixed_12byte_x4 (test_perf_t *tp)
429 {
430   u32 n = tp->n_ops / 4;
431   u8 *d0 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[0].key);
432   u8 *d1 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[1].key);
433   u8 *d2 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[2].key);
434   u8 *d3 = test_mem_alloc_and_splat (12, n, (void *) &ip4_tests[3].key);
435   u32 *h0 = test_mem_alloc (4 * n);
436   u32 *h1 = test_mem_alloc (4 * n);
437   u32 *h2 = test_mem_alloc (4 * n);
438   u32 *h3 = test_mem_alloc (4 * n);
439   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
440
441   test_perf_event_enable (tp);
442   for (int i = 0; i < n; i++)
443     clib_toeplitz_hash_x4 (k, d0 + i * 12, d1 + i * 12, d2 + i * 12,
444                            d3 + i * 12, h0 + i, h1 + i, h2 + i, h3 + i, 12);
445   test_perf_event_disable (tp);
446
447   clib_toeplitz_hash_key_free (k);
448 }
449
450 void __test_perf_fn
451 perftest_fixed_36byte_x4 (test_perf_t *tp)
452 {
453   u32 n = tp->n_ops / 4;
454   u8 *d0 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[0].key);
455   u8 *d1 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[1].key);
456   u8 *d2 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[2].key);
457   u8 *d3 = test_mem_alloc_and_splat (36, n, (void *) &ip4_tests[3].key);
458   u32 *h0 = test_mem_alloc (4 * n);
459   u32 *h1 = test_mem_alloc (4 * n);
460   u32 *h2 = test_mem_alloc (4 * n);
461   u32 *h3 = test_mem_alloc (4 * n);
462   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
463
464   test_perf_event_enable (tp);
465   for (int i = 0; i < n; i++)
466     clib_toeplitz_hash_x4 (k, d0 + i * 36, d1 + i * 36, d2 + i * 36,
467                            d3 + i * 36, h0 + i, h1 + i, h2 + i, h3 + i, 36);
468   test_perf_event_disable (tp);
469
470   clib_toeplitz_hash_key_free (k);
471 }
472
473 void __test_perf_fn
474 perftest_variable_size_x4 (test_perf_t *tp)
475 {
476   u32 key_len, n_keys, n = tp->n_ops / 4;
477   u8 *key;
478   u8 *d0 = test_mem_alloc (n);
479   u8 *d1 = test_mem_alloc (n);
480   u8 *d2 = test_mem_alloc (n);
481   u8 *d3 = test_mem_alloc (n);
482   u32 *h0 = test_mem_alloc (sizeof (u32));
483   u32 *h1 = test_mem_alloc (sizeof (u32));
484   u32 *h2 = test_mem_alloc (sizeof (u32));
485   u32 *h3 = test_mem_alloc (sizeof (u32));
486   clib_toeplitz_hash_key_t *k = clib_toeplitz_hash_key_init (0, 0);
487
488   k = clib_toeplitz_hash_key_init (0, 0);
489   key_len = k->key_length;
490   n_keys = ((n + 4) / k->key_length) + 1;
491   key = test_mem_alloc_and_splat (n_keys, key_len, k->data);
492   clib_toeplitz_hash_key_free (k);
493   k = clib_toeplitz_hash_key_init (key, key_len * n_keys);
494
495   test_perf_event_enable (tp);
496   clib_toeplitz_hash_x4 (k, d0, d1, d2, d3, h0, h1, h2, h3, n);
497   test_perf_event_disable (tp);
498
499   clib_toeplitz_hash_key_free (k);
500 }
501
502 REGISTER_TEST (clib_toeplitz_hash_x4) = {
503   .name = "clib_toeplitz_hash_x4",
504   .fn = test_clib_toeplitz_hash_x4,
505   .perf_tests = PERF_TESTS ({ .name = "fixed (per 12 byte tuple)",
506                               .n_ops = 1024,
507                               .fn = perftest_fixed_12byte_x4 },
508                             { .name = "fixed (per 36 byte tuple)",
509                               .n_ops = 1024,
510                               .fn = perftest_fixed_36byte_x4 },
511                             { .name = "variable size (per byte)",
512                               .n_ops = 16384,
513                               .fn = perftest_variable_size_x4 }),
514 };