2 * SPDX-License-Identifier: Apache-2.0
3 * Copyright(c) 2021 Cisco Systems, Inc.
7 #include <vppinfra/time.h>
8 #include <vppinfra/cache.h>
9 #include <vppinfra/error.h>
10 #include <vnet/hash/hash.h>
11 #include <vnet/ethernet/ethernet.h>
13 #define HASH_TEST_DATA_SIZE 2048
15 typedef struct _hash_test_data
18 const char *description;
21 vnet_hash_fn_type_t ftype;
22 struct _hash_test_data *next;
34 hash_test_data_t *hash_test_data;
37 hash_test_main_t hash_test_main;
39 #define HASH_TEST_REGISTER_DATA(x, ...) \
40 __VA_ARGS__ hash_test_data_t __hash_test_data_##x; \
41 static void __clib_constructor __hash_test_data_fn_##x (void) \
43 hash_test_main_t *htm = &hash_test_main; \
44 __hash_test_data_##x.next = htm->hash_test_data; \
45 htm->hash_test_data = &__hash_test_data_##x; \
47 __VA_ARGS__ hash_test_data_t __hash_test_data_##x
50 u8 eth_qinq_ipv4_tcp_data[72] = {
51 0x02, 0xfe, 0x39, 0xe5, 0x09, 0x8f, 0x02, 0xfe, 0x2d, 0x18, 0x63, 0x18,
52 0x88, 0xa8, 0x03, 0xe8, 0x81, 0x00, 0x03, 0xe8, 0x08, 0x00, 0x45, 0x00,
53 0x05, 0xdc, 0xdb, 0x42, 0x40, 0x00, 0x40, 0x06, 0xc4, 0x85, 0xc0, 0xa8,
54 0x0a, 0x02, 0xc0, 0xa8, 0x0a, 0x01, 0xd8, 0xde, 0x14, 0x51, 0x34, 0x93,
55 0xa8, 0x1b, 0x7b, 0xef, 0x2e, 0x7e, 0x80, 0x10, 0x00, 0xe5, 0xc7, 0x03,
56 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xce, 0xaa, 0x00, 0x2f, 0xf2, 0xc3
59 HASH_TEST_REGISTER_DATA (eth_qinq_ipv4_tcp, static) = {
60 .name = "eth-qinq-ipv4-tcp",
61 .description = "Ethernet QinQ IPv4 TCP",
62 .data = eth_qinq_ipv4_tcp_data,
63 .data_size = sizeof (eth_qinq_ipv4_tcp_data),
64 .ftype = VNET_HASH_FN_TYPE_ETHERNET,
68 u8 eth_vlan_ipv4_tcp_data[68] = {
69 0x02, 0xfe, 0x39, 0xe5, 0x09, 0x8f, 0x02, 0xfe, 0x2d, 0x18, 0x63, 0x18,
70 0x81, 0x00, 0x03, 0xe8, 0x08, 0x00, 0x45, 0x00, 0x05, 0xdc, 0xdb, 0x42,
71 0x40, 0x00, 0x40, 0x06, 0xc4, 0x85, 0xc0, 0xa8, 0x0a, 0x02, 0xc0, 0xa8,
72 0x0a, 0x01, 0xd8, 0xde, 0x14, 0x51, 0x34, 0x93, 0xa8, 0x1b, 0x7b, 0xef,
73 0x2e, 0x7e, 0x80, 0x10, 0x00, 0xe5, 0xc7, 0x03, 0x00, 0x00, 0x01, 0x01,
74 0x08, 0x0a, 0xce, 0xaa, 0x00, 0x2f, 0xf2, 0xc3
77 HASH_TEST_REGISTER_DATA (eth_vlan_ipv4_tcp, static) = {
78 .name = "eth-vlan-ipv4-tcp",
79 .description = "Ethernet Vlan IPv4 TCP",
80 .data = eth_vlan_ipv4_tcp_data,
81 .data_size = sizeof (eth_vlan_ipv4_tcp_data),
82 .ftype = VNET_HASH_FN_TYPE_ETHERNET,
86 u8 eth_ipv4_tcp_data[64] = {
87 0x02, 0xfe, 0x39, 0xe5, 0x09, 0x8f, 0x02, 0xfe, 0x2d, 0x18, 0x63, 0x18, 0x08,
88 0x00, 0x45, 0x00, 0x05, 0xdc, 0xdb, 0x42, 0x40, 0x00, 0x40, 0x06, 0xc4, 0x85,
89 0xc0, 0xa8, 0x0a, 0x02, 0xc0, 0xa8, 0x0a, 0x01, 0xd8, 0xde, 0x14, 0x51, 0x34,
90 0x93, 0xa8, 0x1b, 0x7b, 0xef, 0x2e, 0x7e, 0x80, 0x10, 0x00, 0xe5, 0xc7, 0x03,
91 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xce, 0xaa, 0x00, 0x2f, 0xf2, 0xc3
94 HASH_TEST_REGISTER_DATA (eth_ipv4_tcp, static) = {
95 .name = "eth-ipv4-tcp",
96 .description = "Ethernet IPv4 TCP",
97 .data = eth_ipv4_tcp_data,
98 .data_size = sizeof (eth_ipv4_tcp_data),
99 .ftype = VNET_HASH_FN_TYPE_ETHERNET,
103 u8 eth_ipv4_udp_data[42] = { 0x62, 0x36, 0xbe, 0xff, 0x91, 0x20, 0x5e,
104 0x2c, 0xaf, 0x2e, 0x1e, 0x51, 0x08, 0x00,
105 0x45, 0x00, 0x05, 0xc4, 0x9d, 0xc3, 0x40,
106 0x00, 0x33, 0x11, 0x49, 0x61, 0x3e, 0xd2,
107 0x12, 0x28, 0x0a, 0x09, 0x00, 0x02, 0x14,
108 0x58, 0xc0, 0xd8, 0x05, 0xb0, 0x75, 0xbd };
110 HASH_TEST_REGISTER_DATA (eth_ipv4_udp, static) = {
111 .name = "eth-ipv4-udp",
112 .description = "Ethernet IPv4 UDP",
113 .data = eth_ipv4_udp_data,
114 .data_size = sizeof (eth_ipv4_udp_data),
115 .ftype = VNET_HASH_FN_TYPE_ETHERNET,
119 u8 ipv4_tcp_data[50] = { 0x45, 0x00, 0x05, 0xdc, 0xdb, 0x42, 0x40, 0x00, 0x40,
120 0x06, 0xc4, 0x85, 0xc0, 0xa8, 0x0a, 0x02, 0xc0, 0xa8,
121 0x0a, 0x01, 0xd8, 0xde, 0x14, 0x51, 0x34, 0x93, 0xa8,
122 0x1b, 0x7b, 0xef, 0x2e, 0x7e, 0x80, 0x10, 0x00, 0xe5,
123 0xc7, 0x03, 0x00, 0x00, 0x01, 0x01, 0x08, 0x0a, 0xce,
124 0xaa, 0x00, 0x2f, 0xf2, 0xc3 };
126 HASH_TEST_REGISTER_DATA (ipv4_tcp, static) = {
128 .description = "IPv4 TCP",
129 .data = ipv4_tcp_data,
130 .data_size = sizeof (ipv4_tcp_data),
131 .ftype = VNET_HASH_FN_TYPE_IP,
134 u8 ipv4_icmp_data[84] = {
135 0x45, 0x00, 0x00, 0x54, 0xb7, 0xe6, 0x40, 0x00, 0x40, 0x01, 0xed, 0x6e,
136 0xc0, 0xa8, 0x0a, 0x01, 0xc0, 0xa8, 0x0a, 0x02, 0x08, 0x00, 0xc7, 0x84,
137 0x00, 0x16, 0x00, 0x92, 0xfd, 0xdb, 0xd9, 0x60, 0x00, 0x00, 0x00, 0x00,
138 0x91, 0xc3, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13,
139 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
140 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
141 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
145 HASH_TEST_REGISTER_DATA (ipv4_icmp, static) = {
147 .description = "IPv4 ICMP",
148 .data = ipv4_icmp_data,
149 .data_size = sizeof (ipv4_icmp_data),
150 .ftype = VNET_HASH_FN_TYPE_IP,
154 u8 ipv6_icmp6_data[104] = {
155 0x60, 0x0d, 0xf4, 0x97, 0x00, 0x40, 0x3a, 0x40, 0xfd, 0x01, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xfd, 0x01,
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
158 0x01, 0x80, 0x00, 0x10, 0x84, 0xb1, 0x25, 0x00, 0x01, 0x22, 0x57, 0xf0, 0x60,
159 0x00, 0x00, 0x00, 0x00, 0xcb, 0x4a, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
160 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
161 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
162 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
165 HASH_TEST_REGISTER_DATA (ipv6_icmp6, static) = {
166 .name = "ipv6-icmp6",
167 .description = "IPv6 ICMP6",
168 .data = ipv6_icmp6_data,
169 .data_size = sizeof (ipv6_icmp6_data),
170 .ftype = VNET_HASH_FN_TYPE_IP,
174 fill_buffers (vlib_main_t *vm, u32 *buffer_indices, u8 *data, u32 data_size,
178 u64 seed = clib_cpu_time_now ();
179 for (i = 0; i < n_buffers; i++)
181 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
182 clib_memcpy_fast (b->data, data, data_size);
184 for (j = data_size; j < HASH_TEST_DATA_SIZE; j += 8)
185 *(u64 *) (b->data + j) = 1 + random_u64 (&seed);
186 b->current_length = HASH_TEST_DATA_SIZE;
190 static clib_error_t *
191 test_hash_perf (vlib_main_t *vm, hash_test_main_t *htm)
193 clib_error_t *err = 0;
194 u32 n_buffers, n_alloc = 0, warmup_rounds, rounds;
195 u32 *buffer_indices = 0;
198 hash_test_data_t *hash_test_data = htm->hash_test_data;
202 rounds = htm->rounds ? htm->rounds : 100;
203 n_buffers = htm->n_buffers ? htm->n_buffers : 256;
204 warmup_rounds = htm->warmup_rounds ? htm->warmup_rounds : 100;
206 vec_validate_aligned (p, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
207 vec_validate_aligned (buffer_indices, n_buffers - 1, CLIB_CACHE_LINE_BYTES);
208 n_alloc = vlib_buffer_alloc (vm, buffer_indices, n_buffers);
209 if (n_alloc != n_buffers)
211 err = clib_error_return (0, "buffer alloc failure");
216 "%s: n_buffers %u rounds %u "
218 htm->hash_name, n_buffers, rounds, warmup_rounds);
219 vlib_cli_output (vm, " cpu-freq %.2f GHz",
220 (f64) vm->clib_time.clocks_per_second * 1e-9);
222 while (hash_test_data)
224 fill_buffers (vm, buffer_indices, hash_test_data->data,
225 hash_test_data->data_size, n_buffers);
227 for (i = 0; i < n_buffers; i++)
229 vlib_buffer_t *b = vlib_get_buffer (vm, buffer_indices[i]);
230 p[i] = vlib_buffer_get_current (b);
234 vnet_hash_function_from_name (htm->hash_name, hash_test_data->ftype);
238 err = clib_error_return (0, "wrong hash name");
242 for (i = 0; i < 5; i++)
245 for (j = 0; j < warmup_rounds; j++)
247 hf (p, h, n_buffers);
250 t0[i] = clib_cpu_time_now ();
251 for (j = 0; j < rounds; j++)
252 hf (p, h, n_buffers);
253 t1[i] = clib_cpu_time_now ();
257 vm, "===========================================================");
258 vlib_cli_output (vm, " Test: %s", hash_test_data->description);
260 vm, "===========================================================");
261 for (i = 0; i < 5; i++)
263 f64 tpp1 = (f64) (t1[i] - t0[i]) / (n_buffers * rounds);
264 f64 Mpps1 = vm->clib_time.clocks_per_second * 1e-6 / tpp1;
266 vlib_cli_output (vm, "%-2u: %.03f ticks/packet, %.02f Mpps\n", i + 1,
269 hash_test_data = hash_test_data->next;
274 vlib_buffer_free (vm, buffer_indices, n_alloc);
277 vec_free (buffer_indices);
281 static clib_error_t *
282 test_hash_command_fn (vlib_main_t *vm, unformat_input_t *input,
283 vlib_cli_command_t *cmd)
285 hash_test_main_t *tm = &hash_test_main;
286 clib_error_t *err = 0;
288 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
290 if (unformat (input, "verbose"))
292 else if (unformat (input, "detail"))
294 else if (unformat (input, "perf %s", &tm->hash_name))
296 else if (unformat (input, "buffers %u", &tm->n_buffers))
298 else if (unformat (input, "rounds %u", &tm->rounds))
300 else if (unformat (input, "warmup-rounds %u", &tm->warmup_rounds))
304 err = clib_error_return (0, "unknown input '%U'",
305 format_unformat_error, input);
310 err = test_hash_perf (vm, tm);
313 vec_free (tm->hash_name);
318 VLIB_CLI_COMMAND (test_hash_command, static) = {
320 .short_help = "test hash [perf <hash-name>] [buffers <n>] [rounds <n>] "
321 "[warmup-rounds <n>]",
322 .function = test_hash_command_fn,
325 static clib_error_t *
326 hash_test_init (vlib_main_t *vm)
331 VLIB_INIT_FUNCTION (hash_test_init);