Home | History | Annotate | Line # | Download | only in benchmark
      1  1.1  christos // SPDX-FileCopyrightText: 2009 Mathieu Desnoyers <mathieu.desnoyers (at) efficios.com>
      2  1.1  christos //
      3  1.1  christos // SPDX-License-Identifier: GPL-2.0-or-later
      4  1.1  christos 
      5  1.1  christos /*
      6  1.1  christos  * Userspace RCU library - test program
      7  1.1  christos  */
      8  1.1  christos 
      9  1.1  christos #include <stdio.h>
     10  1.1  christos #include <pthread.h>
     11  1.1  christos #include <stdlib.h>
     12  1.1  christos #include <string.h>
     13  1.1  christos #include <sys/types.h>
     14  1.1  christos #include <sys/wait.h>
     15  1.1  christos #include <unistd.h>
     16  1.1  christos #include <stdio.h>
     17  1.1  christos #include <errno.h>
     18  1.1  christos 
     19  1.1  christos #include <urcu/arch.h>
     20  1.1  christos #include <urcu/assert.h>
     21  1.1  christos #include <urcu/tls-compat.h>
     22  1.1  christos #include "thread-id.h"
     23  1.1  christos 
     24  1.1  christos /* hardcoded number of CPUs */
     25  1.1  christos #define NR_CPUS 16384
     26  1.1  christos 
     27  1.1  christos #ifndef DYNAMIC_LINK_TEST
     28  1.1  christos #define _LGPL_SOURCE
     29  1.1  christos #endif
     30  1.1  christos #include <urcu.h>
     31  1.1  christos 
     32  1.1  christos struct test_array {
     33  1.1  christos 	int a;
     34  1.1  christos };
     35  1.1  christos 
     36  1.1  christos /*
     37  1.1  christos  * static rwlock initializer is broken on Cygwin. Use runtime
     38  1.1  christos  * initialization.
     39  1.1  christos  */
     40  1.1  christos pthread_rwlock_t lock;
     41  1.1  christos 
     42  1.1  christos static unsigned long wdelay;
     43  1.1  christos 
     44  1.1  christos static volatile struct test_array test_array = { 8 };
     45  1.1  christos 
     46  1.1  christos static unsigned long duration;
     47  1.1  christos 
     48  1.1  christos /* read-side C.S. duration, in loops */
     49  1.1  christos static unsigned long rduration;
     50  1.1  christos 
     51  1.1  christos /* write-side C.S. duration, in loops */
     52  1.1  christos static unsigned long wduration;
     53  1.1  christos 
     54  1.1  christos static inline void loop_sleep(unsigned long loops)
     55  1.1  christos {
     56  1.1  christos 	while (loops-- != 0)
     57  1.1  christos 		caa_cpu_relax();
     58  1.1  christos }
     59  1.1  christos 
     60  1.1  christos static int verbose_mode;
     61  1.1  christos 
     62  1.1  christos #define printf_verbose(fmt, args...)		\
     63  1.1  christos 	do {					\
     64  1.1  christos 		if (verbose_mode)		\
     65  1.1  christos 			printf(fmt, args);	\
     66  1.1  christos 	} while (0)
     67  1.1  christos 
     68  1.1  christos static unsigned int cpu_affinities[NR_CPUS];
     69  1.1  christos static unsigned int next_aff = 0;
     70  1.1  christos static int use_affinity = 0;
     71  1.1  christos 
     72  1.1  christos pthread_mutex_t affinity_mutex = PTHREAD_MUTEX_INITIALIZER;
     73  1.1  christos 
     74  1.1  christos static void set_affinity(void)
     75  1.1  christos {
     76  1.1  christos #ifdef HAVE_SCHED_SETAFFINITY
     77  1.1  christos 	cpu_set_t mask;
     78  1.1  christos 	int cpu, ret;
     79  1.1  christos #endif /* HAVE_SCHED_SETAFFINITY */
     80  1.1  christos 
     81  1.1  christos 	if (!use_affinity)
     82  1.1  christos 		return;
     83  1.1  christos 
     84  1.1  christos #ifdef HAVE_SCHED_SETAFFINITY
     85  1.1  christos 	ret = pthread_mutex_lock(&affinity_mutex);
     86  1.1  christos 	if (ret) {
     87  1.1  christos 		perror("Error in pthread mutex lock");
     88  1.1  christos 		exit(-1);
     89  1.1  christos 	}
     90  1.1  christos 	cpu = cpu_affinities[next_aff++];
     91  1.1  christos 	ret = pthread_mutex_unlock(&affinity_mutex);
     92  1.1  christos 	if (ret) {
     93  1.1  christos 		perror("Error in pthread mutex unlock");
     94  1.1  christos 		exit(-1);
     95  1.1  christos 	}
     96  1.1  christos 
     97  1.1  christos 	CPU_ZERO(&mask);
     98  1.1  christos 	CPU_SET(cpu, &mask);
     99  1.1  christos 	sched_setaffinity(0, sizeof(mask), &mask);
    100  1.1  christos #endif /* HAVE_SCHED_SETAFFINITY */
    101  1.1  christos }
    102  1.1  christos 
    103  1.1  christos static DEFINE_URCU_TLS(unsigned long long, nr_writes);
    104  1.1  christos static DEFINE_URCU_TLS(unsigned long long, nr_reads);
    105  1.1  christos 
    106  1.1  christos static unsigned int nr_readers;
    107  1.1  christos static unsigned int nr_writers;
    108  1.1  christos 
    109  1.1  christos pthread_mutex_t rcu_copy_mutex = PTHREAD_MUTEX_INITIALIZER;
    110  1.1  christos 
    111  1.1  christos static
    112  1.1  christos void *thr_reader(void *_count)
    113  1.1  christos {
    114  1.1  christos 	unsigned long long *count = _count;
    115  1.1  christos 
    116  1.1  christos 	printf_verbose("thread_begin %s, tid %lu\n",
    117  1.1  christos 			"reader", urcu_get_thread_id());
    118  1.1  christos 
    119  1.1  christos 	set_affinity();
    120  1.1  christos 
    121  1.1  christos 	wait_until_go();
    122  1.1  christos 
    123  1.1  christos 	for (;;) {
    124  1.1  christos 		int a, ret;
    125  1.1  christos 
    126  1.1  christos 		ret = pthread_rwlock_rdlock(&lock);
    127  1.1  christos 		if (ret) {
    128  1.1  christos 			fprintf(stderr, "reader pthread_rwlock_rdlock: %s\n", strerror(ret));
    129  1.1  christos 			abort();
    130  1.1  christos 		}
    131  1.1  christos 
    132  1.1  christos 		a = test_array.a;
    133  1.1  christos 		urcu_posix_assert(a == 8);
    134  1.1  christos 		if (caa_unlikely(rduration))
    135  1.1  christos 			loop_sleep(rduration);
    136  1.1  christos 
    137  1.1  christos 		ret = pthread_rwlock_unlock(&lock);
    138  1.1  christos 		if (ret) {
    139  1.1  christos 			fprintf(stderr, "reader pthread_rwlock_unlock: %s\n", strerror(ret));
    140  1.1  christos 			abort();
    141  1.1  christos 		}
    142  1.1  christos 
    143  1.1  christos 		URCU_TLS(nr_reads)++;
    144  1.1  christos 		if (caa_unlikely(!test_duration_read()))
    145  1.1  christos 			break;
    146  1.1  christos 	}
    147  1.1  christos 
    148  1.1  christos 	*count = URCU_TLS(nr_reads);
    149  1.1  christos 
    150  1.1  christos 	printf_verbose("thread_end %s, tid %lu, count %llu\n",
    151  1.1  christos 			"reader", urcu_get_thread_id(), *count);
    152  1.1  christos 	return ((void*)1);
    153  1.1  christos 
    154  1.1  christos }
    155  1.1  christos 
    156  1.1  christos static
    157  1.1  christos void *thr_writer(void *_count)
    158  1.1  christos {
    159  1.1  christos 	unsigned long long *count = _count;
    160  1.1  christos 
    161  1.1  christos 	printf_verbose("thread_begin %s, tid %lu\n",
    162  1.1  christos 			"writer", urcu_get_thread_id());
    163  1.1  christos 
    164  1.1  christos 	set_affinity();
    165  1.1  christos 
    166  1.1  christos 	wait_until_go();
    167  1.1  christos 
    168  1.1  christos 	for (;;) {
    169  1.1  christos 		int ret;
    170  1.1  christos 
    171  1.1  christos 		ret = pthread_rwlock_wrlock(&lock);
    172  1.1  christos 		if (ret) {
    173  1.1  christos 			fprintf(stderr, "writer pthread_rwlock_wrlock: %s\n", strerror(ret));
    174  1.1  christos 			abort();
    175  1.1  christos 		}
    176  1.1  christos 
    177  1.1  christos 		test_array.a = 0;
    178  1.1  christos 		test_array.a = 8;
    179  1.1  christos 		if (caa_unlikely(wduration))
    180  1.1  christos 			loop_sleep(wduration);
    181  1.1  christos 
    182  1.1  christos 		ret = pthread_rwlock_unlock(&lock);
    183  1.1  christos 		if (ret) {
    184  1.1  christos 			fprintf(stderr, "writer pthread_rwlock_unlock: %s\n", strerror(ret));
    185  1.1  christos 			abort();
    186  1.1  christos 		}
    187  1.1  christos 
    188  1.1  christos 		URCU_TLS(nr_writes)++;
    189  1.1  christos 		if (caa_unlikely(!test_duration_write()))
    190  1.1  christos 			break;
    191  1.1  christos 		if (caa_unlikely(wdelay))
    192  1.1  christos 			loop_sleep(wdelay);
    193  1.1  christos 	}
    194  1.1  christos 	*count = URCU_TLS(nr_writes);
    195  1.1  christos 
    196  1.1  christos 	printf_verbose("thread_end %s, tid %lu, count %llu\n",
    197  1.1  christos 			"writer", urcu_get_thread_id(), *count);
    198  1.1  christos 	return ((void*)2);
    199  1.1  christos }
    200  1.1  christos 
    201  1.1  christos static
    202  1.1  christos void show_usage(char **argv)
    203  1.1  christos {
    204  1.1  christos 	printf("Usage : %s nr_readers nr_writers duration (s) <OPTIONS>\n",
    205  1.1  christos 		argv[0]);
    206  1.1  christos 	printf("OPTIONS:\n");
    207  1.1  christos 	printf("	[-d delay] (writer period (us))\n");
    208  1.1  christos 	printf("	[-c duration] (reader C.S. duration (in loops))\n");
    209  1.1  christos 	printf("	[-e duration] (writer C.S. duration (in loops))\n");
    210  1.1  christos 	printf("	[-v] (verbose output)\n");
    211  1.1  christos 	printf("	[-a cpu#] [-a cpu#]... (affinity)\n");
    212  1.1  christos 	printf("\n");
    213  1.1  christos }
    214  1.1  christos 
    215  1.1  christos int main(int argc, char **argv)
    216  1.1  christos {
    217  1.1  christos 	int err;
    218  1.1  christos 	pthread_t *tid_reader, *tid_writer;
    219  1.1  christos 	void *tret;
    220  1.1  christos 	unsigned long long *count_reader, *count_writer;
    221  1.1  christos 	unsigned long long tot_reads = 0, tot_writes = 0;
    222  1.1  christos 	int i, a;
    223  1.1  christos 	unsigned int i_thr;
    224  1.1  christos 
    225  1.1  christos 	if (argc < 4) {
    226  1.1  christos 		show_usage(argv);
    227  1.1  christos 		return -1;
    228  1.1  christos 	}
    229  1.1  christos 	cmm_smp_mb();
    230  1.1  christos 
    231  1.1  christos 	err = sscanf(argv[1], "%u", &nr_readers);
    232  1.1  christos 	if (err != 1) {
    233  1.1  christos 		show_usage(argv);
    234  1.1  christos 		return -1;
    235  1.1  christos 	}
    236  1.1  christos 
    237  1.1  christos 	err = sscanf(argv[2], "%u", &nr_writers);
    238  1.1  christos 	if (err != 1) {
    239  1.1  christos 		show_usage(argv);
    240  1.1  christos 		return -1;
    241  1.1  christos 	}
    242  1.1  christos 
    243  1.1  christos 	err = sscanf(argv[3], "%lu", &duration);
    244  1.1  christos 	if (err != 1) {
    245  1.1  christos 		show_usage(argv);
    246  1.1  christos 		return -1;
    247  1.1  christos 	}
    248  1.1  christos 
    249  1.1  christos 	for (i = 4; i < argc; i++) {
    250  1.1  christos 		if (argv[i][0] != '-')
    251  1.1  christos 			continue;
    252  1.1  christos 		switch (argv[i][1]) {
    253  1.1  christos 		case 'a':
    254  1.1  christos 			if (argc < i + 2) {
    255  1.1  christos 				show_usage(argv);
    256  1.1  christos 				return -1;
    257  1.1  christos 			}
    258  1.1  christos 			a = atoi(argv[++i]);
    259  1.1  christos 			cpu_affinities[next_aff++] = a;
    260  1.1  christos 			use_affinity = 1;
    261  1.1  christos 			printf_verbose("Adding CPU %d affinity\n", a);
    262  1.1  christos 			break;
    263  1.1  christos 		case 'c':
    264  1.1  christos 			if (argc < i + 2) {
    265  1.1  christos 				show_usage(argv);
    266  1.1  christos 				return -1;
    267  1.1  christos 			}
    268  1.1  christos 			rduration = atol(argv[++i]);
    269  1.1  christos 			break;
    270  1.1  christos 		case 'd':
    271  1.1  christos 			if (argc < i + 2) {
    272  1.1  christos 				show_usage(argv);
    273  1.1  christos 				return -1;
    274  1.1  christos 			}
    275  1.1  christos 			wdelay = atol(argv[++i]);
    276  1.1  christos 			break;
    277  1.1  christos 		case 'e':
    278  1.1  christos 			if (argc < i + 2) {
    279  1.1  christos 				show_usage(argv);
    280  1.1  christos 				return -1;
    281  1.1  christos 			}
    282  1.1  christos 			wduration = atol(argv[++i]);
    283  1.1  christos 			break;
    284  1.1  christos 		case 'v':
    285  1.1  christos 			verbose_mode = 1;
    286  1.1  christos 			break;
    287  1.1  christos 		}
    288  1.1  christos 	}
    289  1.1  christos 
    290  1.1  christos 	printf_verbose("running test for %lu seconds, %u readers, %u writers.\n",
    291  1.1  christos 		duration, nr_readers, nr_writers);
    292  1.1  christos 	printf_verbose("Writer delay : %lu loops.\n", wdelay);
    293  1.1  christos 	printf_verbose("Writer duration : %lu loops.\n", wduration);
    294  1.1  christos 	printf_verbose("Reader duration : %lu loops.\n", rduration);
    295  1.1  christos 	printf_verbose("thread %-6s, tid %lu\n",
    296  1.1  christos 			"main", urcu_get_thread_id());
    297  1.1  christos 
    298  1.1  christos 	err = pthread_rwlock_init(&lock, NULL);
    299  1.1  christos 	if (err != 0) {
    300  1.1  christos 		fprintf(stderr, "pthread_rwlock_init: (%d) %s\n", err, strerror(err));
    301  1.1  christos 		exit(1);
    302  1.1  christos 	}
    303  1.1  christos 
    304  1.1  christos 	tid_reader = calloc(nr_readers, sizeof(*tid_reader));
    305  1.1  christos 	tid_writer = calloc(nr_writers, sizeof(*tid_writer));
    306  1.1  christos 	count_reader = calloc(nr_readers, sizeof(*count_reader));
    307  1.1  christos 	count_writer = calloc(nr_writers, sizeof(*count_writer));
    308  1.1  christos 
    309  1.1  christos 	next_aff = 0;
    310  1.1  christos 
    311  1.1  christos 	for (i_thr = 0; i_thr < nr_readers; i_thr++) {
    312  1.1  christos 		err = pthread_create(&tid_reader[i_thr], NULL, thr_reader,
    313  1.1  christos 				     &count_reader[i_thr]);
    314  1.1  christos 		if (err != 0)
    315  1.1  christos 			exit(1);
    316  1.1  christos 	}
    317  1.1  christos 	for (i_thr = 0; i_thr < nr_writers; i_thr++) {
    318  1.1  christos 		err = pthread_create(&tid_writer[i_thr], NULL, thr_writer,
    319  1.1  christos 				     &count_writer[i_thr]);
    320  1.1  christos 		if (err != 0)
    321  1.1  christos 			exit(1);
    322  1.1  christos 	}
    323  1.1  christos 
    324  1.1  christos 	test_for(duration);
    325  1.1  christos 
    326  1.1  christos 	for (i_thr = 0; i_thr < nr_readers; i_thr++) {
    327  1.1  christos 		err = pthread_join(tid_reader[i_thr], &tret);
    328  1.1  christos 		if (err != 0)
    329  1.1  christos 			exit(1);
    330  1.1  christos 		tot_reads += count_reader[i_thr];
    331  1.1  christos 	}
    332  1.1  christos 	for (i_thr = 0; i_thr < nr_writers; i_thr++) {
    333  1.1  christos 		err = pthread_join(tid_writer[i_thr], &tret);
    334  1.1  christos 		if (err != 0)
    335  1.1  christos 			exit(1);
    336  1.1  christos 		tot_writes += count_writer[i_thr];
    337  1.1  christos 	}
    338  1.1  christos 
    339  1.1  christos 	printf_verbose("total number of reads : %llu, writes %llu\n", tot_reads,
    340  1.1  christos 	       tot_writes);
    341  1.1  christos 	printf("SUMMARY %-25s testdur %4lu nr_readers %3u rdur %6lu wdur %6lu "
    342  1.1  christos 		"nr_writers %3u "
    343  1.1  christos 		"wdelay %6lu nr_reads %12llu nr_writes %12llu nr_ops %12llu\n",
    344  1.1  christos 		argv[0], duration, nr_readers, rduration, wduration,
    345  1.1  christos 		nr_writers, wdelay, tot_reads, tot_writes,
    346  1.1  christos 		tot_reads + tot_writes);
    347  1.1  christos 
    348  1.1  christos 	err = pthread_rwlock_destroy(&lock);
    349  1.1  christos 	if (err != 0) {
    350  1.1  christos 		fprintf(stderr, "pthread_rwlock_destroy: (%d) %s\n", err, strerror(err));
    351  1.1  christos 		exit(1);
    352  1.1  christos 	}
    353  1.1  christos 	free(tid_reader);
    354  1.1  christos 	free(tid_writer);
    355  1.1  christos 	free(count_reader);
    356  1.1  christos 	free(count_writer);
    357  1.1  christos 	return 0;
    358  1.1  christos }
    359