Home | History | Annotate | Line # | Download | only in benchmark
      1 // SPDX-FileCopyrightText: 2009-2012 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com>
      2 //
      3 // SPDX-License-Identifier: GPL-2.0-or-later
      4 
      5 /*
      6  * Userspace RCU library - test program
      7  */
      8 
      9 #include "test_urcu_hash.h"
     10 
     11 enum urcu_hash_addremove {
     12 	AR_RANDOM = 0,
     13 	AR_ADD = 1,
     14 	AR_REMOVE = -1,
     15 };	/* 1: add, -1 remove, 0: random */
     16 
     17 static enum urcu_hash_addremove addremove; /* 1: add, -1 remove, 0: random */
     18 
     19 void test_hash_unique_sigusr1_handler(int signo __attribute__((unused)))
     20 {
     21 	switch (addremove) {
     22 	case AR_ADD:
     23 		printf("Add/Remove: random.\n");
     24 		addremove = AR_RANDOM;
     25 		break;
     26 	case AR_RANDOM:
     27 		printf("Add/Remove: remove only.\n");
     28 		addremove = AR_REMOVE;
     29 		break;
     30 	case AR_REMOVE:
     31 		printf("Add/Remove: add only.\n");
     32 		addremove = AR_ADD;
     33 		break;
     34 	}
     35 }
     36 
     37 void test_hash_unique_sigusr2_handler(int signo __attribute__((unused)))
     38 {
     39 	char msg[1] = { 0x42 };
     40 	ssize_t ret;
     41 
     42 	do {
     43 		ret = write(count_pipe[1], msg, 1);	/* wakeup thread */
     44 	} while (ret == -1L && errno == EINTR);
     45 }
     46 
     47 void *test_hash_unique_thr_reader(void *_count)
     48 {
     49 	unsigned long long *count = _count;
     50 
     51 	printf_verbose("thread_begin %s, tid %lu\n",
     52 			"reader", urcu_get_thread_id());
     53 
     54 	URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
     55 
     56 	set_affinity();
     57 
     58 	rcu_register_thread();
     59 
     60 	wait_until_go();
     61 
     62 	for (;;) {
     63 		struct lfht_test_node *node;
     64 		struct cds_lfht_iter iter;
     65 		/*
     66 		 * iterate on whole table, ensuring that no duplicate is
     67 		 * found.
     68 		 */
     69 		rcu_read_lock();
     70 		cds_lfht_for_each_entry(test_ht, &iter, node, node) {
     71 			struct cds_lfht_iter dup_iter;
     72 
     73 			dup_iter = iter;
     74 			cds_lfht_next_duplicate(test_ht, test_match,
     75 				node->key, &dup_iter);
     76 			if (dup_iter.node != NULL) {
     77 				printf("[ERROR] Duplicate key %p found\n", node->key);
     78 			}
     79 		}
     80 		rcu_read_unlock();
     81 
     82 		rcu_debug_yield_read();
     83 		if (caa_unlikely(rduration))
     84 			loop_sleep(rduration);
     85 		URCU_TLS(nr_reads)++;
     86 		if (caa_unlikely(!test_duration_read()))
     87 			break;
     88 		if (caa_unlikely((URCU_TLS(nr_reads) & ((1 << 10) - 1)) == 0))
     89 			rcu_quiescent_state();
     90 	}
     91 
     92 	rcu_unregister_thread();
     93 
     94 	*count = URCU_TLS(nr_reads);
     95 	printf_verbose("thread_end %s, tid %lu\n",
     96 			"reader", urcu_get_thread_id());
     97 	printf_verbose("read tid : %lu, lookupfail %lu, lookupok %lu\n",
     98 			urcu_get_thread_id(), URCU_TLS(lookup_fail),
     99 			URCU_TLS(lookup_ok));
    100 	return ((void*)1);
    101 
    102 }
    103 
    104 void *test_hash_unique_thr_writer(void *_count)
    105 {
    106 	struct lfht_test_node *node;
    107 	struct cds_lfht_node *ret_node;
    108 	struct cds_lfht_iter iter;
    109 	struct wr_count *count = _count;
    110 	int ret;
    111 	int loc_add_unique;
    112 
    113 	printf_verbose("thread_begin %s, tid %lu\n",
    114 			"writer", urcu_get_thread_id());
    115 
    116 	URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
    117 
    118 	set_affinity();
    119 
    120 	rcu_register_thread();
    121 
    122 	wait_until_go();
    123 
    124 	for (;;) {
    125 		/*
    126 		 * add unique/add replace with new node key from range.
    127 		 */
    128 		if (1 || (addremove == AR_ADD || add_only)
    129 				|| (addremove == AR_RANDOM && rand_r(&URCU_TLS(rand_lookup)) & 1)) {
    130 			node = malloc(sizeof(struct lfht_test_node));
    131 			lfht_test_node_init(node,
    132 				(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
    133 				sizeof(void *));
    134 			rcu_read_lock();
    135 			loc_add_unique = rand_r(&URCU_TLS(rand_lookup)) & 1;
    136 			if (loc_add_unique) {
    137 				ret_node = cds_lfht_add_unique(test_ht,
    138 					test_hash(node->key, node->key_len, TEST_HASH_SEED),
    139 					test_match, node->key, &node->node);
    140 			} else {
    141 				ret_node = cds_lfht_add_replace(test_ht,
    142 						test_hash(node->key, node->key_len, TEST_HASH_SEED),
    143 						test_match, node->key, &node->node);
    144 #if 0 //generate an error on purpose
    145 				cds_lfht_add(test_ht,
    146 						test_hash(node->key, node->key_len, TEST_HASH_SEED),
    147 						&node->node);
    148 				ret_node = NULL;
    149 #endif //0
    150 			}
    151 			rcu_read_unlock();
    152 			if (loc_add_unique) {
    153 				if (ret_node != &node->node) {
    154 					free(node);
    155 					URCU_TLS(nr_addexist)++;
    156 				} else {
    157 					URCU_TLS(nr_add)++;
    158 				}
    159 			} else {
    160 				if (ret_node) {
    161 					call_rcu(&to_test_node(ret_node)->head,
    162 							free_node_cb);
    163 					URCU_TLS(nr_addexist)++;
    164 				} else {
    165 					URCU_TLS(nr_add)++;
    166 				}
    167 			}
    168 		} else {
    169 			/* May delete */
    170 			rcu_read_lock();
    171 			cds_lfht_test_lookup(test_ht,
    172 				(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % write_pool_size) + write_pool_offset),
    173 				sizeof(void *), &iter);
    174 			ret = cds_lfht_del(test_ht, cds_lfht_iter_get_node(&iter));
    175 			rcu_read_unlock();
    176 			if (ret == 0) {
    177 				node = cds_lfht_iter_get_test_node(&iter);
    178 				call_rcu(&node->head, free_node_cb);
    179 				URCU_TLS(nr_del)++;
    180 			} else
    181 				URCU_TLS(nr_delnoent)++;
    182 		}
    183 #if 0
    184 		//if (URCU_TLS(nr_writes) % 100000 == 0) {
    185 		if (URCU_TLS(nr_writes) % 1000 == 0) {
    186 			rcu_read_lock();
    187 			if (rand_r(&URCU_TLS(rand_lookup)) & 1) {
    188 				ht_resize(test_ht, 1);
    189 			} else {
    190 				ht_resize(test_ht, -1);
    191 			}
    192 			rcu_read_unlock();
    193 		}
    194 #endif //0
    195 		URCU_TLS(nr_writes)++;
    196 		if (caa_unlikely(!test_duration_write()))
    197 			break;
    198 		if (caa_unlikely(wdelay))
    199 			loop_sleep(wdelay);
    200 		if (caa_unlikely((URCU_TLS(nr_writes) & ((1 << 10) - 1)) == 0))
    201 			rcu_quiescent_state();
    202 	}
    203 
    204 	rcu_unregister_thread();
    205 
    206 	printf_verbose("thread_end %s, tid %lu\n",
    207 			"writer", urcu_get_thread_id());
    208 	printf_verbose("info tid %lu: nr_add %lu, nr_addexist %lu, nr_del %lu, "
    209 			"nr_delnoent %lu\n", urcu_get_thread_id(),
    210 			URCU_TLS(nr_add),
    211 			URCU_TLS(nr_addexist),
    212 			URCU_TLS(nr_del),
    213 			URCU_TLS(nr_delnoent));
    214 	count->update_ops = URCU_TLS(nr_writes);
    215 	count->add = URCU_TLS(nr_add);
    216 	count->add_exist = URCU_TLS(nr_addexist);
    217 	count->remove = URCU_TLS(nr_del);
    218 	return ((void*)2);
    219 }
    220 
    221 int test_hash_unique_populate_hash(void)
    222 {
    223 	struct lfht_test_node *node;
    224 	struct cds_lfht_node *ret_node;
    225 
    226 	printf("Starting uniqueness test.\n");
    227 
    228 	URCU_TLS(rand_lookup) = urcu_get_thread_id() ^ time(NULL);
    229 
    230 	if (!init_populate)
    231 		return 0;
    232 
    233 	if (init_populate * 10 > init_pool_size) {
    234 		printf("WARNING: required to populate %lu nodes (-k), but random "
    235 "pool is quite small (%lu values) and we are in add_unique (-u) or add_replace (-s) mode. Try with a "
    236 "larger random pool (-p option). This may take a while...\n", init_populate, init_pool_size);
    237 	}
    238 
    239 	while (URCU_TLS(nr_add) < init_populate) {
    240 		node = malloc(sizeof(struct lfht_test_node));
    241 		lfht_test_node_init(node,
    242 			(void *)(((unsigned long) rand_r(&URCU_TLS(rand_lookup)) % init_pool_size) + init_pool_offset),
    243 			sizeof(void *));
    244 		rcu_read_lock();
    245 		ret_node = cds_lfht_add_replace(test_ht,
    246 				test_hash(node->key, node->key_len, TEST_HASH_SEED),
    247 				test_match, node->key, &node->node);
    248 		rcu_read_unlock();
    249 		if (ret_node) {
    250 			call_rcu(&to_test_node(ret_node)->head, free_node_cb);
    251 			URCU_TLS(nr_addexist)++;
    252 		} else {
    253 			URCU_TLS(nr_add)++;
    254 		}
    255 		URCU_TLS(nr_writes)++;
    256 	}
    257 	return 0;
    258 }
    259