test: move unit tests to separate directory
[dpdk.git] / test / test / test_hash_multiwriter.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 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 #include <inttypes.h>
34 #include <locale.h>
35
36 #include <rte_cycles.h>
37 #include <rte_hash.h>
38 #include <rte_hash_crc.h>
39 #include <rte_launch.h>
40 #include <rte_malloc.h>
41 #include <rte_random.h>
42 #include <rte_spinlock.h>
43
44 #include "test.h"
45
46 /*
47  * Check condition and return an error if true. Assumes that "handle" is the
48  * name of the hash structure pointer to be freed.
49  */
50 #define RETURN_IF_ERROR(cond, str, ...) do {                            \
51         if (cond) {                                                     \
52                 printf("ERROR line %d: " str "\n", __LINE__,            \
53                                                         ##__VA_ARGS__); \
54                 if (handle)                                             \
55                         rte_hash_free(handle);                          \
56                 return -1;                                              \
57         }                                                               \
58 } while (0)
59
60 #define RTE_APP_TEST_HASH_MULTIWRITER_FAILED 0
61
62 struct {
63         uint32_t *keys;
64         uint32_t *found;
65         uint32_t nb_tsx_insertion;
66         struct rte_hash *h;
67 } tbl_multiwriter_test_params;
68
69 const uint32_t nb_entries = 16*1024*1024;
70 const uint32_t nb_total_tsx_insertion = 15*1024*1024;
71 uint32_t rounded_nb_total_tsx_insertion;
72
73 static rte_atomic64_t gcycles;
74 static rte_atomic64_t ginsertions;
75
76 static int use_htm;
77
78 static int
79 test_hash_multiwriter_worker(__attribute__((unused)) void *arg)
80 {
81         uint64_t i, offset;
82         uint32_t lcore_id = rte_lcore_id();
83         uint64_t begin, cycles;
84
85         offset = (lcore_id - rte_get_master_lcore())
86                 * tbl_multiwriter_test_params.nb_tsx_insertion;
87
88         printf("Core #%d inserting %d: %'"PRId64" - %'"PRId64"\n",
89                lcore_id, tbl_multiwriter_test_params.nb_tsx_insertion,
90                offset, offset + tbl_multiwriter_test_params.nb_tsx_insertion);
91
92         begin = rte_rdtsc_precise();
93
94         for (i = offset;
95              i < offset + tbl_multiwriter_test_params.nb_tsx_insertion;
96              i++) {
97                 if (rte_hash_add_key(tbl_multiwriter_test_params.h,
98                                      tbl_multiwriter_test_params.keys + i) < 0)
99                         break;
100         }
101
102         cycles = rte_rdtsc_precise() - begin;
103         rte_atomic64_add(&gcycles, cycles);
104         rte_atomic64_add(&ginsertions, i - offset);
105
106         for (; i < offset + tbl_multiwriter_test_params.nb_tsx_insertion; i++)
107                 tbl_multiwriter_test_params.keys[i]
108                         = RTE_APP_TEST_HASH_MULTIWRITER_FAILED;
109
110         return 0;
111 }
112
113
114 static int
115 test_hash_multiwriter(void)
116 {
117         unsigned int i, rounded_nb_total_tsx_insertion;
118         static unsigned calledCount = 1;
119
120         uint32_t *keys;
121         uint32_t *found;
122
123         struct rte_hash_parameters hash_params = {
124                 .entries = nb_entries,
125                 .key_len = sizeof(uint32_t),
126                 .hash_func = rte_hash_crc,
127                 .hash_func_init_val = 0,
128                 .socket_id = rte_socket_id(),
129         };
130         if (use_htm)
131                 hash_params.extra_flag =
132                         RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
133                                 | RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
134         else
135                 hash_params.extra_flag =
136                         RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
137
138         struct rte_hash *handle;
139         char name[RTE_HASH_NAMESIZE];
140
141         const void *next_key;
142         void *next_data;
143         uint32_t iter = 0;
144
145         uint32_t duplicated_keys = 0;
146         uint32_t lost_keys = 0;
147
148         snprintf(name, 32, "test%u", calledCount++);
149         hash_params.name = name;
150
151         handle = rte_hash_create(&hash_params);
152         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
153
154         tbl_multiwriter_test_params.h = handle;
155         tbl_multiwriter_test_params.nb_tsx_insertion =
156                 nb_total_tsx_insertion / rte_lcore_count();
157
158         rounded_nb_total_tsx_insertion = (nb_total_tsx_insertion /
159                 tbl_multiwriter_test_params.nb_tsx_insertion)
160                 * tbl_multiwriter_test_params.nb_tsx_insertion;
161
162         rte_srand(rte_rdtsc());
163
164         keys = rte_malloc(NULL, sizeof(uint32_t) * nb_entries, 0);
165
166         if (keys == NULL) {
167                 printf("RTE_MALLOC failed\n");
168                 goto err1;
169         }
170
171         found = rte_zmalloc(NULL, sizeof(uint32_t) * nb_entries, 0);
172         if (found == NULL) {
173                 printf("RTE_ZMALLOC failed\n");
174                 goto err2;
175         }
176
177         for (i = 0; i < nb_entries; i++)
178                 keys[i] = i;
179
180         tbl_multiwriter_test_params.keys = keys;
181         tbl_multiwriter_test_params.found = found;
182
183         rte_atomic64_init(&gcycles);
184         rte_atomic64_clear(&gcycles);
185
186         rte_atomic64_init(&ginsertions);
187         rte_atomic64_clear(&ginsertions);
188
189         /* Fire all threads. */
190         rte_eal_mp_remote_launch(test_hash_multiwriter_worker,
191                                  NULL, CALL_MASTER);
192         rte_eal_mp_wait_lcore();
193
194         while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
195                 /* Search for the key in the list of keys added .*/
196                 i = *(const uint32_t *)next_key;
197                 tbl_multiwriter_test_params.found[i]++;
198         }
199
200         for (i = 0; i < rounded_nb_total_tsx_insertion; i++) {
201                 if (tbl_multiwriter_test_params.keys[i]
202                     != RTE_APP_TEST_HASH_MULTIWRITER_FAILED) {
203                         if (tbl_multiwriter_test_params.found[i] > 1) {
204                                 duplicated_keys++;
205                                 break;
206                         }
207                         if (tbl_multiwriter_test_params.found[i] == 0) {
208                                 lost_keys++;
209                                 printf("key %d is lost\n", i);
210                                 break;
211                         }
212                 }
213         }
214
215         if (duplicated_keys > 0) {
216                 printf("%d key duplicated\n", duplicated_keys);
217                 goto err3;
218         }
219
220         if (lost_keys > 0) {
221                 printf("%d key lost\n", lost_keys);
222                 goto err3;
223         }
224
225         printf("No key corrupted during multiwriter insertion.\n");
226
227         unsigned long long int cycles_per_insertion =
228                 rte_atomic64_read(&gcycles)/
229                 rte_atomic64_read(&ginsertions);
230
231         printf(" cycles per insertion: %llu\n", cycles_per_insertion);
232
233         rte_free(tbl_multiwriter_test_params.found);
234         rte_free(tbl_multiwriter_test_params.keys);
235         rte_hash_free(handle);
236         return 0;
237
238 err3:
239         rte_free(tbl_multiwriter_test_params.found);
240 err2:
241         rte_free(tbl_multiwriter_test_params.keys);
242 err1:
243         rte_hash_free(handle);
244         return -1;
245 }
246
247 static int
248 test_hash_multiwriter_main(void)
249 {
250         if (rte_lcore_count() == 1) {
251                 printf("More than one lcore is required to do multiwriter test\n");
252                 return 0;
253         }
254
255
256         setlocale(LC_NUMERIC, "");
257
258
259         if (!rte_tm_supported()) {
260                 printf("Hardware transactional memory (lock elision) "
261                         "is NOT supported\n");
262         } else {
263                 printf("Hardware transactional memory (lock elision) "
264                         "is supported\n");
265
266                 printf("Test multi-writer with Hardware transactional memory\n");
267
268                 use_htm = 1;
269                 if (test_hash_multiwriter() < 0)
270                         return -1;
271         }
272
273         printf("Test multi-writer without Hardware transactional memory\n");
274         use_htm = 0;
275         if (test_hash_multiwriter() < 0)
276                 return -1;
277
278         return 0;
279 }
280
281 REGISTER_TEST_COMMAND(hash_multiwriter_autotest, test_hash_multiwriter_main);