tests: use SPDX identifiers
[urcu.git] / tests / benchmark / test_urcu_hash.h
1 // SPDX-FileCopyrightText: 2009-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2 //
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 #ifndef _TEST_URCU_HASH_H
6 #define _TEST_URCU_HASH_H
7
8 /*
9 * Userspace RCU library - test program
10 */
11
12 #include <stdio.h>
13 #include <pthread.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <sys/wait.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <signal.h>
22
23 #include <urcu/assert.h>
24 #include <urcu/tls-compat.h>
25 #include <compat-rand.h>
26 #include "thread-id.h"
27 #include "../common/debug-yield.h"
28
29 #define DEFAULT_HASH_SIZE 32
30 #define DEFAULT_MIN_ALLOC_SIZE 1
31 #define DEFAULT_RAND_POOL 1000000
32
33 /*
34 * Note: the hash seed should be a random value for hash tables
35 * targeting production environments to provide protection against
36 * denial of service attacks. We keep it a static value within this test
37 * program to compare identical benchmark runs.
38 */
39 #define TEST_HASH_SEED 0x42UL
40
41 /* hardcoded number of CPUs */
42 #define NR_CPUS 16384
43
44 #ifdef POISON_FREE
45 #define poison_free(ptr) \
46 do { \
47 memset(ptr, 0x42, sizeof(*(ptr))); \
48 free(ptr); \
49 } while (0)
50 #else
51 #define poison_free(ptr) free(ptr)
52 #endif
53
54 #ifndef DYNAMIC_LINK_TEST
55 #define _LGPL_SOURCE
56 #else
57 #define debug_yield_read()
58 #endif
59 #include <urcu-qsbr.h>
60 #include <urcu/rculfhash.h>
61 #include <urcu-call-rcu.h>
62
63 struct wr_count {
64 unsigned long update_ops;
65 unsigned long add;
66 unsigned long add_exist;
67 unsigned long remove;
68 };
69
70 extern DECLARE_URCU_TLS(unsigned int, rand_lookup);
71 extern DECLARE_URCU_TLS(unsigned long, nr_add);
72 extern DECLARE_URCU_TLS(unsigned long, nr_addexist);
73 extern DECLARE_URCU_TLS(unsigned long, nr_del);
74 extern DECLARE_URCU_TLS(unsigned long, nr_delnoent);
75 extern DECLARE_URCU_TLS(unsigned long, lookup_fail);
76 extern DECLARE_URCU_TLS(unsigned long, lookup_ok);
77
78 extern struct cds_lfht *test_ht;
79
80 struct test_data {
81 int a;
82 int b;
83 };
84
85 struct lfht_test_node {
86 struct cds_lfht_node node;
87 void *key;
88 unsigned int key_len;
89 /* cache-cold for iteration */
90 struct rcu_head head;
91 };
92
93 static inline struct lfht_test_node *
94 to_test_node(struct cds_lfht_node *node)
95 {
96 return caa_container_of(node, struct lfht_test_node, node);
97 }
98
99 static inline
100 void lfht_test_node_init(struct lfht_test_node *node, void *key,
101 size_t key_len)
102 {
103 cds_lfht_node_init(&node->node);
104 node->key = key;
105 node->key_len = key_len;
106 }
107
108 static inline struct lfht_test_node *
109 cds_lfht_iter_get_test_node(struct cds_lfht_iter *iter)
110 {
111 return to_test_node(cds_lfht_iter_get_node(iter));
112 }
113
114 extern volatile int test_go, test_stop;
115
116 extern unsigned long wdelay;
117
118 extern unsigned long duration;
119
120 /* read-side C.S. duration, in loops */
121 extern unsigned long rduration;
122
123 extern unsigned long init_hash_size;
124 extern unsigned long min_hash_alloc_size;
125 extern unsigned long max_hash_buckets_size;
126 extern unsigned long init_populate;
127 extern int opt_auto_resize;
128 extern int add_only, add_unique, add_replace;
129 extern const struct cds_lfht_mm_type *memory_backend;
130
131 extern unsigned long init_pool_offset, lookup_pool_offset, write_pool_offset;
132 extern unsigned long init_pool_size,
133 lookup_pool_size,
134 write_pool_size;
135 extern int validate_lookup;
136
137 extern unsigned long nr_hash_chains;
138
139 extern int count_pipe[2];
140
141 static inline void loop_sleep(unsigned long loops)
142 {
143 while (loops-- != 0)
144 caa_cpu_relax();
145 }
146
147 extern int verbose_mode;
148
149 #define printf_verbose(fmt, args...) \
150 do { \
151 if (verbose_mode) \
152 printf(fmt, ## args); \
153 } while (0)
154
155 extern unsigned int cpu_affinities[NR_CPUS];
156 extern unsigned int next_aff;
157 extern int use_affinity;
158
159 extern pthread_mutex_t affinity_mutex;
160
161 void set_affinity(void);
162
163 /*
164 * returns 0 if test should end.
165 */
166 static inline int test_duration_write(void)
167 {
168 return !test_stop;
169 }
170
171 static inline int test_duration_read(void)
172 {
173 return !test_stop;
174 }
175
176 extern DECLARE_URCU_TLS(unsigned long long, nr_writes);
177 extern DECLARE_URCU_TLS(unsigned long long, nr_reads);
178
179 extern unsigned int nr_readers;
180 extern unsigned int nr_writers;
181
182 void rcu_copy_mutex_lock(void);
183 void rcu_copy_mutex_unlock(void);
184
185 /*
186 * Hash function
187 * Source: http://burtleburtle.net/bob/c/lookup3.c
188 * Originally Public Domain
189 */
190
191 #define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
192
193 #define mix(a, b, c) \
194 do { \
195 a -= c; a ^= rot(c, 4); c += b; \
196 b -= a; b ^= rot(a, 6); a += c; \
197 c -= b; c ^= rot(b, 8); b += a; \
198 a -= c; a ^= rot(c, 16); c += b; \
199 b -= a; b ^= rot(a, 19); a += c; \
200 c -= b; c ^= rot(b, 4); b += a; \
201 } while (0)
202
203 #define final(a, b, c) \
204 { \
205 c ^= b; c -= rot(b, 14); \
206 a ^= c; a -= rot(c, 11); \
207 b ^= a; b -= rot(a, 25); \
208 c ^= b; c -= rot(b, 16); \
209 a ^= c; a -= rot(c, 4);\
210 b ^= a; b -= rot(a, 14); \
211 c ^= b; c -= rot(b, 24); \
212 }
213
214 static inline __attribute__((unused))
215 uint32_t hash_u32(
216 const uint32_t *k, /* the key, an array of uint32_t values */
217 size_t length, /* the length of the key, in uint32_ts */
218 uint32_t initval) /* the previous hash, or an arbitrary value */
219 {
220 uint32_t a, b, c;
221
222 /* Set up the internal state */
223 a = b = c = 0xdeadbeef + (((uint32_t) length) << 2) + initval;
224
225 /*----------------------------------------- handle most of the key */
226 while (length > 3) {
227 a += k[0];
228 b += k[1];
229 c += k[2];
230 mix(a, b, c);
231 length -= 3;
232 k += 3;
233 }
234
235 /*----------------------------------- handle the last 3 uint32_t's */
236 switch (length) { /* all the case statements fall through */
237 case 3: c += k[2]; /* fall through */
238 case 2: b += k[1]; /* fall through */
239 case 1: a += k[0];
240 final(a, b, c);
241 /* fall through */
242 case 0: /* case 0: nothing left to add */
243 break;
244 }
245 /*---------------------------------------------- report the result */
246 return c;
247 }
248
249 static inline
250 void hashword2(
251 const uint32_t *k, /* the key, an array of uint32_t values */
252 size_t length, /* the length of the key, in uint32_ts */
253 uint32_t *pc, /* IN: seed OUT: primary hash value */
254 uint32_t *pb) /* IN: more seed OUT: secondary hash value */
255 {
256 uint32_t a, b, c;
257
258 /* Set up the internal state */
259 a = b = c = 0xdeadbeef + ((uint32_t) (length << 2)) + *pc;
260 c += *pb;
261
262 /*----------------------------------------- handle most of the key */
263 while (length > 3) {
264 a += k[0];
265 b += k[1];
266 c += k[2];
267 mix(a, b, c);
268 length -= 3;
269 k += 3;
270 }
271
272 /*----------------------------------- handle the last 3 uint32_t's */
273 switch (length) { /* all the case statements fall through */
274 case 3: c += k[2]; /* fall through */
275 case 2: b += k[1]; /* fall through */
276 case 1: a += k[0];
277 final(a, b, c);
278 /* fall through */
279 case 0: /* case 0: nothing left to add */
280 break;
281 }
282 /*---------------------------------------------- report the result */
283 *pc = c;
284 *pb = b;
285 }
286
287 #if (CAA_BITS_PER_LONG == 32)
288 static inline
289 unsigned long test_hash_mix(const void *_key, size_t length, unsigned long seed)
290 {
291 unsigned int key = (unsigned int) _key;
292
293 urcu_posix_assert(length == sizeof(unsigned int));
294 return hash_u32(&key, 1, seed);
295 }
296 #else
297 static inline
298 unsigned long test_hash_mix(const void *_key, size_t length, unsigned long seed)
299 {
300 union {
301 uint64_t v64;
302 uint32_t v32[2];
303 } v;
304 union {
305 uint64_t v64;
306 uint32_t v32[2];
307 } key;
308
309 urcu_posix_assert(length == sizeof(unsigned long));
310 v.v64 = (uint64_t) seed;
311 key.v64 = (uint64_t) _key;
312 hashword2(key.v32, 2, &v.v32[0], &v.v32[1]);
313 return v.v64;
314 }
315 #endif
316
317 /*
318 * Hash function with nr_hash_chains != 0 for testing purpose only!
319 * Creates very long hash chains, deteriorating the hash table into a
320 * few linked lists, depending on the nr_hash_chains value. The purpose
321 * of this test is to check how the hash table behaves with hash chains
322 * containing different values, which is a rare case in a normal hash
323 * table.
324 */
325 static inline
326 unsigned long test_hash(const void *_key, size_t length,
327 unsigned long seed)
328 {
329 if (nr_hash_chains == 0) {
330 return test_hash_mix(_key, length, seed);
331 } else {
332 unsigned long v;
333
334 urcu_posix_assert(length == sizeof(unsigned long));
335 v = (unsigned long) _key;
336 return v % nr_hash_chains;
337 }
338 }
339
340 unsigned long test_compare(const void *key1, size_t key1_len,
341 const void *key2, size_t key2_len);
342
343 static inline
344 int test_match(struct cds_lfht_node *node, const void *key)
345 {
346 struct lfht_test_node *test_node = to_test_node(node);
347
348 return !test_compare(test_node->key, test_node->key_len,
349 key, sizeof(unsigned long));
350 }
351
352 static inline
353 void cds_lfht_test_lookup(struct cds_lfht *ht, void *key, size_t key_len,
354 struct cds_lfht_iter *iter)
355 {
356 urcu_posix_assert(key_len == sizeof(unsigned long));
357
358 cds_lfht_lookup(ht, test_hash(key, key_len, TEST_HASH_SEED),
359 test_match, key, iter);
360 }
361
362 void free_node_cb(struct rcu_head *head);
363
364 /* rw test */
365 void test_hash_rw_sigusr1_handler(int signo);
366 void test_hash_rw_sigusr2_handler(int signo);
367 void *test_hash_rw_thr_reader(void *_count);
368 void *test_hash_rw_thr_writer(void *_count);
369 int test_hash_rw_populate_hash(void);
370
371 /* unique test */
372 void test_hash_unique_sigusr1_handler(int signo);
373 void test_hash_unique_sigusr2_handler(int signo);
374 void *test_hash_unique_thr_reader(void *_count);
375 void *test_hash_unique_thr_writer(void *_count);
376 int test_hash_unique_populate_hash(void);
377
378 #endif /* _TEST_URCU_HASH_H */
This page took 0.037975 seconds and 5 git commands to generate.