Home | History | Annotate | Line # | Download | only in benchmark
      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