New upstream version 18.08
[deb_dpdk.git] / test / test / test_hash_scaling.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015 Intel Corporation
3  */
4
5 #include <stdio.h>
6
7 #include <rte_cycles.h>
8 #include <rte_hash.h>
9 #include <rte_hash_crc.h>
10 #include <rte_spinlock.h>
11 #include <rte_launch.h>
12
13 #include "test.h"
14
15 /*
16  * Check condition and return an error if true. Assumes that "handle" is the
17  * name of the hash structure pointer to be freed.
18  */
19 #define RETURN_IF_ERROR(cond, str, ...) do {                            \
20         if (cond) {                                                     \
21                 printf("ERROR line %d: " str "\n", __LINE__,            \
22                                                         ##__VA_ARGS__); \
23                 if (handle)                                             \
24                         rte_hash_free(handle);                          \
25                 return -1;                                              \
26         }                                                               \
27 } while (0)
28
29 enum locking_mode_t {
30         NORMAL_LOCK,
31         LOCK_ELISION,
32         NULL_LOCK
33 };
34
35 struct {
36         uint32_t num_iterations;
37         struct rte_hash *h;
38         rte_spinlock_t *lock;
39         int locking_mode;
40 } tbl_scaling_test_params;
41
42 static rte_atomic64_t gcycles;
43
44 static int test_hash_scaling_worker(__attribute__((unused)) void *arg)
45 {
46         uint64_t i, key;
47         uint32_t thr_id = rte_sys_gettid();
48         uint64_t begin, cycles = 0;
49
50         switch (tbl_scaling_test_params.locking_mode) {
51
52         case NORMAL_LOCK:
53
54                 for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) {
55                         /*      different threads get different keys because
56                                 we use the thread-id in the key computation
57                          */
58                         key = rte_hash_crc(&i, sizeof(i), thr_id);
59                         begin = rte_rdtsc_precise();
60                         rte_spinlock_lock(tbl_scaling_test_params.lock);
61                         rte_hash_add_key(tbl_scaling_test_params.h, &key);
62                         rte_spinlock_unlock(tbl_scaling_test_params.lock);
63                         cycles += rte_rdtsc_precise() - begin;
64                 }
65                 break;
66
67         case LOCK_ELISION:
68
69                 for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) {
70                         key = rte_hash_crc(&i, sizeof(i), thr_id);
71                         begin = rte_rdtsc_precise();
72                         rte_spinlock_lock_tm(tbl_scaling_test_params.lock);
73                         rte_hash_add_key(tbl_scaling_test_params.h, &key);
74                         rte_spinlock_unlock_tm(tbl_scaling_test_params.lock);
75                         cycles += rte_rdtsc_precise() - begin;
76                 }
77                 break;
78
79         default:
80
81                 for (i = 0; i < tbl_scaling_test_params.num_iterations; i++) {
82                         key = rte_hash_crc(&i, sizeof(i), thr_id);
83                         begin = rte_rdtsc_precise();
84                         rte_hash_add_key(tbl_scaling_test_params.h, &key);
85                         cycles += rte_rdtsc_precise() - begin;
86                 }
87         }
88
89         rte_atomic64_add(&gcycles, cycles);
90
91         return 0;
92 }
93
94 /*
95  * Do scalability perf tests.
96  */
97 static int
98 test_hash_scaling(int locking_mode)
99 {
100         static unsigned calledCount =    1;
101         uint32_t num_iterations = 1024*1024;
102         uint64_t i, key;
103         struct rte_hash_parameters hash_params = {
104                 .entries = num_iterations*2,
105                 .key_len = sizeof(key),
106                 .hash_func = rte_hash_crc,
107                 .hash_func_init_val = 0,
108                 .socket_id = rte_socket_id(),
109                 .extra_flag = RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT
110         };
111         struct rte_hash *handle;
112         char name[RTE_HASH_NAMESIZE];
113         rte_spinlock_t lock;
114
115         rte_spinlock_init(&lock);
116
117         snprintf(name, 32, "test%u", calledCount++);
118         hash_params.name = name;
119
120         handle = rte_hash_create(&hash_params);
121         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
122
123         tbl_scaling_test_params.num_iterations =
124                 num_iterations/rte_lcore_count();
125         tbl_scaling_test_params.h = handle;
126         tbl_scaling_test_params.lock = &lock;
127         tbl_scaling_test_params.locking_mode = locking_mode;
128
129         rte_atomic64_init(&gcycles);
130         rte_atomic64_clear(&gcycles);
131
132         /* fill up to initial size */
133         for (i = 0; i < num_iterations; i++) {
134                 key = rte_hash_crc(&i, sizeof(i), 0xabcdabcd);
135                 rte_hash_add_key(tbl_scaling_test_params.h, &key);
136         }
137
138         rte_eal_mp_remote_launch(test_hash_scaling_worker, NULL, CALL_MASTER);
139         rte_eal_mp_wait_lcore();
140
141         unsigned long long int cycles_per_operation =
142                 rte_atomic64_read(&gcycles)/
143                 (tbl_scaling_test_params.num_iterations*rte_lcore_count());
144         const char *lock_name;
145
146         switch (locking_mode) {
147         case NORMAL_LOCK:
148                 lock_name = "normal spinlock";
149                 break;
150         case LOCK_ELISION:
151                 lock_name = "lock elision";
152                 break;
153         default:
154                 lock_name = "null lock";
155         }
156         printf("--------------------------------------------------------\n");
157         printf("Cores: %d; %s mode ->  cycles per operation: %llu\n",
158                 rte_lcore_count(), lock_name, cycles_per_operation);
159         printf("--------------------------------------------------------\n");
160         /* CSV output */
161         printf(">>>%d,%s,%llu\n", rte_lcore_count(), lock_name,
162                 cycles_per_operation);
163
164         rte_hash_free(handle);
165         return 0;
166 }
167
168 static int
169 test_hash_scaling_main(void)
170 {
171         int r = 0;
172
173         if (rte_lcore_count() == 1)
174                 r = test_hash_scaling(NULL_LOCK);
175
176         if (r == 0)
177                 r = test_hash_scaling(NORMAL_LOCK);
178
179         if (!rte_tm_supported()) {
180                 printf("Hardware transactional memory (lock elision) is NOT supported\n");
181                 return r;
182         }
183         printf("Hardware transactional memory (lock elision) is supported\n");
184
185         if (r == 0)
186                 r = test_hash_scaling(LOCK_ELISION);
187
188         return r;
189 }
190
191 REGISTER_TEST_COMMAND(hash_scaling_autotest, test_hash_scaling_main);