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