1 // SPDX-FileCopyrightText: 2009 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 <stdio.h> 10 #include <pthread.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <sys/types.h> 14 #include <sys/wait.h> 15 #include <unistd.h> 16 #include <stdio.h> 17 #include <errno.h> 18 19 #include <urcu/arch.h> 20 #include <urcu/assert.h> 21 22 #include "thread-id.h" 23 24 #define _LGPL_SOURCE 25 #include <urcu.h> 26 27 pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER; 28 29 static 30 void rcu_copy_mutex_lock(void) 31 { 32 int ret; 33 ret = pthread_mutex_lock(&rcu_copy_mutex); 34 if (ret) { 35 perror("Error in pthread mutex lock"); 36 exit(-1); 37 } 38 } 39 40 static 41 void rcu_copy_mutex_unlock(void) 42 { 43 int ret; 44 45 ret = pthread_mutex_unlock(&rcu_copy_mutex); 46 if (ret) { 47 perror("Error in pthread mutex unlock"); 48 exit(-1); 49 } 50 } 51 52 struct test_array { 53 int a; 54 }; 55 56 static struct test_array *test_rcu_pointer; 57 58 #define OUTER_READ_LOOP 2000U 59 #define INNER_READ_LOOP 100000U 60 #define READ_LOOP ((unsigned long long)OUTER_READ_LOOP * INNER_READ_LOOP) 61 62 #define OUTER_WRITE_LOOP 10U 63 #define INNER_WRITE_LOOP 200U 64 #define WRITE_LOOP ((unsigned long long)OUTER_WRITE_LOOP * INNER_WRITE_LOOP) 65 66 static int num_read; 67 static int num_write; 68 69 #define NR_READ num_read 70 #define NR_WRITE num_write 71 72 static caa_cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *reader_time; 73 static caa_cycles_t __attribute__((aligned(CAA_CACHE_LINE_SIZE))) *writer_time; 74 75 static 76 void *thr_reader(void *arg) 77 { 78 unsigned int i, j; 79 struct test_array *local_ptr; 80 caa_cycles_t time1, time2; 81 82 printf("thread_begin %s, tid %lu\n", 83 "reader", urcu_get_thread_id()); 84 sleep(2); 85 86 rcu_register_thread(); 87 88 time1 = caa_get_cycles(); 89 for (i = 0; i < OUTER_READ_LOOP; i++) { 90 for (j = 0; j < INNER_READ_LOOP; j++) { 91 rcu_read_lock(); 92 local_ptr = rcu_dereference(test_rcu_pointer); 93 if (local_ptr) { 94 urcu_posix_assert(local_ptr->a == 8); 95 } 96 rcu_read_unlock(); 97 } 98 } 99 time2 = caa_get_cycles(); 100 101 rcu_unregister_thread(); 102 103 reader_time[(unsigned long)arg] = time2 - time1; 104 105 sleep(2); 106 printf("thread_end %s, tid %lu\n", 107 "reader", urcu_get_thread_id()); 108 return ((void*)1); 109 110 } 111 112 static 113 void *thr_writer(void *arg) 114 { 115 unsigned int i, j; 116 struct test_array *new, *old; 117 caa_cycles_t time1, time2; 118 119 printf("thread_begin %s, tid %lu\n", 120 "writer", urcu_get_thread_id()); 121 sleep(2); 122 123 for (i = 0; i < OUTER_WRITE_LOOP; i++) { 124 for (j = 0; j < INNER_WRITE_LOOP; j++) { 125 time1 = caa_get_cycles(); 126 new = malloc(sizeof(struct test_array)); 127 rcu_copy_mutex_lock(); 128 old = test_rcu_pointer; 129 if (old) { 130 urcu_posix_assert(old->a == 8); 131 } 132 new->a = 8; 133 old = rcu_xchg_pointer(&test_rcu_pointer, new); 134 rcu_copy_mutex_unlock(); 135 synchronize_rcu(); 136 /* can be done after unlock */ 137 if (old) { 138 old->a = 0; 139 } 140 free(old); 141 time2 = caa_get_cycles(); 142 writer_time[(unsigned long)arg] += time2 - time1; 143 usleep(1); 144 } 145 } 146 147 printf("thread_end %s, tid %lu\n", 148 "writer", urcu_get_thread_id()); 149 return ((void*)2); 150 } 151 152 int main(int argc, char **argv) 153 { 154 int err; 155 pthread_t *tid_reader, *tid_writer; 156 void *tret; 157 int i; 158 caa_cycles_t tot_rtime = 0; 159 caa_cycles_t tot_wtime = 0; 160 161 if (argc < 2) { 162 printf("Usage : %s nr_readers nr_writers\n", argv[0]); 163 exit(-1); 164 } 165 num_read = atoi(argv[1]); 166 num_write = atoi(argv[2]); 167 168 reader_time = calloc(num_read, sizeof(*reader_time)); 169 writer_time = calloc(num_write, sizeof(*writer_time)); 170 tid_reader = calloc(num_read, sizeof(*tid_reader)); 171 tid_writer = calloc(num_write, sizeof(*tid_writer)); 172 173 printf("thread %-6s, tid %lu\n", 174 "main", urcu_get_thread_id()); 175 176 for (i = 0; i < NR_READ; i++) { 177 err = pthread_create(&tid_reader[i], NULL, thr_reader, 178 (void *)(long)i); 179 if (err != 0) 180 exit(1); 181 } 182 for (i = 0; i < NR_WRITE; i++) { 183 err = pthread_create(&tid_writer[i], NULL, thr_writer, 184 (void *)(long)i); 185 if (err != 0) 186 exit(1); 187 } 188 189 sleep(10); 190 191 for (i = 0; i < NR_READ; i++) { 192 err = pthread_join(tid_reader[i], &tret); 193 if (err != 0) 194 exit(1); 195 tot_rtime += reader_time[i]; 196 } 197 for (i = 0; i < NR_WRITE; i++) { 198 err = pthread_join(tid_writer[i], &tret); 199 if (err != 0) 200 exit(1); 201 tot_wtime += writer_time[i]; 202 } 203 free(test_rcu_pointer); 204 printf("Time per read : %g cycles\n", 205 (double)tot_rtime / ((double)NR_READ * (double)READ_LOOP)); 206 printf("Time per write : %g cycles\n", 207 (double)tot_wtime / ((double)NR_WRITE * (double)WRITE_LOOP)); 208 209 free(reader_time); 210 free(writer_time); 211 free(tid_reader); 212 free(tid_writer); 213 214 return 0; 215 } 216